Merge "Attempt to fix InvalidationTrackerTest#testWeak flake." into androidx-main
diff --git a/benchmark/integration-tests/macrobenchmark-target/build.gradle b/benchmark/integration-tests/macrobenchmark-target/build.gradle
index 00866e4..d455803 100644
--- a/benchmark/integration-tests/macrobenchmark-target/build.gradle
+++ b/benchmark/integration-tests/macrobenchmark-target/build.gradle
@@ -41,4 +41,8 @@
     implementation(project(":tracing:tracing-ktx"))
     implementation(project(":tracing:tracing-perfetto"))
     implementation(libs.material)
+
+    implementation(project(":work:work-runtime"))
+    implementation(project(":work:work-runtime-ktx"))
+    implementation(project(":room:room-runtime"))
 }
diff --git a/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index da19fa4..abd247c 100644
--- a/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -70,6 +70,16 @@
             </intent-filter>
         </activity>
 
+
+        <activity
+            android:name=".BackgroundWorkActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="androidx.benchmark.integration.macrobenchmark.target.BACKGROUND_WORK_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity
             android:name=".NotExportedActivity"
             android:exported="false"> <!-- intentionally not exported -->
diff --git a/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/BackgroundWorkActivity.kt b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/BackgroundWorkActivity.kt
new file mode 100644
index 0000000..9ccde18
--- /dev/null
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/BackgroundWorkActivity.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.integration.macrobenchmark.target
+
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.tracing.trace
+import kotlin.concurrent.thread
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.OutOfQuotaPolicy
+import androidx.work.WorkInfo
+import androidx.work.WorkManager
+import java.util.concurrent.CountDownLatch
+
+class BackgroundWorkActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+
+        val notice = findViewById<TextView>(R.id.txtNotice)
+        notice.setText(R.string.app_notice)
+
+        startWork(this)
+    }
+
+    private fun startWork(context: Context) {
+        val count = 20
+        var countDownLatch = CountDownLatch(count)
+
+        for (i in 0 until count) {
+            var workRequest = OneTimeWorkRequestBuilder<NoOpWorker>()
+                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+                .build()
+            WorkManager.getInstance(context).beginWith(workRequest)
+                .enqueue()
+            WorkManager.getInstance(context)
+                .getWorkInfoByIdLiveData(workRequest.id)
+            .observe(this) { workInfo ->
+                if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
+                    countDownLatch.countDown()
+                }
+            }
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        if (Build.VERSION.SDK_INT <= 23) {
+            // temporary logging/tracing to debug b/204572406
+            Log.d("Benchmark", "onResume")
+            trace("onResume") {}
+        }
+    }
+
+    init {
+        if (Build.VERSION.SDK_INT <= 23) {
+            // temporary tracing to debug b/204572406
+            thread {
+                while (true) {
+                    trace("tracing") { Thread.sleep(50) }
+                }
+            }
+        }
+    }
+}
diff --git a/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NoOpWorker.kt b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NoOpWorker.kt
new file mode 100644
index 0000000..37e868f
--- /dev/null
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NoOpWorker.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.integration.macrobenchmark.target
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+
+/**
+ * Does not do anything useful except returning a [androidx.work.ListenableWorker.Result.success].
+ */
+class NoOpWorker(context: Context, parameters: WorkerParameters) :
+    CoroutineWorker(context, parameters) {
+    override suspend fun doWork(): Result {
+        return Result.success()
+    }
+}
\ No newline at end of file
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
index 638830c..855fb12 100644
--- a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
+++ b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialPowerBenchmark.kt
@@ -151,7 +151,7 @@
 
     companion object {
         private const val PACKAGE_NAME = "androidx.benchmark.integration.macrobenchmark.target"
-        private const val ACTION = "$PACKAGE_NAME.TRIVIAL_STARTUP_ACTIVITY"
+        private const val ACTION = "$PACKAGE_NAME.BACKGROUND_WORK_ACTIVITY"
         private const val DURATION_MS = 5000
     }
 }
\ No newline at end of file
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index 1b5b012..55e0c22 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -144,6 +144,13 @@
  */
 const val KMP_ENABLE_LINUX = "androidx.kmp.linux.enabled"
 
+/**
+ * If true, include all native targets when building KMP.
+ * Replaces KMP_ENABLE_MAC and KMP_ENABLE_LINUX in collections, and will eventually be
+ * consolidated into the AndroidX plugin.
+ */
+const val KMP_ENABLE_NATIVE = "androidx.kmp.native.enabled"
+
 val ALL_ANDROIDX_PROPERTIES = setOf(
     ALL_WARNINGS_AS_ERRORS,
     ALTERNATIVE_PROJECT_URL,
@@ -171,7 +178,8 @@
     KMP_GITHUB_BUILD,
     KMP_ENABLE_MAC,
     KMP_ENABLE_JS,
-    KMP_ENABLE_LINUX
+    KMP_ENABLE_LINUX,
+    KMP_ENABLE_NATIVE
 )
 
 /**
diff --git a/camera/camera-camera2-pipe-integration/build.gradle b/camera/camera-camera2-pipe-integration/build.gradle
index a92732f..4242098 100644
--- a/camera/camera-camera2-pipe-integration/build.gradle
+++ b/camera/camera-camera2-pipe-integration/build.gradle
@@ -85,6 +85,9 @@
     defaultConfig {
         multiDexEnabled = true
     }
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
     namespace "androidx.camera.camera2.pipe.integration"
 }
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
index 97d2902..32c872d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraControlAdapter.kt
@@ -156,6 +156,10 @@
             evCompControl.updateAsync(exposure).asListenableFuture()
         )
 
+    override fun setZslDisabled(disabled: Boolean) {
+        // Override if Zero-Shutter Lag needs to be disabled or not.
+    }
+
     override fun addZslConfig(resolution: Size, sessionConfigBuilder: SessionConfig.Builder) {
         // Override if Zero-Shutter Lag needs to add config to session config.
     }
diff --git a/camera/camera-camera2-pipe-testing/build.gradle b/camera/camera-camera2-pipe-testing/build.gradle
index 243bfa0..5497bb7 100644
--- a/camera/camera-camera2-pipe-testing/build.gradle
+++ b/camera/camera-camera2-pipe-testing/build.gradle
@@ -43,6 +43,9 @@
 }
 
 android {
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.camera2.pipe.testing"
diff --git a/camera/camera-camera2-pipe/build.gradle b/camera/camera-camera2-pipe/build.gradle
index 210189a..071a5e2 100644
--- a/camera/camera-camera2-pipe/build.gradle
+++ b/camera/camera-camera2-pipe/build.gradle
@@ -54,6 +54,9 @@
 }
 
 android {
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.camera2.pipe"
diff --git a/camera/camera-camera2/build.gradle b/camera/camera-camera2/build.gradle
index c994081..0ab6d1e 100644
--- a/camera/camera-camera2/build.gradle
+++ b/camera/camera-camera2/build.gradle
@@ -77,6 +77,10 @@
         consumerProguardFiles "proguard-rules.pro"
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.camera2"
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
index b30d021..4754fde 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
@@ -389,6 +389,11 @@
         mZslControl.addZslConfig(resolution, sessionConfigBuilder);
     }
 
+    @Override
+    public void setZslDisabled(boolean disabled) {
+        mZslControl.setZslDisabled(disabled);
+    }
+
     /** {@inheritDoc} */
     @Override
     @NonNull
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index b86daff..228f221 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -781,6 +781,8 @@
         synchronized (mLock) {
             mSessionProcessor = sessionProcessor;
         }
+
+        getCameraControlInternal().setZslDisabled(cameraConfig.isZslDisabled());
     }
 
     @NonNull
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControl.java
index 2f2c082..be2a193 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControl.java
@@ -27,11 +27,22 @@
 interface ZslControl {
 
     /**
-     * Add zero-shutter lag config to {@link SessionConfig}.
+     * Adds zero-shutter lag config to {@link SessionConfig}.
+     *
      * @param resolution surface resolution.
      * @param sessionConfigBuilder session config builder.
      */
     void addZslConfig(
             @NonNull Size resolution,
             @NonNull SessionConfig.Builder sessionConfigBuilder);
+
+    /**
+     * Sets zsl disabled or not.
+     *
+     * @param disabled True if zero-shutter lag should be disabled. Otherwise, should not be
+     *                 disabled. However, enabling zero-shutter lag needs other conditions e.g.
+     *                 flash mode OFF, so setting to false doesn't guarantee zero-shutter lag to
+     *                 be always ON.
+     */
+    void setZslDisabled(boolean disabled);
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlImpl.java
index 208261c..a57a454 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlImpl.java
@@ -65,6 +65,7 @@
     @NonNull
     final Queue<TotalCaptureResult> mTotalCaptureResultRingBuffer = new LinkedList<>();
 
+    private boolean mIsZslDisabled = false;
     private boolean mIsYuvReprocessingSupported = false;
     private boolean mIsPrivateReprocessingSupported = false;
 
@@ -84,11 +85,19 @@
                         REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
     }
 
+    @Override
+    public void setZslDisabled(boolean disabled) {
+        mIsZslDisabled = disabled;
+    }
 
     @Override
     public void addZslConfig(
             @NonNull Size resolution,
             @NonNull SessionConfig.Builder sessionConfigBuilder) {
+        if (mIsZslDisabled) {
+            return;
+        }
+
         if (!mIsYuvReprocessingSupported && !mIsPrivateReprocessingSupported) {
             return;
         }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlNoOpImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlNoOpImpl.java
index bcb2e1e..9087b0b 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlNoOpImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ZslControlNoOpImpl.java
@@ -29,4 +29,8 @@
     public void addZslConfig(@NonNull Size resolution,
             @NonNull SessionConfig.Builder sessionConfigBuilder) {
     }
+
+    @Override
+    public void setZslDisabled(boolean disabled) {
+    }
 }
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
index 50d851e..f831878 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
@@ -166,7 +166,7 @@
         // Act.
         pipeline.executeCapture(
             listOf(singleRequest),
-            ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH,
+            FLASH_MODE_OFF,
         )
 
         // Assert.
diff --git a/camera/camera-core/build.gradle b/camera/camera-core/build.gradle
index 589bff7..c11aab9 100644
--- a/camera/camera-core/build.gradle
+++ b/camera/camera-core/build.gradle
@@ -89,6 +89,10 @@
         }
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
 
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt
index be57eaf..878f0c5 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt
@@ -34,7 +34,6 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.Mockito
-import org.mockito.Mockito.spy
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -46,7 +45,7 @@
 
     @Before
     fun setUp() {
-        imageReader = spy(ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2))
+        imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2)
         imageReaderProxy = ModifiableImageReaderProxy(imageReader)
     }
 
@@ -156,10 +155,14 @@
 
     @Test
     fun setOnImageAvailableListener_innerReaderIsInvoked() {
+        val imageReader = Mockito.mock(
+            ImageReader::class.java
+        )
+        val imageReaderProxy = ModifiableImageReaderProxy(imageReader)
+
         val listener = Mockito.mock(
             ImageReaderProxy.OnImageAvailableListener::class.java
         )
-
         imageReaderProxy.setOnImageAvailableListener(
             listener,
             CameraXExecutors.directExecutor()
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
index 90c9cac..051552b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraConfig.java
@@ -48,6 +48,9 @@
     Option<SessionProcessor> OPTION_SESSION_PROCESSOR =
             Option.create("camerax.core.camera.SessionProcessor", SessionProcessor.class);
 
+    Option<Boolean> OPTION_ZSL_DISABLED =
+            Option.create("camerax.core.camera.isZslDisabled", Boolean.class);
+
     /**
      * No rule is required when the camera is opened by the camera config.
      */
@@ -76,6 +79,14 @@
     }
 
     /**
+     * Retrieves the status for zsl disabled or not.
+     */
+    @NonNull
+    default Boolean isZslDisabled() {
+        return retrieveOption(OPTION_ZSL_DISABLED, Boolean.FALSE);
+    }
+
+    /**
      * Retrieves the compatibility {@link Identifier}.
      *
      * <p>If camera configs have the same compatibility identifier, they will allow to bind a new
@@ -148,5 +159,14 @@
          */
         @NonNull
         B setSessionProcessor(@NonNull SessionProcessor sessionProcessor);
+
+        /**
+         * Sets zsl disabled or not. If disabled is true, zero-shutter lag should be disabled.
+         * Otherwise, zero-shutter lag should not be disabled. However, enabling zero-shutter lag
+         * needs other conditions e.g. flash mode OFF, so setting to false doesn't guarantee
+         * zero-shutter lag to be always ON.
+         */
+        @NonNull
+        B setZslDisabled(boolean disabled);
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraControlInternal.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraControlInternal.java
index d0563e5..8ef5544 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraControlInternal.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraControlInternal.java
@@ -59,7 +59,7 @@
     void setFlashMode(@FlashMode int flashMode);
 
     /**
-     * Add zero-shutter lag config to {@link SessionConfig}.
+     * Adds zero-shutter lag config to {@link SessionConfig}.
      * @param resolution surface resolution.
      * @param sessionConfigBuilder session config builder.
      */
@@ -68,6 +68,16 @@
             @NonNull SessionConfig.Builder sessionConfigBuilder);
 
     /**
+     * Sets zsl disabled or not.
+     *
+     * @param disabled True if zero-shutter lag should be disabled. Otherwise, should not be
+     *                 disabled. However, enabling zero-shutter lag needs other conditions e.g.
+     *                 flash mode OFF, so setting to false doesn't guarantee zero-shutter lag to
+     *                 be always ON.
+     */
+    void setZslDisabled(boolean disabled);
+
+    /**
      * Performs still capture requests with the desired capture mode.
      *
      * @param captureConfigs capture configuration used for creating CaptureRequest
@@ -130,6 +140,10 @@
         }
 
         @Override
+        public void setZslDisabled(boolean disabled) {
+        }
+
+        @Override
         public void addZslConfig(@NonNull Size resolution,
                 @NonNull SessionConfig.Builder sessionConfigBuilder) {
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
index 70bdbc4..db0e00f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
@@ -16,6 +16,8 @@
 
 package androidx.camera.core.impl;
 
+import android.util.Range;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -75,6 +77,13 @@
     Option<CameraSelector> OPTION_CAMERA_SELECTOR =
             Config.Option.create("camerax.core.useCase.cameraSelector", CameraSelector.class);
 
+    /**
+     * Option: camerax.core.useCase.targetFramerate
+     */
+    Option<Range<Integer>> OPTION_TARGET_FRAME_RATE =
+            Config.Option.create("camerax.core.useCase.targetFrameRate", CameraSelector.class);
+
+
     // *********************************************************************************************
 
     /**
@@ -250,6 +259,28 @@
     }
 
     /**
+     * Retrieves target frame rate
+     * @param valueIfMissing
+     * @return the stored value or <code>valueIfMissing</code> if the value does not exist in
+     * this configuration
+     */
+    @Nullable
+    default Range<Integer> getTargetFramerate(@Nullable Range<Integer> valueIfMissing) {
+        return retrieveOption(OPTION_TARGET_FRAME_RATE, valueIfMissing);
+    }
+
+    /**
+     * Retrieves the target frame rate
+     *
+     * @return The stored value, if it exists in this configuration.
+     * @throws IllegalArgumentException if the option does not exist in this configuration.
+     */
+    @NonNull
+    default Range<Integer> getTargetFramerate() {
+        return retrieveOption(OPTION_TARGET_FRAME_RATE);
+    }
+
+    /**
      * Builder for a {@link UseCase}.
      *
      * @param <T> The type of the object which will be built by {@link #build()}.
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt
new file mode 100644
index 0000000..0f6df49
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.core.impl
+
+import android.os.Build
+import android.util.Range
+import androidx.camera.testing.fakes.FakeUseCaseConfig
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(
+    RobolectricTestRunner::class
+)
+@DoNotInstrument
+class UseCaseConfigTest {
+    @Test
+    fun canGetTargetFrameRate() {
+        val useCaseBuilder = FakeUseCaseConfig.Builder()
+        val range = Range(10, 20)
+        useCaseBuilder.mutableConfig.insertOption(UseCaseConfig.OPTION_TARGET_FRAME_RATE, range)
+        Truth.assertThat(useCaseBuilder.useCaseConfig.targetFramerate).isEqualTo(range)
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-extensions-stub/build.gradle b/camera/camera-extensions-stub/build.gradle
index 04ab4be..ac016eb 100644
--- a/camera/camera-extensions-stub/build.gradle
+++ b/camera/camera-extensions-stub/build.gradle
@@ -36,5 +36,9 @@
 
  android {
      namespace "androidx.camera.extensions.impl"
+
+     lintOptions {
+         enable 'CameraXQuirksClassDetector'
+     }
  }
 
diff --git a/camera/camera-extensions/build.gradle b/camera/camera-extensions/build.gradle
index ee2869a..6422e1e 100644
--- a/camera/camera-extensions/build.gradle
+++ b/camera/camera-extensions/build.gradle
@@ -69,6 +69,10 @@
         consumerProguardFiles "proguard-rules.pro"
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.extensions"
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
index 5aab6b2..c821b53 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsConfig.java
@@ -99,5 +99,12 @@
             mConfig.insertOption(OPTION_SESSION_PROCESSOR, sessionProcessor);
             return this;
         }
+
+        @NonNull
+        @Override
+        public Builder setZslDisabled(boolean disabled) {
+            mConfig.insertOption(OPTION_ZSL_DISABLED, disabled);
+            return this;
+        }
     }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
index b7927fb..f620986 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
@@ -210,6 +210,7 @@
                         .setExtensionMode(mode)
                         .setUseCaseConfigFactory(factory)
                         .setCompatibilityId(id)
+                        .setZslDisabled(true)
                         .setUseCaseCombinationRequiredRule(
                                 CameraConfig.REQUIRED_RULE_COEXISTING_PREVIEW_AND_IMAGE_CAPTURE);
 
diff --git a/camera/camera-lifecycle/build.gradle b/camera/camera-lifecycle/build.gradle
index 1a926c7..68c12c7 100644
--- a/camera/camera-lifecycle/build.gradle
+++ b/camera/camera-lifecycle/build.gradle
@@ -52,6 +52,9 @@
     defaultConfig {
         multiDexEnabled = true
     }
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.lifecycle"
diff --git a/camera/camera-mlkit-vision/build.gradle b/camera/camera-mlkit-vision/build.gradle
index cb76fcb..5e12fca 100644
--- a/camera/camera-mlkit-vision/build.gradle
+++ b/camera/camera-mlkit-vision/build.gradle
@@ -49,6 +49,10 @@
         multiDexEnabled = true
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.mlkit.vision"
 }
diff --git a/camera/camera-testing/build.gradle b/camera/camera-testing/build.gradle
index d94c891..c521f7b 100644
--- a/camera/camera-testing/build.gradle
+++ b/camera/camera-testing/build.gradle
@@ -59,6 +59,10 @@
         }
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
 
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
index 39936df..944b757 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
@@ -62,6 +62,7 @@
     private final ArrayList<CallbackToFutureAdapter.Completer<Void>> mSubmittedCompleterList =
             new ArrayList<>();
 
+    private boolean mIsZslDisabled = true;
     private boolean mIsZslConfigAdded = false;
 
     public FakeCameraControl(@NonNull ControlUpdateCallback controlUpdateCallback) {
@@ -130,6 +131,11 @@
     }
 
     @Override
+    public void setZslDisabled(boolean disabled) {
+        mIsZslDisabled = disabled;
+    }
+
+    @Override
     public void addZslConfig(@NonNull Size resolution,
             @NonNull SessionConfig.Builder sessionConfigBuilder) {
         // Override if Zero-Shutter Lag needs to add config to session config.
@@ -137,7 +143,15 @@
     }
 
     /**
-     * Check if {@link FakeCameraControl#addZslConfig(Size, SessionConfig.Builder)} is
+     * Checks if Zsl is disabled. Only for testing purpose.
+     * @return
+     */
+    public boolean isZslDisabled() {
+        return mIsZslDisabled;
+    }
+
+    /**
+     * Checks if {@link FakeCameraControl#addZslConfig(Size, SessionConfig.Builder)} is
      * triggered. Only for testing purpose.
      * @return
      */
diff --git a/camera/camera-testlib-extensions/build.gradle b/camera/camera-testlib-extensions/build.gradle
index 7744cff..3f343b6 100644
--- a/camera/camera-testlib-extensions/build.gradle
+++ b/camera/camera-testlib-extensions/build.gradle
@@ -30,6 +30,11 @@
     defaultConfig {
         multiDexEnabled true
     }
+
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     namespace "androidx.camera.extensions.impl"
 }
 
diff --git a/camera/camera-video/build.gradle b/camera/camera-video/build.gradle
index c1af9d3..b4e94bf 100644
--- a/camera/camera-video/build.gradle
+++ b/camera/camera-video/build.gradle
@@ -74,6 +74,10 @@
         multiDexEnabled = true
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.video"
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/ExcludeStretchedVideoQualityQuirk.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/ExcludeStretchedVideoQualityQuirk.java
index 7128625..4cb6541 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/ExcludeStretchedVideoQualityQuirk.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/ExcludeStretchedVideoQualityQuirk.java
@@ -23,10 +23,11 @@
 import androidx.camera.video.Quality;
 
 /**
- * Bug Id: 202792648
- * Description: The captured video is stretched while selecting the quality is greater or
- * equality to FHD resolution.
- * Device(s): Samsung J4 (sm-j400g)
+ * <p>QuirkSummary
+ *     Bug Id: 202792648
+ *     Description: The captured video is stretched while selecting the quality is greater or
+ *                  equality to FHD resolution
+ *     Device(s): Samsung J4 (sm-j400g)
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class ExcludeStretchedVideoQualityQuirk implements VideoQualityQuirk {
diff --git a/camera/camera-view/build.gradle b/camera/camera-view/build.gradle
index 128207a..4339da8 100644
--- a/camera/camera-view/build.gradle
+++ b/camera/camera-view/build.gradle
@@ -69,6 +69,10 @@
         multiDexEnabled = true
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.view"
 }
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/SurfaceViewNotCroppedByParentQuirk.java b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/SurfaceViewNotCroppedByParentQuirk.java
index 606f941..4965c24 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/SurfaceViewNotCroppedByParentQuirk.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/SurfaceViewNotCroppedByParentQuirk.java
@@ -24,9 +24,13 @@
 /**
  * A quirk where a scaled up SurfaceView is not cropped by the parent View.
  *
- * <p> On certain Xiaomi devices, when the scale type is FILL_* and the preview is scaled up
- * to be larger than its parent, the SurfaceView is not cropped by its parent. As the result, the
- * preview incorrectly covers the neighboring UI elements. b/211370840
+ * <p>QuirkSummary
+ *     Bug Id: 211370840
+ *     Description: On certain Xiaomi devices, when the scale type is FILL_* and the preview is
+ *                  scaled up to be larger than its parent, the SurfaceView is not cropped by its
+ *                  parent. As the result, the preview incorrectly covers the neighboring UI
+ *                  elements.
+ *     Device(s): XIAOMI M2101K7AG
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class SurfaceViewNotCroppedByParentQuirk implements Quirk {
diff --git a/camera/camera-viewfinder/build.gradle b/camera/camera-viewfinder/build.gradle
index 61ab815..aa1e133 100644
--- a/camera/camera-viewfinder/build.gradle
+++ b/camera/camera-viewfinder/build.gradle
@@ -65,6 +65,10 @@
         multiDexEnabled = true
     }
 
+    lintOptions {
+        enable 'CameraXQuirksClassDetector'
+    }
+
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.camera.viewfinder"
     lintOptions {
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index 342ffd0..38008d3 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -108,7 +108,6 @@
 @LargeTest
 @RunWith(Parameterized::class)
 class ImageCaptureTest(private val implName: String, private val cameraXConfig: CameraXConfig) {
-
     @get:Rule
     val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
         CameraUtil.PreTestCameraIdList(cameraXConfig)
diff --git a/car/app/app-automotive/src/main/res/values-ky/strings.xml b/car/app/app-automotive/src/main/res/values-ky/strings.xml
index 192fef2..a27b786 100644
--- a/car/app/app-automotive/src/main/res/values-ky/strings.xml
+++ b/car/app/app-automotive/src/main/res/values-ky/strings.xml
@@ -23,8 +23,8 @@
     <string name="error_message_client_side_error" msgid="3323186720368387787">"Колдонмодо ката кетти. Бул катаны колдонмонун иштеп чыгуучусуна кабарлаңыз"</string>
     <string name="error_message_host_error" msgid="5484419926049675696">"Тутум катасы"</string>
     <string name="error_message_host_connection_lost" msgid="5723205987837759151">"Тутум убактылуу жеткиликсиз"</string>
-    <string name="error_message_host_not_found" msgid="3241065067065670113">"Тутумду жаңыртуу керек"</string>
-    <string name="error_message_host_incompatible" msgid="160406216155183851">"Тутумду жаңыртуу керек"</string>
+    <string name="error_message_host_not_found" msgid="3241065067065670113">"Системаны жаңыртуу керек"</string>
+    <string name="error_message_host_incompatible" msgid="160406216155183851">"Системаны жаңыртуу керек"</string>
     <string name="error_message_multiple_hosts" msgid="2591031904206928207">"Шайкеш келбеген тутум"</string>
     <string name="error_message_unknown_error" msgid="1918523834689044166">"Белгисиз ката"</string>
     <string name="error_message_no_vending" msgid="5866202078252905802">"Унаа кызматтары менен байланышыңыз"</string>
diff --git a/car/app/app-samples/showcase/automotive/build.gradle b/car/app/app-samples/showcase/automotive/build.gradle
index 878e1f5..81a0c13 100644
--- a/car/app/app-samples/showcase/automotive/build.gradle
+++ b/car/app/app-samples/showcase/automotive/build.gradle
@@ -31,6 +31,9 @@
     }
 
     buildTypes {
+        debug {
+            pseudoLocalesEnabled true
+        }
         release {
             // Enables code shrinking, obfuscation, and optimization.
             minifyEnabled true
diff --git a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
index 19c1727..877fe98 100644
--- a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
@@ -60,7 +60,8 @@
   <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher"
-      android:extractNativeLibs="false">
+      android:extractNativeLibs="false"
+      android:supportsRtl="true">
 
     <meta-data
         android:name="com.android.automotive"
diff --git a/car/app/app-samples/showcase/common/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/common/src/main/AndroidManifest.xml
index 1913959..542568f 100644
--- a/car/app/app-samples/showcase/common/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/common/src/main/AndroidManifest.xml
@@ -21,7 +21,8 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 
-    <application>
+    <application
+        android:supportsRtl="true">
         <activity android:name=".templates.SignInWithGoogleActivity" />
     </application>
 </manifest>
diff --git a/car/app/app-samples/showcase/mobile/build.gradle b/car/app/app-samples/showcase/mobile/build.gradle
index 5df6865..48c8048 100644
--- a/car/app/app-samples/showcase/mobile/build.gradle
+++ b/car/app/app-samples/showcase/mobile/build.gradle
@@ -31,6 +31,9 @@
     }
 
     buildTypes {
+        debug {
+            pseudoLocalesEnabled true
+        }
         release {
             // Enables code shrinking, obfuscation, and optimization.
             minifyEnabled true
diff --git a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
index 6f80a4e..3e1f7f2 100644
--- a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
@@ -41,7 +41,8 @@
   <application
       android:label="@string/app_name"
       android:icon="@drawable/ic_launcher"
-      android:extractNativeLibs="false">
+      android:extractNativeLibs="false"
+      android:supportsRtl="true">
 
     <meta-data
         android:name="com.google.android.gms.car.application"
diff --git a/collection/collection/build.gradle b/collection/collection/build.gradle
index bb4dead..eedae0f 100644
--- a/collection/collection/build.gradle
+++ b/collection/collection/build.gradle
@@ -16,16 +16,35 @@
 
 
 import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
 
 plugins {
     id("AndroidXPlugin")
     id("org.jetbrains.kotlin.multiplatform")
 }
 
+// This should be true when building from GitHub, and false when building
+// from AOSP.  Use this to block out any features or code that we're not
+// ready to build yet in AOSP
+
+def boolProperty(name) {
+    return project.providers.gradleProperty(name).getOrNull()?.toBoolean()
+}
+
+def playground = androidx.build.StudioType.isPlayground(project)
+//Native on by default in playground
+def enableNative = boolProperty('androidx.kmp.native.enabled') ?: playground
+
 kotlin {
     jvm {
         withJava()
     }
+    if (enableNative) {
+        macosX64()
+        macosArm64()
+        linuxX64()
+        mingwX64()
+    }
 
     sourceSets {
         commonMain {
@@ -40,6 +59,19 @@
             }
         }
 
+        if (enableNative) {
+            nativeMain
+
+            configure([linuxX64Main, macosX64Main, macosArm64Main, mingwX64Main]) {
+                dependsOn nativeMain
+            }
+
+            nativeTest
+            configure([linuxX64Test, macosX64Test, macosArm64Test, mingwX64Test]) {
+                dependsOn nativeTest
+            }
+        }
+
         jvmMain {
             dependencies {
                 api(libs.kotlinStdlib)
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
similarity index 87%
rename from collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt
rename to collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
index 80a7b91..6230ddb 100644
--- a/collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
@@ -16,6 +16,9 @@
 
 package androidx.collection
 
+import androidx.collection.CollectionPlatformUtils.createIndexOutOfBoundsException
+import kotlin.jvm.JvmOverloads
+
 /**
  * CircularArray is a generic circular array data structure that provides O(1) random read, O(1)
  * prepend and O(1) append. The CircularArray automatically grows its capacity when number of added
@@ -40,8 +43,8 @@
 
         // If minCapacity isn't a power of 2, round up to the next highest
         // power of 2.
-        val arrayCapacity: Int = if (Integer.bitCount(minCapacity) != 1) {
-            Integer.highestOneBit(minCapacity - 1) shl 1
+        val arrayCapacity: Int = if (minCapacity.countOneBits() != 1) {
+            (minCapacity - 1).takeHighestOneBit() shl 1
         } else {
             minCapacity
         }
@@ -97,11 +100,11 @@
      * Remove first element from front of the [CircularArray] and return it.
      *
      * @return The element removed.
-     * @throws ArrayIndexOutOfBoundsException if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty (on jvm)
      */
     public fun popFirst(): E {
         if (head == tail) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         val result = elements[head]
         elements[head] = null
@@ -115,11 +118,11 @@
      * Remove last element from end of the [CircularArray] and return it.
      *
      * @return The element removed.
-     * @throws ArrayIndexOutOfBoundsException if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public fun popLast(): E {
         if (head == tail) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         val t = (tail - 1) and capacityBitmask
         val result = elements[t]
@@ -142,14 +145,14 @@
      * is less than or equal to 0.
      *
      * @param count Number of elements to remove.
-     * @throws ArrayIndexOutOfBoundsException if [count] is larger than [size]
+     * @throws [ArrayIndexOutOfBoundsException] if [count] is larger than [size]
      */
     public fun removeFromStart(count: Int) {
         if (count <= 0) {
             return
         }
         if (count > size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
 
         var numOfElements = count
@@ -177,14 +180,14 @@
      * is less than or equals to 0.
      *
      * @param count Number of elements to remove.
-     * @throws ArrayIndexOutOfBoundsException if [count] is larger than [size]
+     * @throws [ArrayIndexOutOfBoundsException] if [count] is larger than [size]
      */
     public fun removeFromEnd(count: Int) {
         if (count <= 0) {
             return
         }
         if (count > size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
 
         var numOfElements = count
@@ -213,12 +216,12 @@
      * Get first element of the [CircularArray].
      *
      * @return The first element.
-     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public val first: E
         get() {
             if (head == tail) {
-                throw ArrayIndexOutOfBoundsException()
+                throw createIndexOutOfBoundsException()
             }
             return elements[head]!!
         }
@@ -227,12 +230,12 @@
      * Get last element of the [CircularArray].
      *
      * @return The last element.
-     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public val last: E
         get() {
             if (head == tail) {
-                throw ArrayIndexOutOfBoundsException()
+                throw createIndexOutOfBoundsException()
             }
             return elements[tail - 1 and capacityBitmask]!!
         }
@@ -242,11 +245,11 @@
      *
      * @param index The zero based element index in the [CircularArray].
      * @return The nth element.
-     * @throws [ArrayIndexOutOfBoundsException] if n < 0 or n >= size().
+     * @throws [ArrayIndexOutOfBoundsException] if n < 0 or n >= size()
      */
     public operator fun get(index: Int): E {
         if (index < 0 || index >= size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         return elements[(head + index) and capacityBitmask]!!
     }
@@ -266,4 +269,4 @@
      * @return `true` if [size] is 0.
      */
     public fun isEmpty(): Boolean = head == tail
-}
+}
\ No newline at end of file
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
new file mode 100644
index 0000000..f3cec22
--- /dev/null
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+/**
+ * Internal utils for handling implementation differences for the various targets of Collections.
+ */
+internal expect object CollectionPlatformUtils {
+
+    /**
+     * IndexOutOfBoundsException is the nearest kotlin common ancestor for the native and jvm
+     * specific implementations of ArrayIndexOutOfBoundsException.  Actuals should throw an
+     * exception specific to their target platform.
+     */
+    internal inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException
+}
diff --git a/collection/collection/src/jvmTest/java/androidx/collection/CircularArrayTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/CircularArrayTest.kt
similarity index 100%
rename from collection/collection/src/jvmTest/java/androidx/collection/CircularArrayTest.kt
rename to collection/collection/src/commonTest/kotlin/androidx/collection/CircularArrayTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java b/collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
similarity index 62%
copy from health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
copy to collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
index a5d6306..0233729 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
+++ b/collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-package androidx.health.data.client.metadata;
+package androidx.collection
 
-import static com.google.common.truth.Truth.assertThat;
+/**
+ * JVM actual of internal utils for handling target differences in collection code.
+ */
+internal actual object CollectionPlatformUtils {
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DeviceTypeTest {
-    @Test
-    public void javaInterlope() {
-        assertThat(DeviceTypes.CHEST_STRAP).isNotEqualTo(DeviceTypes.FITNESS_BAND);
+    @Suppress("NOTHING_TO_INLINE")
+    internal actual inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException {
+        return ArrayIndexOutOfBoundsException()
     }
 }
diff --git a/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java b/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java
deleted file mode 100644
index 6e14244..0000000
--- a/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.collection;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-@RunWith(JUnit4.class)
-public class LruCacheTest {
-
-    private int mExpectedCreateCount;
-    private int mExpectedPutCount;
-    private int mExpectedHitCount;
-    private int mExpectedMissCount;
-    private int mExpectedEvictionCount;
-
-    @Test
-    public void testStatistics() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        assertStatistics(cache);
-        assertEquals(null, cache.put("a", "A"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertSnapshot(cache, "a", "A");
-        assertEquals(null, cache.put("b", "B"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertHit(cache, "b", "B");
-        assertSnapshot(cache, "a", "A", "b", "B");
-        assertEquals(null, cache.put("c", "C"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "a", "A", "b", "B", "c", "C");
-        assertEquals(null, cache.put("d", "D"));
-        mExpectedPutCount++;
-        mExpectedEvictionCount++; // a should have been evicted
-        assertStatistics(cache);
-        assertMiss(cache, "a");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertHit(cache, "d", "D");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "d", "D", "b", "B", "c", "C");
-        assertEquals(null, cache.put("e", "E"));
-        mExpectedPutCount++;
-        mExpectedEvictionCount++; // d should have been evicted
-        assertStatistics(cache);
-        assertMiss(cache, "d");
-        assertMiss(cache, "a");
-        assertHit(cache, "e", "E");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "e", "E", "b", "B", "c", "C");
-    }
-
-    @Test
-    public void testStatisticsWithCreate() {
-        LruCache<String, String> cache = newCreatingCache();
-        assertStatistics(cache);
-        assertCreated(cache, "aa", "created-aa");
-        assertHit(cache, "aa", "created-aa");
-        assertSnapshot(cache, "aa", "created-aa");
-        assertCreated(cache, "bb", "created-bb");
-        assertMiss(cache, "c");
-        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb");
-        assertCreated(cache, "cc", "created-cc");
-        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc");
-        mExpectedEvictionCount++; // aa will be evicted
-        assertCreated(cache, "dd", "created-dd");
-        assertSnapshot(cache, "bb", "created-bb",  "cc", "created-cc", "dd", "created-dd");
-        mExpectedEvictionCount++; // bb will be evicted
-        assertCreated(cache, "aa", "created-aa");
-        assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa");
-    }
-
-    @Test
-    public void testCreateOnCacheMiss() {
-        LruCache<String, String> cache = newCreatingCache();
-        String created = cache.get("aa");
-        assertEquals("created-aa", created);
-    }
-
-    @Test
-    public void testNoCreateOnCacheHit() {
-        LruCache<String, String> cache = newCreatingCache();
-        cache.put("aa", "put-aa");
-        assertEquals("put-aa", cache.get("aa"));
-    }
-
-    @Test
-    public void testConstructorDoesNotAllowZeroCacheSize() {
-        try {
-            new LruCache<String, String>(0);
-            fail();
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testCannotPutNullKey() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        try {
-            cache.put(null, "A");
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testCannotPutNullValue() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        try {
-            cache.put("a", null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testToString() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString());
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("d", "D");
-        cache.get("a"); // miss
-        cache.get("b"); // hit
-        cache.get("c"); // hit
-        cache.get("d"); // hit
-        cache.get("e"); // miss
-        assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString());
-    }
-
-    @Test
-    public void testEvictionWithSingletonCache() {
-        LruCache<String, String> cache = new LruCache<String, String>(1);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        assertSnapshot(cache, "b", "B");
-    }
-
-    @Test
-    public void testEntryEvictedWhenFull() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        assertEquals(Collections.<String>emptyList(), log);
-        cache.put("d", "D");
-        assertEquals(Arrays.asList("a=A"), log);
-    }
-
-    /**
-     * Replacing the value for a key doesn't cause an eviction but it does bring
-     * the replaced entry to the front of the queue.
-     */
-    @Test
-    public void testPutCauseEviction() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("b", "B2");
-        assertEquals(Arrays.asList("b=B>B2"), log);
-        assertSnapshot(cache, "a", "A", "c", "C", "b", "B2");
-    }
-
-    @Test
-    public void testCustomSizesImpactsSize() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return key.length() + value.length();
-            }
-        };
-        assertEquals(0, cache.size());
-        cache.put("a", "AA");
-        assertEquals(3, cache.size());
-        cache.put("b", "BBBB");
-        assertEquals(8, cache.size());
-        cache.put("a", "");
-        assertEquals(6, cache.size());
-    }
-
-    @Test
-    public void testEvictionWithCustomSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(4) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "AAAA");
-        assertSnapshot(cache, "a", "AAAA");
-        cache.put("b", "BBBB"); // should evict a
-        assertSnapshot(cache, "b", "BBBB");
-        cache.put("c", "CC"); // should evict b
-        assertSnapshot(cache, "c", "CC");
-        cache.put("d", "DD");
-        assertSnapshot(cache, "c", "CC", "d", "DD");
-        cache.put("e", "E"); // should evict c
-        assertSnapshot(cache, "d", "DD", "e", "E");
-        cache.put("f", "F");
-        assertSnapshot(cache, "d", "DD", "e", "E", "f", "F");
-        cache.put("g", "G"); // should evict d
-        assertSnapshot(cache, "e", "E", "f", "F", "g", "G");
-        cache.put("h", "H");
-        assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H");
-        cache.put("i", "III"); // should evict e, f, and g
-        assertSnapshot(cache, "h", "H", "i", "III");
-        cache.put("j", "JJJ"); // should evict h and i
-        assertSnapshot(cache, "j", "JJJ");
-    }
-
-    @Test
-    public void testEvictionThrowsWhenSizesAreInconsistent() {
-        LruCache<String, int[]> cache = new LruCache<String, int[]>(4) {
-            @Override protected int sizeOf(String key, int[] value) {
-                return value[0];
-            }
-        };
-        int[] a = { 4 };
-        cache.put("a", a);
-        // get the cache size out of sync
-        a[0] = 1;
-        assertEquals(4, cache.size());
-        // evict something
-        try {
-            cache.put("b", new int[] { 2 });
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    @Test
-    public void testEvictionThrowsWhenSizesAreNegative() {
-        LruCache<String, String> cache = new LruCache<String, String>(4) {
-            @Override protected int sizeOf(String key, String value) {
-                return -1;
-            }
-        };
-        try {
-            cache.put("a", "A");
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    /**
-     * Naive caches evict at most one element at a time. This is problematic
-     * because evicting a small element may be insufficient to make room for a
-     * large element.
-     */
-    @Test
-    public void testDifferentElementSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "1");
-        cache.put("b", "12345678");
-        cache.put("c", "1");
-        assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1");
-        cache.put("d", "12345678"); // should evict a and b
-        assertSnapshot(cache, "c", "1", "d", "12345678");
-        cache.put("e", "12345678"); // should evict c and d
-        assertSnapshot(cache, "e", "12345678");
-    }
-
-    @Test
-    public void testEvictAll() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.evictAll();
-        assertEquals(0, cache.size());
-        assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log);
-    }
-
-    @Test
-    public void testEvictAllEvictsSizeZeroElements() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return 0;
-            }
-        };
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.evictAll();
-        assertSnapshot(cache);
-    }
-
-    @Test
-    public void testRemoveWithCustomSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "123456");
-        cache.put("b", "1234");
-        cache.remove("a");
-        assertEquals(4, cache.size());
-    }
-
-    @Test
-    public void testRemoveAbsentElement() {
-        LruCache<String, String> cache = new LruCache<String, String>(10);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        assertEquals(null, cache.remove("c"));
-        assertEquals(2, cache.size());
-    }
-
-    @Test
-    public void testRemoveNullThrows() {
-        LruCache<String, String> cache = new LruCache<String, String>(10);
-        try {
-            cache.remove(null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testRemoveCallsEntryRemoved() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.remove("a");
-        assertEquals(Arrays.asList("a=A>null"), log);
-    }
-
-    @Test
-    public void testPutCallsEntryRemoved() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("a", "A2");
-        assertEquals(Arrays.asList("a=A>A2"), log);
-    }
-
-    @Test
-    public void testEntryRemovedIsCalledWithoutSynchronization() {
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                assertFalse(Thread.holdsLock(this));
-            }
-        };
-        cache.put("a", "A");
-        cache.put("a", "A2"); // replaced
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("d", "D");  // single eviction
-        cache.remove("a");    // removed
-        cache.evictAll();     // multiple eviction
-    }
-
-    @Test
-    public void testCreateIsCalledWithoutSynchronization() {
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                assertFalse(Thread.holdsLock(this));
-                return null;
-            }
-        };
-        cache.get("a");
-    }
-
-    /**
-     * Test what happens when a value is added to the map while create is
-     * working. The map value should be returned by get(), and the created value
-     * should be released with entryRemoved().
-     */
-    @Test
-    public void testCreateWithConcurrentPut() {
-        final List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                put(key, "B");
-                return "A";
-            }
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                log.add(key + "=" + oldValue + ">" + newValue);
-            }
-        };
-        assertEquals("B", cache.get("a"));
-        assertEquals(Arrays.asList("a=A>B"), log);
-    }
-
-    /**
-     * Test what happens when two creates happen concurrently. The result from
-     * the first create to return is returned by both gets. The other created
-     * values should be released with entryRemove().
-     */
-    @Test
-    public void testCreateWithConcurrentCreate() {
-        final List<String> log = new ArrayList<String>();
-        LruCache<String, Integer> cache = new LruCache<String, Integer>(3) {
-            int mCallCount = 0;
-            @Override protected Integer create(String key) {
-                if (mCallCount++ == 0) {
-                    assertEquals(2, get(key).intValue());
-                    return 1;
-                } else {
-                    return 2;
-                }
-            }
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, Integer oldValue, Integer newValue) {
-                log.add(key + "=" + oldValue + ">" + newValue);
-            }
-        };
-        assertEquals(2, cache.get("a").intValue());
-        assertEquals(Arrays.asList("a=1>2"), log);
-    }
-
-    /** Makes sure that LruCache operations are correctly synchronized to guarantee consistency. */
-    @Test
-    public void consistentMultithreadedAccess() {
-        class Tally {
-            int mNonNullValues;
-            int mNullValues;
-            int mValuesPut;
-            int mConflicts;
-            int mRemoved;
-        }
-
-        final Tally tally = new Tally();
-        final int rounds = 10000;
-        final String key = "key";
-        final int value = 42;
-        final LruCache<String, Integer> cache  = new LruCache<String, Integer>(1) {
-            @Override
-            protected Integer create(String key) {
-                return value;
-            }
-        };
-
-        Runnable r0 = new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < rounds; i++) {
-                    if (cache.get(key) != null) {
-                        tally.mNonNullValues++;
-                    } else {
-                        tally.mNullValues++;
-                    }
-                }
-            }
-        };
-
-        Runnable r1 = new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < rounds; i++) {
-                    if (i % 2 == 0) {
-                        if (cache.put(key, value) != null) {
-                            tally.mConflicts++;
-                        } else {
-                            tally.mValuesPut++;
-                        }
-                    } else {
-                        cache.remove(key);
-                        tally.mRemoved++;
-                    }
-                }
-            }
-        };
-
-
-        Thread t0 = new Thread(r0);
-        Thread t1 = new Thread(r1);
-
-        t0.start();
-        t1.start();
-        try {
-            t0.join();
-            t1.join();
-        } catch (InterruptedException e) {
-            fail();
-        }
-
-        assertEquals(rounds, tally.mNonNullValues);
-        assertEquals(0, tally.mNullValues);
-        assertEquals(rounds, tally.mValuesPut + tally.mConflicts + tally.mRemoved);
-    }
-
-    private LruCache<String, String> newCreatingCache() {
-        return new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                return (key.length() > 1) ? ("created-" + key) : null;
-            }
-        };
-    }
-
-    private LruCache<String, String> newRemovalLogCache(final List<String> log) {
-        return new LruCache<String, String>(3) {
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                String message = evicted
-                        ? (key + "=" + oldValue)
-                        : (key + "=" + oldValue + ">" + newValue);
-                log.add(message);
-            }
-        };
-    }
-
-    private void assertHit(LruCache<String, String> cache, String key, String value) {
-        assertEquals(value, cache.get(key));
-        mExpectedHitCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertMiss(LruCache<String, String> cache, String key) {
-        assertEquals(null, cache.get(key));
-        mExpectedMissCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertCreated(LruCache<String, String> cache, String key, String value) {
-        assertEquals(value, cache.get(key));
-        mExpectedMissCount++;
-        mExpectedCreateCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertStatistics(LruCache<?, ?> cache) {
-        assertEquals("create count", mExpectedCreateCount, cache.createCount());
-        assertEquals("put count", mExpectedPutCount, cache.putCount());
-        assertEquals("hit count", mExpectedHitCount, cache.hitCount());
-        assertEquals("miss count", mExpectedMissCount, cache.missCount());
-        assertEquals("eviction count", mExpectedEvictionCount, cache.evictionCount());
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T> void assertSnapshot(LruCache<T, T> cache, T... keysAndValues) {
-        List<T> actualKeysAndValues = new ArrayList<T>();
-        for (Map.Entry<T, T> entry : cache.snapshot().entrySet()) {
-            actualKeysAndValues.add(entry.getKey());
-            actualKeysAndValues.add(entry.getValue());
-        }
-        // assert using lists because order is important for LRUs
-        assertEquals(Arrays.asList(keysAndValues), actualKeysAndValues);
-    }
-}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt
new file mode 100644
index 0000000..8c0dc29
--- /dev/null
+++ b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+import kotlin.concurrent.thread
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+
+internal class LruCacheJvmTest {
+
+    @Test
+    fun testEntryRemovedIsCalledWithoutSynchronization() {
+        val cache =
+            object : LruCache<String, String>(3) {
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: String,
+                    newValue: String?
+                ) {
+                    assertFalse(Thread.holdsLock(this))
+                }
+            }
+        cache.put("a", "A")
+        cache.put("a", "A2") // replaced
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("d", "D") // single eviction
+        cache.remove("a") // removed
+        cache.evictAll() // multiple eviction
+    }
+
+    /** Makes sure that LruCache operations are correctly synchronized to guarantee consistency.  */
+    @Test
+    fun consistentMultithreadedAccess() {
+        var nonNullValues = 0
+        var nullValues = 0
+        var valuesPut = 0
+        var conflicts = 0
+        var removed = 0
+
+        val rounds = 10000
+        val key = "key"
+        val value = 42
+        val cache =
+            object : LruCache<String, Int>(1) {
+                override fun create(key: String): Int = value
+            }
+
+        val t0 =
+            thread {
+                repeat(rounds) {
+                    if (cache[key] != null) {
+                        nonNullValues++
+                    } else {
+                        nullValues++
+                    }
+                }
+            }
+
+        val t1 =
+            thread {
+                repeat(rounds) { i ->
+                    if (i % 2 == 0) {
+                        if (cache.put(key, value) != null) {
+                            conflicts++
+                        } else {
+                            valuesPut++
+                        }
+                    } else {
+                        cache.remove(key)
+                        removed++
+                    }
+                }
+            }
+
+        t0.join()
+        t1.join()
+
+        assertEquals(rounds, nonNullValues)
+        assertEquals(0, nullValues)
+        assertEquals(rounds, valuesPut + conflicts + removed)
+    }
+}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt
new file mode 100644
index 0000000..98d7ee6
--- /dev/null
+++ b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+import kotlin.test.Test
+import kotlin.test.assertContentEquals
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNull
+
+internal class LruCacheTest {
+
+    private var expectedCreateCount = 0
+    private var expectedPutCount = 0
+    private var expectedHitCount = 0
+    private var expectedMissCount = 0
+    private var expectedEvictionCount = 0
+
+    @Test
+    fun testStatistics() {
+        val cache = LruCache<String, String>(3)
+        assertStatistics(cache)
+        assertNull(cache.put("a", "A"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertSnapshot(cache, "a", "A")
+        assertNull(cache.put("b", "B"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertHit(cache, "b", "B")
+        assertSnapshot(cache, "a", "A", "b", "B")
+        assertNull(cache.put("c", "C"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "a", "A", "b", "B", "c", "C")
+        assertNull(cache.put("d", "D"))
+        expectedPutCount++
+        expectedEvictionCount++ // a should have been evicted
+        assertStatistics(cache)
+        assertMiss(cache, "a")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertHit(cache, "d", "D")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "d", "D", "b", "B", "c", "C")
+        assertNull(cache.put("e", "E"))
+        expectedPutCount++
+        expectedEvictionCount++ // d should have been evicted
+        assertStatistics(cache)
+        assertMiss(cache, "d")
+        assertMiss(cache, "a")
+        assertHit(cache, "e", "E")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "e", "E", "b", "B", "c", "C")
+    }
+
+    @Test
+    fun testStatisticsWithCreate() {
+        val cache = newCreatingCache()
+        assertStatistics(cache)
+        assertCreated(cache, "aa", "created-aa")
+        assertHit(cache, "aa", "created-aa")
+        assertSnapshot(cache, "aa", "created-aa")
+        assertCreated(cache, "bb", "created-bb")
+        assertMiss(cache, "c")
+        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb")
+        assertCreated(cache, "cc", "created-cc")
+        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc")
+        expectedEvictionCount++ // aa will be evicted
+        assertCreated(cache, "dd", "created-dd")
+        assertSnapshot(cache, "bb", "created-bb", "cc", "created-cc", "dd", "created-dd")
+        expectedEvictionCount++ // bb will be evicted
+        assertCreated(cache, "aa", "created-aa")
+        assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa")
+    }
+
+    @Test
+    fun testCreateOnCacheMiss() {
+        val cache = newCreatingCache()
+        val created = cache["aa"]
+        assertEquals("created-aa", created)
+    }
+
+    @Test
+    fun testNoCreateOnCacheHit() {
+        val cache = newCreatingCache()
+        cache.put("aa", "put-aa")
+        assertEquals("put-aa", cache["aa"])
+    }
+
+    @Test
+    fun testConstructorDoesNotAllowZeroCacheSize() {
+        assertFailsWith<IllegalArgumentException> {
+            LruCache<String, String>(0)
+        }
+    }
+
+    @Test
+    fun testToString() {
+        val cache = LruCache<String, String>(3)
+        assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString())
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("d", "D")
+        cache["a"] // miss
+        cache["b"] // hit
+        cache["c"] // hit
+        cache["d"] // hit
+        cache["e"] // miss
+        assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString())
+    }
+
+    @Test
+    fun testEvictionWithSingletonCache() {
+        val cache = LruCache<String, String>(1)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        assertSnapshot(cache, "b", "B")
+    }
+
+    @Test
+    fun testEntryEvictedWhenFull() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        assertContentEquals(emptyList(), log)
+        cache.put("d", "D")
+        assertContentEquals(listOf("a=A"), log)
+    }
+
+    /**
+     * Replacing the value for a key doesn't cause an eviction but it does bring
+     * the replaced entry to the front of the queue.
+     */
+    @Test
+    fun testPutCauseEviction() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("b", "B2")
+        assertContentEquals(listOf("b=B>B2"), log)
+        assertSnapshot(cache, "a", "A", "c", "C", "b", "B2")
+    }
+
+    @Test
+    fun testCustomSizesImpactsSize() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int =
+                    key.length + value.length
+            }
+        assertEquals(0, cache.size())
+        cache.put("a", "AA")
+        assertEquals(3, cache.size())
+        cache.put("b", "BBBB")
+        assertEquals(8, cache.size())
+        cache.put("a", "")
+        assertEquals(6, cache.size())
+    }
+
+    @Test
+    fun testEvictionWithCustomSizes() {
+        val cache =
+            object : LruCache<String, String>(4) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "AAAA")
+        assertSnapshot(cache, "a", "AAAA")
+        cache.put("b", "BBBB") // should evict a
+        assertSnapshot(cache, "b", "BBBB")
+        cache.put("c", "CC") // should evict b
+        assertSnapshot(cache, "c", "CC")
+        cache.put("d", "DD")
+        assertSnapshot(cache, "c", "CC", "d", "DD")
+        cache.put("e", "E") // should evict c
+        assertSnapshot(cache, "d", "DD", "e", "E")
+        cache.put("f", "F")
+        assertSnapshot(cache, "d", "DD", "e", "E", "f", "F")
+        cache.put("g", "G") // should evict d
+        assertSnapshot(cache, "e", "E", "f", "F", "g", "G")
+        cache.put("h", "H")
+        assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H")
+        cache.put("i", "III") // should evict e, f, and g
+        assertSnapshot(cache, "h", "H", "i", "III")
+        cache.put("j", "JJJ") // should evict h and i
+        assertSnapshot(cache, "j", "JJJ")
+    }
+
+    @Test
+    fun testEvictionThrowsWhenSizesAreInconsistent() {
+        val cache = object : LruCache<String, IntArray>(4) {
+            override fun sizeOf(key: String, value: IntArray): Int = value[0]
+        }
+        val a = intArrayOf(4)
+        cache.put("a", a)
+        // get the cache size out of sync
+        a[0] = 1
+        assertEquals(4, cache.size())
+        // evict something
+        assertFailsWith<IllegalStateException> {
+            cache.put("b", intArrayOf(2))
+        }
+    }
+
+    @Test
+    fun testEvictionThrowsWhenSizesAreNegative() {
+        val cache =
+            object : LruCache<String, String>(4) {
+                override fun sizeOf(key: String, value: String): Int = -1
+            }
+        assertFailsWith<IllegalStateException> {
+            cache.put("a", "A")
+        }
+    }
+
+    /**
+     * Naive caches evict at most one element at a time. This is problematic
+     * because evicting a small element may be insufficient to make room for a
+     * large element.
+     */
+    @Test
+    fun testDifferentElementSizes() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "1")
+        cache.put("b", "12345678")
+        cache.put("c", "1")
+        assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1")
+        cache.put("d", "12345678") // should evict a and b
+        assertSnapshot(cache, "c", "1", "d", "12345678")
+        cache.put("e", "12345678") // should evict c and d
+        assertSnapshot(cache, "e", "12345678")
+    }
+
+    @Test
+    fun testEvictAll() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.evictAll()
+        assertEquals(0, cache.size())
+        assertContentEquals(listOf("a=A", "b=B", "c=C"), log)
+    }
+
+    @Test
+    fun testEvictAllEvictsSizeZeroElements() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = 0
+            }
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.evictAll()
+        assertSnapshot(cache)
+    }
+
+    @Test
+    fun testRemoveWithCustomSizes() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "123456")
+        cache.put("b", "1234")
+        cache.remove("a")
+        assertEquals(4, cache.size())
+    }
+
+    @Test
+    fun testRemoveAbsentElement() {
+        val cache = LruCache<String, String>(10)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        assertNull(cache.remove("c"))
+        assertEquals(2, cache.size())
+    }
+
+    @Test
+    fun testRemoveCallsEntryRemoved() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.remove("a")
+        assertContentEquals(listOf("a=A>null"), log)
+    }
+
+    @Test
+    fun testPutCallsEntryRemoved() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("a", "A2")
+        assertContentEquals(listOf("a=A>A2"), log)
+    }
+
+    /**
+     * Test what happens when a value is added to the map while create is
+     * working. The map value should be returned by get(), and the created value
+     * should be released with entryRemoved().
+     */
+    @Test
+    fun testCreateWithConcurrentPut() {
+        val log = java.util.ArrayList<String>()
+        val cache =
+            object : LruCache<String, String>(3) {
+                override fun create(key: String): String {
+                    put(key, "B")
+                    return "A"
+                }
+
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: String,
+                    newValue: String?
+                ) {
+                    log.add("$key=$oldValue>$newValue")
+                }
+            }
+        assertEquals("B", cache["a"])
+        assertContentEquals(listOf("a=A>B"), log)
+    }
+
+    /**
+     * Test what happens when two creates happen concurrently. The result from
+     * the first create to return is returned by both gets. The other created
+     * values should be released with entryRemove().
+     */
+    @Test
+    fun testCreateWithConcurrentCreate() {
+        val log = ArrayList<String>()
+        val cache =
+            object : LruCache<String, Int>(3) {
+                var mCallCount = 0
+
+                override fun create(key: String): Int =
+                    if (mCallCount++ == 0) {
+                        assertEquals(2, get(key))
+                        1
+                    } else {
+                        2
+                    }
+
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: Int,
+                    newValue: Int?
+                ) {
+                    log.add("$key=$oldValue>$newValue")
+                }
+            }
+        assertEquals(2, cache["a"])
+        assertContentEquals(listOf("a=1>2"), log)
+    }
+
+    private fun newCreatingCache(): LruCache<String, String> =
+        object : LruCache<String, String>(3) {
+            override fun create(key: String): String? =
+                if (key.length > 1) "created-$key" else null
+        }
+
+    private fun newRemovalLogCache(log: MutableList<String>): LruCache<String, String> =
+        object : LruCache<String, String>(3) {
+            override fun entryRemoved(
+                evicted: Boolean,
+                key: String,
+                oldValue: String,
+                newValue: String?
+            ) {
+                log += if (evicted) "$key=$oldValue" else "$key=$oldValue>$newValue"
+            }
+        }
+
+    private fun assertHit(cache: LruCache<String, String>, key: String, value: String) {
+        assertEquals(value, cache[key])
+        expectedHitCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertMiss(cache: LruCache<String, String>, key: String) {
+        assertEquals(null, cache[key])
+        expectedMissCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertCreated(cache: LruCache<String, String>, key: String, value: String) {
+        assertEquals(value, cache[key])
+        expectedMissCount++
+        expectedCreateCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertStatistics(cache: LruCache<*, *>) {
+        assertEquals(expectedCreateCount, cache.createCount(), "create count")
+        assertEquals(expectedPutCount, cache.putCount(), "put count")
+        assertEquals(expectedHitCount, cache.hitCount(), "hit count")
+        assertEquals(expectedMissCount, cache.missCount(), "miss count")
+        assertEquals(expectedEvictionCount, cache.evictionCount(), "eviction count")
+    }
+
+    private fun <T : Any> assertSnapshot(cache: LruCache<T, T>, vararg keysAndValues: T) {
+        val actualKeysAndValues = cache.snapshot().flatMap { (key, value) -> listOf(key, value) }
+        // assert using lists because order is important for LRUs
+        assertContentEquals(keysAndValues.asList(), actualKeysAndValues)
+    }
+}
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java b/collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
similarity index 61%
copy from health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
copy to collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
index a5d6306..678d982 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
+++ b/collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -13,19 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.collection
 
-package androidx.health.data.client.metadata;
+/**
+ * Native actual of internal utils for handling target differences in collection code.
+ */
+internal actual object CollectionPlatformUtils {
 
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DeviceTypeTest {
-    @Test
-    public void javaInterlope() {
-        assertThat(DeviceTypes.CHEST_STRAP).isNotEqualTo(DeviceTypes.FITNESS_BAND);
+    internal actual inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException {
+        return ArrayIndexOutOfBoundsException()
     }
-}
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
index 143cc90..dd8c203 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
@@ -21,6 +21,8 @@
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.relocation.BringIntoViewResponder
+import androidx.compose.foundation.relocation.bringIntoViewResponder
 import androidx.compose.foundation.lazy.layout.ModifierLocalPinnableParent
 import androidx.compose.foundation.lazy.layout.PinnableParent
 import androidx.compose.foundation.lazy.layout.PinnableParent.PinnedItemsHandle
@@ -33,6 +35,9 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.modifier.modifierLocalProvider
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
@@ -57,6 +62,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class FocusableTest {
@@ -77,7 +83,7 @@
     }
 
     @Test
-    fun focusableTest_defaultSemantics() {
+    fun focusable_defaultSemantics() {
         rule.setContent {
             Box {
                 BasicText(
@@ -93,7 +99,7 @@
     }
 
     @Test
-    fun focusableTest_disabledSemantics() {
+    fun focusable_disabledSemantics() {
         rule.setContent {
             Box {
                 BasicText(
@@ -107,9 +113,8 @@
             .assert(isNotFocusable())
     }
 
-    @ExperimentalComposeUiApi
     @Test
-    fun focusableTest_focusAcquire() {
+    fun focusable_focusAcquire() {
         val (focusRequester, otherFocusRequester) = FocusRequester.createRefs()
         rule.setContent {
             Box {
@@ -147,9 +152,8 @@
             .assertIsNotFocused()
     }
 
-    @ExperimentalComposeUiApi
     @Test
-    fun focusableTest_interactionSource() {
+    fun focusable_interactionSource() {
         val interactionSource = MutableInteractionSource()
         val (focusRequester, otherFocusRequester) = FocusRequester.createRefs()
 
@@ -208,7 +212,7 @@
     }
 
     @Test
-    fun focusableTest_interactionSource_resetWhenDisposed() {
+    fun focusable_interactionSource_resetWhenDisposed() {
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         var emitFocusableText by mutableStateOf(true)
@@ -298,16 +302,48 @@
     }
 
     @Test
-    fun focusableText_testInspectorValue() {
+    fun focusable_inspectorValue() {
+        val modifier = Modifier.focusable() as InspectableValue
+        assertThat(modifier.nameFallback).isEqualTo("focusable")
+        assertThat(modifier.valueOverride).isNull()
+        assertThat(modifier.inspectableElements.map { it.name }.asIterable())
+            .containsExactly(
+                "enabled",
+                "interactionSource"
+            )
+    }
+
+    @Test
+    fun focusable_requestsBringIntoView_whenFocused() {
+        val requestedRects = mutableListOf<Rect>()
+        val bringIntoViewResponder = object : BringIntoViewResponder {
+            override fun calculateRectForParent(localRect: Rect): Rect = localRect
+            override suspend fun bringChildIntoView(localRect: Rect) {
+                requestedRects += localRect
+            }
+        }
+        val focusRequester = FocusRequester()
+
         rule.setContent {
-            val modifier = Modifier.focusable() as InspectableValue
-            assertThat(modifier.nameFallback).isEqualTo("focusable")
-            assertThat(modifier.valueOverride).isNull()
-            assertThat(modifier.inspectableElements.map { it.name }.asIterable())
-                .containsExactly(
-                    "enabled",
-                    "interactionSource"
+            with(rule.density) {
+                Box(
+                    Modifier
+                        .bringIntoViewResponder(bringIntoViewResponder)
+                        .focusRequester(focusRequester)
+                        .focusable()
+                        // Needs a non-zero size.
+                        .size(1f.toDp())
                 )
+            }
+        }
+
+        rule.runOnIdle {
+            assertThat(requestedRects).isEmpty()
+            focusRequester.requestFocus()
+        }
+
+        rule.runOnIdle {
+            assertThat(requestedRects).containsExactly(Rect(Offset.Zero, Size(1f, 1f)))
         }
     }
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequesterViewIntegrationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequesterViewIntegrationTest.kt
index 5d682d7..af5d456 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequesterViewIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequesterViewIntegrationTest.kt
@@ -25,7 +25,6 @@
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
@@ -46,7 +45,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
+@OptIn(ExperimentalFoundationApi::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class BringIntoViewRequesterViewIntegrationTest {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponderTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponderTest.kt
index 70eba2f..5e07173 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponderTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponderTest.kt
@@ -21,7 +21,6 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
@@ -41,7 +40,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
+@OptIn(ExperimentalFoundationApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class BringIntoViewResponderTest {
@@ -49,13 +48,13 @@
     @get:Rule
     val rule = createAndroidComposeRule<TestActivity>()
 
-    fun Float.toDp(): Dp = with(rule.density) { this@toDp.toDp() }
+    private fun Float.toDp(): Dp = with(rule.density) { this@toDp.toDp() }
 
     @Test
     fun zeroSizedItem_zeroSizedParent_bringIntoView() {
         // Arrange.
         val bringIntoViewRequester = BringIntoViewRequester()
-        lateinit var requestedRect: Rect
+        var requestedRect: Rect? = null
         rule.setContent {
             Box(
                 Modifier
@@ -65,7 +64,9 @@
         }
 
         // Act.
-        runBlocking { bringIntoViewRequester.bringIntoView() }
+        runBlocking {
+            bringIntoViewRequester.bringIntoView()
+        }
 
         // Assert.
         rule.runOnIdle {
@@ -131,8 +132,8 @@
                 Modifier
                     .size(1f.toDp())
                     .fakeScrollable { requestedRect = it }
-                    .size(20f.toDp(), 10f.toDp())
                     .bringIntoViewRequester(bringIntoViewRequester)
+                    .size(20f.toDp(), 10f.toDp())
             )
         }
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSoftKeyboardTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSoftKeyboardTest.kt
index dba0121..0b02623 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSoftKeyboardTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSoftKeyboardTest.kt
@@ -90,6 +90,7 @@
         keyboardHelper.waitForKeyboardVisibility(visible = true)
     }
 
+    @FlakyTest(bugId = 229247491)
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
     @Test
     fun keyboardHiddenWhenFocusIsLost() {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
index 96980dac..bd3c896 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextSelectionColorsScreenshotTest.kt
@@ -43,6 +43,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
+import androidx.test.filters.Suppress
 import androidx.test.screenshot.AndroidXScreenshotTestRule
 import org.junit.Rule
 import org.junit.Test
@@ -106,6 +107,7 @@
             .assertAgainstGolden(screenshotRule, "text_customSelectionColors")
     }
 
+    @Suppress // crashes when creating actuals on local b/228583901
     @Test
     fun textField_defaultSelectionColors() {
         rule.setContent {
@@ -126,6 +128,7 @@
             .assertAgainstGolden(screenshotRule, "textField_defaultSelectionColors")
     }
 
+    @Suppress // crashes when creating actuals on local b/228583901
     @Test
     fun textField_customSelectionColors() {
         rule.setContent {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
index 2e23bf6..1f25b23 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
@@ -17,7 +17,6 @@
 package androidx.compose.foundation
 
 import androidx.compose.runtime.remember
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.layout.LayoutCoordinates
@@ -45,7 +44,6 @@
  * Note that there may be some cases where the focused bounds change but the callback is _not_
  * invoked, but the last [LayoutCoordinates] will always return the most up-to-date bounds.
  */
-@OptIn(ExperimentalComposeUiApi::class)
 @ExperimentalFoundationApi
 fun Modifier.onFocusedBoundsChanged(onPositioned: (LayoutCoordinates?) -> Unit): Modifier =
     composed(
@@ -57,7 +55,6 @@
         remember(onPositioned) { FocusedBoundsObserverModifier(onPositioned) }
     }
 
-@OptIn(ExperimentalFoundationApi::class)
 private class FocusedBoundsObserverModifier(
     private val handler: (LayoutCoordinates?) -> Unit
 ) : ModifierLocalConsumer,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoView.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoView.kt
index 35aa72c..57efd71 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoView.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoView.kt
@@ -19,7 +19,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.OnGloballyPositionedModifier
+import androidx.compose.ui.layout.OnPlacedModifier
 import androidx.compose.ui.modifier.ModifierLocalConsumer
 import androidx.compose.ui.modifier.ModifierLocalReadScope
 import androidx.compose.ui.modifier.modifierLocalOf
@@ -69,7 +69,7 @@
 internal abstract class BringIntoViewChildModifier(
     private val defaultParent: BringIntoViewParent
 ) : ModifierLocalConsumer,
-    OnGloballyPositionedModifier {
+    OnPlacedModifier {
 
     private var localParent: BringIntoViewParent? = null
 
@@ -87,7 +87,7 @@
         }
     }
 
-    override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
+    override fun onPlaced(coordinates: LayoutCoordinates) {
         layoutCoordinates = coordinates
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
index 9beb190..531f018 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.geometry.Offset
@@ -61,7 +60,6 @@
  * The text magnifier follows horizontal dragging exactly, but is vertically clamped to the current
  * line, so when it changes lines we animate it.
  */
-@OptIn(ExperimentalComposeUiApi::class)
 @Suppress("ModifierInspectorInfo")
 internal fun Modifier.animatedSelectionMagnifier(
     magnifierCenter: () -> Offset,
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index a211c10..735f25a 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -237,6 +237,8 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
@@ -245,8 +247,8 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class IconKt {
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index 78c1a14..98e9c45 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -313,6 +313,8 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
@@ -325,8 +327,8 @@
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilledIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material3.IconButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index a211c10..735f25a 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -237,6 +237,8 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
@@ -245,8 +247,8 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.IconToggleButtonColors colors, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class IconKt {
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index 05448b4..5239032 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -96,10 +96,10 @@
 import androidx.compose.material3.samples.TextButtonSample
 import androidx.compose.material3.samples.TextFieldSample
 import androidx.compose.material3.samples.TextFieldWithErrorState
-import androidx.compose.material3.samples.TextFieldWithHelperMessage
 import androidx.compose.material3.samples.TextFieldWithHideKeyboardOnImeAction
 import androidx.compose.material3.samples.TextFieldWithIcons
 import androidx.compose.material3.samples.TextFieldWithPlaceholder
+import androidx.compose.material3.samples.TextFieldWithSupportingText
 import androidx.compose.material3.samples.TextTabs
 import androidx.compose.material3.samples.TriStateCheckboxSample
 import androidx.compose.runtime.Composable
@@ -684,11 +684,11 @@
         TextFieldWithErrorState()
     },
     Example(
-        name = ::TextFieldWithHelperMessage.name,
+        name = ::TextFieldWithSupportingText.name,
         description = TextFieldsExampleDescription,
         sourceUrl = TextFieldsExampleSourceUrl
     ) {
-        TextFieldWithHelperMessage()
+        TextFieldWithSupportingText()
     },
     Example(
         name = ::PasswordTextField.name,
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
index 44ae71a..b9b8a42 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TabSamples.kt
@@ -61,7 +61,7 @@
 @Composable
 fun TextTabs() {
     var state by remember { mutableStateOf(0) }
-    val titles = listOf("TAB 1", "TAB 2", "TAB 3 WITH LOTS OF TEXT")
+    val titles = listOf("Tab 1", "Tab 2", "Tab 3 with lots of text")
     Column {
         TabRow(selectedTabIndex = state) {
             titles.forEachIndexed { index, title ->
@@ -106,9 +106,9 @@
 fun TextAndIconTabs() {
     var state by remember { mutableStateOf(0) }
     val titlesAndIcons = listOf(
-        "TAB 1" to Icons.Filled.Favorite,
-        "TAB 2" to Icons.Filled.Favorite,
-        "TAB 3 WITH LOTS OF TEXT" to Icons.Filled.Favorite
+        "Tab 1" to Icons.Filled.Favorite,
+        "Tab 2" to Icons.Filled.Favorite,
+        "Tab 3 with lots of text" to Icons.Filled.Favorite
     )
     Column {
         TabRow(selectedTabIndex = state) {
@@ -133,9 +133,9 @@
 fun LeadingIconTabs() {
     var state by remember { mutableStateOf(0) }
     val titlesAndIcons = listOf(
-        "TAB" to Icons.Filled.Favorite,
-        "TAB & ICON" to Icons.Filled.Favorite,
-        "TAB 3 WITH LOTS OF TEXT" to Icons.Filled.Favorite
+        "Tab" to Icons.Filled.Favorite,
+        "Tab & icon" to Icons.Filled.Favorite,
+        "Tab 3 with lots of text" to Icons.Filled.Favorite
     )
     Column {
         TabRow(selectedTabIndex = state) {
@@ -160,16 +160,16 @@
 fun ScrollingTextTabs() {
     var state by remember { mutableStateOf(0) }
     val titles = listOf(
-        "TAB 1",
-        "TAB 2",
-        "TAB 3 WITH LOTS OF TEXT",
-        "TAB 4",
-        "TAB 5",
-        "TAB 6 WITH LOTS OF TEXT",
-        "TAB 7",
-        "TAB 8",
-        "TAB 9 WITH LOTS OF TEXT",
-        "TAB 10"
+        "Tab 1",
+        "Tab 2",
+        "Tab 3 with lots of text",
+        "Tab 4",
+        "Tab 5",
+        "Tab 6 with lots of text",
+        "Tab 7",
+        "Tab 8",
+        "Tab 9 with lots of text",
+        "Tab 10"
     )
     Column {
         ScrollableTabRow(selectedTabIndex = state) {
@@ -193,7 +193,7 @@
 @Composable
 fun FancyTabs() {
     var state by remember { mutableStateOf(0) }
-    val titles = listOf("TAB 1", "TAB 2", "TAB 3")
+    val titles = listOf("Tab 1", "Tab 2", "Tab 3")
     Column {
         TabRow(selectedTabIndex = state) {
             titles.forEachIndexed { index, title ->
@@ -212,7 +212,7 @@
 @Composable
 fun FancyIndicatorTabs() {
     var state by remember { mutableStateOf(0) }
-    val titles = listOf("TAB 1", "TAB 2", "TAB 3")
+    val titles = listOf("Tab 1", "Tab 2", "Tab 3")
 
     // Reuse the default offset animation modifier, but use our own indicator
     val indicator = @Composable { tabPositions: List<TabPosition> ->
@@ -244,7 +244,7 @@
 @Composable
 fun FancyIndicatorContainerTabs() {
     var state by remember { mutableStateOf(0) }
-    val titles = listOf("TAB 1", "TAB 2", "TAB 3")
+    val titles = listOf("Tab 1", "Tab 2", "Tab 3")
 
     val indicator = @Composable { tabPositions: List<TabPosition> ->
         FancyAnimatedIndicator(tabPositions = tabPositions, selectedTabIndex = state)
@@ -275,16 +275,16 @@
 fun ScrollingFancyIndicatorContainerTabs() {
     var state by remember { mutableStateOf(0) }
     val titles = listOf(
-        "TAB 1",
-        "TAB 2",
-        "TAB 3 WITH LOTS OF TEXT",
-        "TAB 4",
-        "TAB 5",
-        "TAB 6 WITH LOTS OF TEXT",
-        "TAB 7",
-        "TAB 8",
-        "TAB 9 WITH LOTS OF TEXT",
-        "TAB 10"
+        "Tab 1",
+        "Tab 2",
+        "Tab 3 with lots of text",
+        "Tab 4",
+        "Tab 5",
+        "Tab 6 with lots of text",
+        "Tab 7",
+        "Tab 8",
+        "Tab 9 with lots of text",
+        "Tab 10"
     )
     val indicator = @Composable { tabPositions: List<TabPosition> ->
         FancyAnimatedIndicator(tabPositions = tabPositions, selectedTabIndex = state)
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
index 4bd25b0..ec9f8e4 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
@@ -48,6 +48,7 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.vector.ImageVector
@@ -117,33 +118,43 @@
 @Sampled
 @Composable
 fun TextFieldWithErrorState() {
+    val errorMessage = "Email format is invalid"
     var text by rememberSaveable { mutableStateOf("") }
     var isError by rememberSaveable { mutableStateOf(false) }
 
     fun validate(text: String) {
-        isError = text.count() < 5
+        isError = !text.contains('@')
     }
 
-    TextField(
-        value = text,
-        onValueChange = {
-            text = it
-            isError = false
-        },
-        singleLine = true,
-        label = { Text(if (isError) "Email*" else "Email") },
-        isError = isError,
-        keyboardActions = KeyboardActions { validate(text) },
-        modifier = Modifier.semantics {
-            // Provide localized description of the error
-            if (isError) error("Email format is invalid.")
-        }
-    )
+    Column {
+        TextField(
+            value = text,
+            onValueChange = {
+                text = it
+                isError = false
+            },
+            singleLine = true,
+            label = { Text(if (isError) "Email*" else "Email") },
+            isError = isError,
+            keyboardActions = KeyboardActions { validate(text) },
+            modifier = Modifier.semantics {
+                // Provide localized description of the error
+                if (isError) error(errorMessage)
+            }
+        )
+        // Supporting text for error message.
+        Text(
+            text = errorMessage,
+            color = MaterialTheme.colorScheme.error,
+            style = MaterialTheme.typography.bodySmall,
+            modifier = Modifier.padding(start = 16.dp, top = 4.dp).alpha(if (isError) 1f else 0f)
+        )
+    }
 }
 
 @Sampled
 @Composable
-fun TextFieldWithHelperMessage() {
+fun TextFieldWithSupportingText() {
     var text by rememberSaveable { mutableStateOf("") }
 
     Column {
@@ -153,10 +164,10 @@
             label = { Text("Label") }
         )
         Text(
-            text = "Helper message",
+            text = "Supporting text",
             color = MaterialTheme.colorScheme.onSurface,
             style = MaterialTheme.typography.bodySmall,
-            modifier = Modifier.padding(start = 16.dp)
+            modifier = Modifier.padding(start = 16.dp, top = 4.dp)
         )
     }
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
index 6b3e7e0..e3d0489 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
@@ -16,6 +16,7 @@
 package androidx.compose.material3
 
 import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -65,6 +66,8 @@
  * [Interaction]s for this icon button. You can create and pass in your own remembered
  * [MutableInteractionSource] to observe [Interaction]s that will customize the appearance
  * / behavior of this icon button in different states
+ * @param colors an [IconButtonColors] that will be used to resolve the colors used for this icon
+ * button in different states. See [IconButtonDefaults.iconButtonColors].
  * @param content the content (icon) to be drawn inside the icon button. This is typically an
  * [Icon].
  */
@@ -74,6 +77,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
     content: @Composable () -> Unit
 ) {
     Box(
@@ -81,6 +85,7 @@
         modifier
             .minimumTouchTargetSize()
             .size(IconButtonTokens.StateLayerSize)
+            .background(color = colors.containerColor(enabled).value)
             .clickable(
                 onClick = onClick,
                 enabled = enabled,
@@ -93,13 +98,7 @@
             ),
         contentAlignment = Alignment.Center
     ) {
-        val contentColor =
-            if (enabled) {
-                IconButtonTokens.UnselectedIconColor.toColor()
-            } else {
-                IconButtonTokens.DisabledIconColor.toColor()
-                    .copy(alpha = IconButtonTokens.DisabledIconOpacity)
-            }
+        val contentColor = colors.contentColor(enabled).value
         CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
     }
 }
@@ -128,6 +127,8 @@
  * [Interaction]s for this icon button. You can create and pass in your own remembered
  * [MutableInteractionSource] to observe [Interaction]s that will customize the appearance
  * / behavior of this icon button in different states
+ * @param colors an [IconToggleButtonColors] that will be used to resolve the colors used for this
+ * icon button in different states. See [IconButtonDefaults.iconToggleButtonColors].
  * @param content the content (icon) to be drawn inside the icon button. This is typically an
  * [Icon].
  */
@@ -138,6 +139,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonColors(),
     content: @Composable () -> Unit
 ) {
     Box(
@@ -145,6 +147,7 @@
         modifier
             .minimumTouchTargetSize()
             .size(IconButtonTokens.StateLayerSize)
+            .background(color = colors.containerColor(enabled, checked).value)
             .toggleable(
                 value = checked,
                 onValueChange = onCheckedChange,
@@ -158,12 +161,7 @@
             ),
         contentAlignment = Alignment.Center
     ) {
-        val contentColor = when {
-            !enabled -> IconButtonTokens.DisabledIconColor.toColor()
-                .copy(alpha = IconButtonTokens.DisabledIconOpacity)
-            !checked -> IconButtonTokens.UnselectedIconColor.toColor()
-            else -> IconButtonTokens.SelectedIconColor.toColor()
-        }
+        val contentColor = colors.contentColor(enabled, checked).value
         CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
     }
 }
@@ -205,7 +203,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = FilledIconButtonTokens.ContainerShape,
+    shape: Shape = FilledIconButtonTokens.ContainerShape.toShape(),
     colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors(),
     content: @Composable () -> Unit
 ) = Surface(
@@ -267,7 +265,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = FilledIconButtonTokens.ContainerShape,
+    shape: Shape = FilledIconButtonTokens.ContainerShape.toShape(),
     colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
     content: @Composable () -> Unit
 ) = Surface(
@@ -326,7 +324,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = FilledIconButtonTokens.ContainerShape,
+    shape: Shape = FilledIconButtonTokens.ContainerShape.toShape(),
     colors: IconToggleButtonColors = IconButtonDefaults.filledIconToggleButtonColors(),
     content: @Composable () -> Unit
 ) = Surface(
@@ -391,7 +389,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = FilledIconButtonTokens.ContainerShape,
+    shape: Shape = FilledIconButtonTokens.ContainerShape.toShape(),
     colors: IconToggleButtonColors = IconButtonDefaults.filledTonalIconToggleButtonColors(),
     content: @Composable () -> Unit
 ) = Surface(
@@ -455,7 +453,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = OutlinedIconButtonTokens.ContainerShape,
+    shape: Shape = OutlinedIconButtonTokens.ContainerShape.toShape(),
     border: BorderStroke? = IconButtonDefaults.outlinedIconButtonBorder(enabled),
     colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors(),
     content: @Composable () -> Unit
@@ -478,7 +476,7 @@
 }
 
 /**
- * <a href="https://m3.material.io/components/icon-button/overview" class="external" target="_blank">Material Design oultined icon toggle button</a>.
+ * <a href="https://m3.material.io/components/icon-button/overview" class="external" target="_blank">Material Design outlined icon toggle button</a>.
  *
  * Icon buttons help people take supplementary actions with a single tap. They’re used when a
  * compact button is required, such as in a toolbar or image list.
@@ -517,7 +515,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = OutlinedIconButtonTokens.ContainerShape,
+    shape: Shape = OutlinedIconButtonTokens.ContainerShape.toShape(),
     border: BorderStroke? = IconButtonDefaults.outlinedIconToggleButtonBorder(enabled, checked),
     colors: IconToggleButtonColors = IconButtonDefaults.outlinedIconToggleButtonColors(),
     content: @Composable () -> Unit
@@ -607,6 +605,59 @@
 object IconButtonDefaults {
 
     /**
+     * Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
+     *
+     * @param containerColor the container color of this icon button when enabled.
+     * @param contentColor the content color of this icon button when enabled.
+     * @param disabledContainerColor the container color of this icon button when not enabled.
+     * @param disabledContentColor the content color of this icon button when not enabled.
+     */
+    @Composable
+    fun iconButtonColors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = LocalContentColor.current,
+        disabledContainerColor: Color = Color.Transparent,
+        disabledContentColor: Color =
+            contentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity)
+    ): IconButtonColors =
+        DefaultIconButtonColors(
+            containerColor = containerColor,
+            contentColor = contentColor,
+            disabledContainerColor = disabledContainerColor,
+            disabledContentColor = disabledContentColor,
+        )
+
+    /**
+     * Creates a [IconToggleButtonColors] that represents the default colors used in a
+     * [IconToggleButton].
+     *
+     * @param containerColor the container color of this icon button when enabled.
+     * @param contentColor the content color of this icon button when enabled.
+     * @param disabledContainerColor the container color of this icon button when not enabled.
+     * @param disabledContentColor the content color of this icon button when not enabled.
+     * @param checkedContainerColor the container color of this icon button when checked.
+     * @param checkedContentColor the content color of this icon button when checked.
+     */
+    @Composable
+    fun iconToggleButtonColors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = LocalContentColor.current,
+        disabledContainerColor: Color = Color.Transparent,
+        disabledContentColor: Color =
+            contentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity),
+        checkedContainerColor: Color = Color.Transparent,
+        checkedContentColor: Color = IconButtonTokens.SelectedIconColor.toColor()
+    ): IconToggleButtonColors =
+        DefaultIconToggleButtonColors(
+            containerColor = containerColor,
+            contentColor = contentColor,
+            disabledContainerColor = disabledContainerColor,
+            disabledContentColor = disabledContentColor,
+            checkedContainerColor = checkedContainerColor,
+            checkedContentColor = checkedContentColor,
+        )
+
+    /**
      * Creates a [IconButtonColors] that represents the default colors used in a [FilledIconButton].
      *
      * @param containerColor the container color of this icon button when enabled.
@@ -632,7 +683,7 @@
 
     /**
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
-     * toggleable [FilledIconButton].
+     * [FilledIconToggleButton].
      *
      * @param containerColor the container color of this icon button when enabled.
      * @param contentColor the content color of this icon button when enabled.
@@ -664,7 +715,8 @@
         )
 
     /**
-     * Creates a [IconButtonColors] that represents the default colors used in a [FilledIconButton].
+     * Creates a [IconButtonColors] that represents the default colors used in a
+     * [FilledTonalIconButton].
      *
      * @param containerColor the container color of this icon button when enabled.
      * @param contentColor the content color of this icon button when enabled.
@@ -689,7 +741,7 @@
 
     /**
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
-     * [FilledIconButton].
+     * [FilledTonalIconToggleButton].
      *
      * @param containerColor the container color of this icon button when enabled.
      * @param contentColor the content color of this icon button when enabled.
@@ -731,10 +783,10 @@
     @Composable
     fun outlinedIconButtonColors(
         containerColor: Color = Color.Transparent,
-        contentColor: Color = OutlinedIconButtonTokens.UnselectedColor.toColor(),
+        contentColor: Color = LocalContentColor.current,
         disabledContainerColor: Color = Color.Transparent,
-        disabledContentColor: Color = OutlinedIconButtonTokens.DisabledColor.toColor()
-            .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
+        disabledContentColor: Color =
+            contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
     ): IconButtonColors =
         DefaultIconButtonColors(
             containerColor = containerColor,
@@ -757,10 +809,10 @@
     @Composable
     fun outlinedIconToggleButtonColors(
         containerColor: Color = Color.Transparent,
-        contentColor: Color = OutlinedIconButtonTokens.UnselectedColor.toColor(),
+        contentColor: Color = LocalContentColor.current,
         disabledContainerColor: Color = Color.Transparent,
-        disabledContentColor: Color = OutlinedIconButtonTokens.DisabledColor.toColor()
-            .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
+        disabledContentColor: Color =
+            contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
         checkedContainerColor: Color =
             OutlinedIconButtonTokens.SelectedContainerColor.toColor(),
         checkedContentColor: Color = contentColorFor(checkedContainerColor)
@@ -797,9 +849,9 @@
     @Composable
     fun outlinedIconButtonBorder(enabled: Boolean): BorderStroke {
         val color: Color = if (enabled) {
-            OutlinedIconButtonTokens.UnselectedOutlineColor.toColor()
+            LocalContentColor.current
         } else {
-            OutlinedIconButtonTokens.DisabledOutlineColor.toColor()
+            LocalContentColor.current
                 .copy(alpha = OutlinedIconButtonTokens.DisabledOutlineOpacity)
         }
         return remember(color) {
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index 9759be1..262b681 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -94,7 +94,7 @@
  *
  * Additionally, you may provide additional message at the bottom:
  *
- * @sample androidx.compose.material3.samples.TextFieldWithHelperMessage
+ * @sample androidx.compose.material3.samples.TextFieldWithSupportingText
  *
  * Password text field example:
  *
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledIconButtonTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledIconButtonTokens.kt
index 7cc814e..f5fb952 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledIconButtonTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledIconButtonTokens.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_92
+// VERSION: v0_93
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
 package androidx.compose.material3.tokens
@@ -22,7 +22,7 @@
 
 internal object FilledIconButtonTokens {
     val ContainerColor = ColorSchemeKeyTokens.Primary
-    val ContainerShape = ShapeTokens.CornerFull
+    val ContainerShape = ShapeKeyTokens.CornerFull
     val ContainerSize = 40.0.dp
     val DisabledContainerColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledContainerOpacity = 0.12f
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledTonalIconButtonTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledTonalIconButtonTokens.kt
index c82f8c3..cbb9d40 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledTonalIconButtonTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FilledTonalIconButtonTokens.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_92
+// VERSION: v0_93
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
 package androidx.compose.material3.tokens
@@ -22,7 +22,7 @@
 
 internal object FilledTonalIconButtonTokens {
     val ContainerColor = ColorSchemeKeyTokens.SecondaryContainer
-    val ContainerShape = ShapeTokens.CornerFull
+    val ContainerShape = ShapeKeyTokens.CornerFull
     val ContainerSize = 40.0.dp
     val DisabledContainerColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledContainerOpacity = 0.12f
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/IconButtonTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/IconButtonTokens.kt
index afec766..6cc1bc1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/IconButtonTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/IconButtonTokens.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_92
+// VERSION: v0_93
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
 package androidx.compose.material3.tokens
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/OutlinedIconButtonTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/OutlinedIconButtonTokens.kt
index c30f605..cff5ada 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/OutlinedIconButtonTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/OutlinedIconButtonTokens.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_92
+// VERSION: v0_93
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
 package androidx.compose.material3.tokens
@@ -21,7 +21,7 @@
 import androidx.compose.ui.unit.dp
 
 internal object OutlinedIconButtonTokens {
-    val ContainerShape = ShapeTokens.CornerFull
+    val ContainerShape = ShapeKeyTokens.CornerFull
     val ContainerSize = 40.0.dp
     val DisabledColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledOpacity = 0.38f
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphFillBoundingBoxesTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphFillBoundingBoxesTest.kt
index a002f22..512b6e8 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphFillBoundingBoxesTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphFillBoundingBoxesTest.kt
@@ -175,11 +175,19 @@
         ).isEqualToWithTolerance(ltrCharacterBoundariesForTestFont(text))
     }
 
+    @OptIn(ExperimentalTextApi::class)
     @Test
     fun multiLineCharacterLineHeight() {
         val lineHeight = fontSize * 2
         val text = "a\na\na"
-        val paragraph = Paragraph(text, style = TextStyle(lineHeight = lineHeight))
+        @Suppress("DEPRECATION")
+        val paragraph = Paragraph(
+            text,
+            style = TextStyle(
+                lineHeight = lineHeight,
+                platformStyle = PlatformTextStyle(includeFontPadding = false)
+            )
+        )
 
         // first line no line height
         val firstLineEnd = text.indexOf("\n") + 1
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
index 9c9e831..ca63649 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
@@ -2708,6 +2708,7 @@
         }
     }
 
+    @OptIn(ExperimentalTextApi::class)
     @Test
     fun lineHeight_IsNotAppliedToFirstLine() {
         val text = "abcdefgh"
@@ -2716,9 +2717,14 @@
         val layoutWidth = text.length * fontSize / 4
         val lineHeight = 2f
 
+        @Suppress("DEPRECATION")
         val paragraph = simpleParagraph(
             text = text,
-            style = TextStyle(fontSize = fontSize.sp, lineHeight = lineHeight.em),
+            style = TextStyle(
+                fontSize = fontSize.sp,
+                lineHeight = lineHeight.em,
+                platformStyle = PlatformTextStyle(includeFontPadding = false)
+            ),
             width = layoutWidth
         )
 
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
index e58482b..72001ea 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/AndroidTextStyle.android.kt
@@ -18,7 +18,7 @@
 
 package androidx.compose.ui.text
 
-internal const val DefaultIncludeFontPadding = false
+internal const val DefaultIncludeFontPadding = true
 
 /**
  * Provides Android specific [TextStyle] configuration options for styling and compatibility.
diff --git a/datastore/OWNERS b/datastore/OWNERS
index 12a6371..c198e4d 100644
--- a/datastore/OWNERS
+++ b/datastore/OWNERS
@@ -1,5 +1,6 @@
 # Bug component: 907884
 spf@google.com
 rohitsat@google.com
+zhiyuanwang@google.com
 
 per-file settings.gradle = dustinlam@google.com, rahulrav@google.com
diff --git a/datastore/datastore-multiprocess/api/current.txt b/datastore/datastore-multiprocess/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/datastore/datastore-multiprocess/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/datastore/datastore-multiprocess/api/public_plus_experimental_current.txt b/datastore/datastore-multiprocess/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/datastore/datastore-multiprocess/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/health/health-data-client/api/res-current.txt b/datastore/datastore-multiprocess/api/res-current.txt
similarity index 100%
copy from health/health-data-client/api/res-current.txt
copy to datastore/datastore-multiprocess/api/res-current.txt
diff --git a/datastore/datastore-multiprocess/api/restricted_current.txt b/datastore/datastore-multiprocess/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/datastore/datastore-multiprocess/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/datastore/datastore-multiprocess/build.gradle b/datastore/datastore-multiprocess/build.gradle
new file mode 100644
index 0000000..1b5e4313
--- /dev/null
+++ b/datastore/datastore-multiprocess/build.gradle
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    api(libs.kotlinStdlib)
+    api(libs.kotlinCoroutinesCore)
+
+    androidTestImplementation(libs.junit)
+    androidTestImplementation(libs.kotlinCoroutinesTest)
+    androidTestImplementation(libs.truth)
+    androidTestImplementation(project(":internal-testutils-truth"))
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testCore)
+}
+
+android {
+    externalNativeBuild {
+        cmake {
+            path "src/main/cpp/CMakeLists.txt"
+            version libs.versions.cmake.get()
+        }
+    }
+    namespace "androidx.datastore.multiprocess"
+}
+
+androidx {
+    name = "androidx.datastore:datastore-multiprocess"
+    type = LibraryType.PUBLISHED_LIBRARY
+    mavenGroup = LibraryGroups.DATASTORE
+    inceptionYear = "2022"
+    description = "Android DataStore MultiProcess - contains the underlying store used by " +
+            "multiple process use cases"
+}
diff --git a/datastore/datastore-multiprocess/src/androidTest/java/androidx/datastore/multiprocess/SharedCounterTest.kt b/datastore/datastore-multiprocess/src/androidTest/java/androidx/datastore/multiprocess/SharedCounterTest.kt
new file mode 100644
index 0000000..e3d6b20
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/androidTest/java/androidx/datastore/multiprocess/SharedCounterTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.multiprocess
+
+import androidx.test.filters.MediumTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.io.IOException
+import kotlin.collections.MutableSet
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@ExperimentalCoroutinesApi
+@MediumTest
+@RunWith(JUnit4::class)
+class SharedCounterTest {
+
+    companion object {
+        init {
+            SharedCounter.loadLib()
+        }
+    }
+
+    @get:Rule
+    val tempFolder = TemporaryFolder()
+    private lateinit var testFile: File
+
+    @Before
+    fun setup() {
+        testFile = tempFolder.newFile()
+    }
+
+    @Test
+    fun testCreate_success() {
+        val counter: SharedCounter = SharedCounter.create { testFile }
+        assertThat(counter).isNotNull()
+    }
+
+    @Test
+    fun testCreate_failure() {
+        val tempFile = tempFolder.newFile()
+        tempFile.setReadable(false)
+        assertThrows(IOException::class.java) {
+            SharedCounter.create {
+                tempFile
+            }
+        }
+    }
+
+    @Test
+    fun testGetValue() {
+        val counter: SharedCounter = SharedCounter.create { testFile }
+        assertThat(counter.getValue()).isEqualTo(0)
+    }
+
+    @Test
+    fun testIncrementAndGet() {
+        val counter: SharedCounter = SharedCounter.create { testFile }
+        for (count in 1..100) {
+            assertThat(counter.incrementAndGetValue()).isEqualTo(count)
+        }
+    }
+
+    @Test
+    fun testIncrementInParallel() = runTest {
+        val counter: SharedCounter = SharedCounter.create { testFile }
+        val valueToAdd = 100
+        val numCoroutines = 10
+        val numbers: MutableSet<Int> = mutableSetOf()
+        val deferred = async {
+            repeat(numCoroutines) {
+                launch {
+                    repeat(valueToAdd) {
+                        assertThat(numbers.add(counter.incrementAndGetValue())).isTrue()
+                    }
+                }
+            }
+        }
+        deferred.await()
+        assertThat(counter.getValue()).isEqualTo(numCoroutines * valueToAdd)
+        for (num in 1..(numCoroutines * valueToAdd)) {
+            assertThat(numbers).contains(num)
+        }
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/AndroidManifest.xml b/datastore/datastore-multiprocess/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2aeafa4
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.datastore.multiprocess">
+
+</manifest>
diff --git a/datastore/datastore-multiprocess/src/main/cpp/CMakeLists.txt b/datastore/datastore-multiprocess/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..cee8f56
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+
+cmake_minimum_required(VERSION 3.22)
+
+project(datastore_shared_counter)
+
+set (CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
+
+add_library(shared_counter STATIC shared_counter.cc)
+add_library(datastore_shared_counter SHARED jni/androidx_datastore_multiprocess_SharedCounter.cc)
+
+target_link_libraries(datastore_shared_counter shared_counter)
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/cpp/jni/androidx_datastore_multiprocess_SharedCounter.cc b/datastore/datastore-multiprocess/src/main/cpp/jni/androidx_datastore_multiprocess_SharedCounter.cc
new file mode 100644
index 0000000..892157e
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/cpp/jni/androidx_datastore_multiprocess_SharedCounter.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstring>
+#include <jni.h>
+#include "../shared_counter.h"
+
+static_assert(sizeof(jlong) >= sizeof(volatile std::atomic<uint32_t>*),
+              "jlong not large enough for pointer");
+
+jint ThrowIoException(JNIEnv* env, const char* message) {
+  jclass ioExceptionClass = env->FindClass("java/io/IOException");
+  if (ioExceptionClass == nullptr) {
+    // We couldn't find the IOException class to throw. We can special case -1
+    // kotlin side in case this happens.
+    return -1;
+  }
+
+  return env->ThrowNew(ioExceptionClass, message);
+}
+
+extern "C" {
+
+JNIEXPORT jlong JNICALL
+Java_androidx_datastore_multiprocess_NativeSharedCounter_nativeCreateSharedCounter(
+        JNIEnv *env, jclass clazz, jint fd) {
+    void* address = nullptr;
+    if (int errNum = datastore::CreateSharedCounter(fd, &address)) {
+        return ThrowIoException(env, strerror(errNum));
+    }
+    return reinterpret_cast<jlong>(address);
+}
+
+JNIEXPORT jint JNICALL
+Java_androidx_datastore_multiprocess_NativeSharedCounter_nativeGetCounterValue(
+        JNIEnv *env, jclass clazz, jlong address) {
+    return static_cast<jint>(
+        datastore::GetCounterValue(reinterpret_cast<std::atomic<uint32_t>*>(address)));
+}
+
+JNIEXPORT jint JNICALL
+Java_androidx_datastore_multiprocess_NativeSharedCounter_nativeIncrementAndGetCounterValue(
+        JNIEnv *env, jclass clazz, jlong address) {
+    return static_cast<jint>(
+        datastore::IncrementAndGetCounterValue(reinterpret_cast<std::atomic<uint32_t>*>(address)));
+}
+
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/cpp/shared_counter.cc b/datastore/datastore-multiprocess/src/main/cpp/shared_counter.cc
new file mode 100644
index 0000000..9dcf9da
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/cpp/shared_counter.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cstdint>
+#include <functional>
+
+#include "shared_counter.h"
+
+namespace {
+constexpr int NUM_BYTES = 4;
+} // namespace
+
+// Allocate 4 bytes from mmap to be used as an atomic integer.
+static_assert(sizeof(std::atomic<uint32_t>) == NUM_BYTES,
+              "Unexpected atomic<uint32_t> size");
+// Atomics are safe to use across processes as they are lock free, because atomic operations on
+// the same memory location via two different addresses will communicate atomically. See more
+// details at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html#DiscussLockFree
+static_assert(std::atomic<uint32_t>::is_always_lock_free == true,
+              "atomic<uint32_t> is not always lock free");
+
+namespace datastore {
+
+/*
+ * This function returns non-zero errno if fails to create the counter. Caller should use
+ * "strerror(errno)" to get error message.
+ */
+int CreateSharedCounter(int fd, void** counter_address) {
+    if (ftruncate(fd, NUM_BYTES) != 0) {
+      return errno;
+    }
+    void* mmap_result = mmap(nullptr, NUM_BYTES, PROT_READ | PROT_WRITE,
+                           MAP_SHARED | MAP_LOCKED, fd, 0);
+
+    if (mmap_result == MAP_FAILED) {
+        return errno;
+    }
+    *counter_address = mmap_result;
+    return 0;
+}
+
+uint32_t GetCounterValue(std::atomic<uint32_t>* address) {
+    auto counter_atomic =
+        reinterpret_cast<volatile std::atomic<uint32_t>*>(address);
+
+    // Note: this read will not be protected by a lock, but is safe since the read is atomic.
+    return counter_atomic->load();
+}
+
+uint32_t IncrementAndGetCounterValue(std::atomic<uint32_t>* address) {
+    // Since other processes may change the value, it's also marked volatile.
+    auto counter_atomic =
+        reinterpret_cast<volatile std::atomic<uint32_t>*>(address);
+
+    // Note: this increment is protected by an exclusive file lock, though the
+    // lock isn't required since the counter is atomic.
+    return counter_atomic->fetch_add(1) + 1;
+}
+} // namespace datastore
\ No newline at end of file
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt b/datastore/datastore-multiprocess/src/main/cpp/shared_counter.h
similarity index 61%
copy from health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
copy to datastore/datastore-multiprocess/src/main/cpp/shared_counter.h
index aa65dc9..756e2fe 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
+++ b/datastore/datastore-multiprocess/src/main/cpp/shared_counter.h
@@ -13,13 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
 
-/**
- * Abstraction to represent a change to Android Health Platform.
- *
- * @see androidx.health.data.client.response.ChangesResponse
- * @see UpsertionChange
- * @see DeletionChange
- */
-interface Change
+#include <atomic>
+#include <cstdint>
+
+#ifndef DATASTORE_SHARED_COUNTER_H
+#define DATASTORE_SHARED_COUNTER_H
+
+namespace datastore {
+int CreateSharedCounter(int fd, void** counter_address);
+uint32_t GetCounterValue(std::atomic<uint32_t>* counter);
+uint32_t IncrementAndGetCounterValue(std::atomic<uint32_t>* counter);
+} // namespace datastore
+
+#endif // DATASTORE_SHARED_COUNTER_H
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/SharedCounter.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/SharedCounter.kt
new file mode 100644
index 0000000..eb64a3c
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/SharedCounter.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.multiprocess
+
+import android.annotation.SuppressLint
+import android.os.ParcelFileDescriptor
+import java.io.File
+import java.io.IOException
+
+/**
+ * Put the JNI methods in a separate class to make them internal to the package.
+ */
+internal class NativeSharedCounter {
+    external fun nativeCreateSharedCounter(fd: Int): Long
+    external fun nativeGetCounterValue(address: Long): Int
+    external fun nativeIncrementAndGetCounterValue(address: Long): Int
+}
+
+/**
+ * An atomic counter implemented by shared memory, which could be used by multi-process DataStore as
+ * an atomic version counter. The underlying JNI library would be pre-compiled and shipped as part
+ * of the `datastore-multiprocess` AAR artifact, users don't need extra steps other than adding it
+ * as dependency.
+ */
+internal class SharedCounter private constructor(
+    /**
+     * The memory address to be mapped.
+     */
+    private val mappedAddress: Long
+) {
+
+    fun getValue(): Int {
+        return nativeSharedCounter.nativeGetCounterValue(mappedAddress)
+    }
+
+    fun incrementAndGetValue(): Int {
+        return nativeSharedCounter.nativeIncrementAndGetCounterValue(mappedAddress)
+    }
+
+    companion object Factory {
+        internal val nativeSharedCounter = NativeSharedCounter()
+
+        fun loadLib() = System.loadLibrary("datastore_shared_counter")
+
+        @SuppressLint("SyntheticAccessor")
+        private fun createCounterFromFd(pfd: ParcelFileDescriptor): SharedCounter {
+            val nativeFd = pfd.getFd()
+            val address = nativeSharedCounter.nativeCreateSharedCounter(nativeFd)
+            if (address < 0) {
+                throw IOException("Failed to mmap or truncate counter file")
+            }
+            return SharedCounter(address)
+        }
+
+        internal fun create(produceFile: () -> File): SharedCounter {
+            val file = produceFile()
+            return ParcelFileDescriptor.open(
+                file,
+                ParcelFileDescriptor.MODE_READ_WRITE or ParcelFileDescriptor.MODE_CREATE
+            ).use {
+                createCounterFromFd(it)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 135facb..7a9ccff 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -117,6 +117,7 @@
     docs(project(":customview:customview-poolingcontainer"))
     docs(project(":datastore:datastore"))
     docs(project(":datastore:datastore-core"))
+    docs(project(":datastore:datastore-multiprocess"))
     docs(project(":datastore:datastore-preferences"))
     docs(project(":datastore:datastore-preferences-core"))
     docs(project(":datastore:datastore-preferences-proto"))
@@ -147,7 +148,7 @@
     docs(project(":glance:glance-appwidget"))
     docs(project(":glance:glance-wear-tiles"))
     docs(project(":gridlayout:gridlayout"))
-    docs(project(":health:health-data-client"))
+    docs(project(":health:health-connect-client"))
     docs(project(":health:health-services-client"))
     docs(project(":heifwriter:heifwriter"))
     docs(project(":hilt:hilt-common"))
diff --git a/fragment/fragment/api/1.5.0-beta01.txt b/fragment/fragment/api/1.5.0-beta01.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/1.5.0-beta01.txt
+++ b/fragment/fragment/api/1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt b/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
+++ b/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/restricted_1.5.0-beta01.txt b/fragment/fragment/api/restricted_1.5.0-beta01.txt
index 9e7cc35..7f0aa7c 100644
--- a/fragment/fragment/api/restricted_1.5.0-beta01.txt
+++ b/fragment/fragment/api/restricted_1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 9e7cc35..7f0aa7c 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
index c582362..8ae92e1 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
@@ -66,6 +66,12 @@
     }
 }
 
+object FragmentDismissNow : Operation() {
+    override fun run(dialogFragment: DialogFragment) {
+        dialogFragment.dismissNow()
+    }
+}
+
 @LargeTest
 @RunWith(Parameterized::class)
 class DialogFragmentDismissTest(
@@ -87,6 +93,8 @@
                 // Run the operation off the main thread
                 add(arrayOf(operation, false))
             }
+            // dismissNow can only be run on the main thread
+            add(arrayOf(FragmentDismissNow, true))
         }
     }
 
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
index 92ec098..dfd3fbc 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
@@ -113,6 +113,27 @@
 
     @UiThreadTest
     @Test
+    fun testDialogFragmentDismissNow() {
+        val fragment = TestDialogFragment()
+        fragment.show(activityTestRule.activity.supportFragmentManager, null)
+        activityTestRule.runOnUiThread {
+            activityTestRule.activity.supportFragmentManager.executePendingTransactions()
+        }
+
+        val dialog = fragment.dialog
+        assertWithMessage("Dialog was not being shown")
+            .that(dialog?.isShowing)
+            .isTrue()
+
+        fragment.dismissNow()
+
+        assertWithMessage("Dialog should be removed")
+            .that(dialog?.isShowing)
+            .isFalse()
+    }
+
+    @UiThreadTest
+    @Test
     fun testDialogFragmentDismissAllowingStateLoss() {
         val viewModelStore = ViewModelStore()
         val fc = activityTestRule.startupFragmentController(viewModelStore)
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
index 1477da4..7cf9874 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
@@ -307,7 +307,16 @@
      * the fragment.
      */
     public void dismiss() {
-        dismissInternal(false, false);
+        dismissInternal(false, false, false);
+    }
+
+    /**
+     * Version of {@link #dismiss()} that uses {@link FragmentTransaction#commitNow()}.
+     * See linked documentation for further details.
+     */
+    @MainThread
+    public void dismissNow() {
+        dismissInternal(false, false, true);
     }
 
     /**
@@ -317,10 +326,10 @@
      * documentation for further details.
      */
     public void dismissAllowingStateLoss() {
-        dismissInternal(true, false);
+        dismissInternal(true, false, false);
     }
 
-    private void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss) {
+    private void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss, boolean immediate) {
         if (mDismissed) {
             return;
         }
@@ -346,14 +355,22 @@
         }
         mViewDestroyed = true;
         if (mBackStackId >= 0) {
-            getParentFragmentManager().popBackStack(mBackStackId,
-                    FragmentManager.POP_BACK_STACK_INCLUSIVE, allowStateLoss);
+            if (immediate) {
+                getParentFragmentManager().popBackStackImmediate(mBackStackId,
+                        FragmentManager.POP_BACK_STACK_INCLUSIVE);
+            } else {
+                getParentFragmentManager().popBackStack(mBackStackId,
+                        FragmentManager.POP_BACK_STACK_INCLUSIVE, allowStateLoss);
+            }
             mBackStackId = -1;
         } else {
             FragmentTransaction ft = getParentFragmentManager().beginTransaction();
             ft.setReorderingAllowed(true);
             ft.remove(this);
-            if (allowStateLoss) {
+            // allowStateLoss and immediate should not both be true
+            if (immediate) {
+                ft.commitNow();
+            } else if (allowStateLoss) {
                 ft.commitAllowingStateLoss();
             } else {
                 ft.commit();
@@ -633,7 +650,7 @@
             if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                 Log.d(TAG, "onDismiss called for DialogFragment " + this);
             }
-            dismissInternal(true, true);
+            dismissInternal(true, true, false);
         }
     }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 5c424fe..f598eae 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -105,6 +105,8 @@
  */
 public abstract class FragmentManager implements FragmentResultOwner {
     static final String SAVED_STATE_TAG = "android:support:fragments";
+    static final String FRAGMENT_MANAGER_STATE_TAG = "state";
+    static final String RESULT_NAME_PREFIX = "result_";
     private static boolean DEBUG = false;
 
     /** @hide */
@@ -2347,10 +2349,13 @@
             throwException(new IllegalStateException("You cannot use saveAllState when your "
                     + "FragmentHostCallback implements SavedStateRegistryOwner."));
         }
-        return saveAllStateInternal();
+        Bundle savedState = saveAllStateInternal();
+        return savedState.isEmpty() ? null : savedState;
     }
 
-    Parcelable saveAllStateInternal() {
+    @NonNull
+    Bundle saveAllStateInternal() {
+        Bundle bundle = new Bundle();
         // Make sure all pending operations have now been executed to get
         // our state update-to-date.
         forcePostponedTransactions();
@@ -2365,46 +2370,50 @@
 
         // And grab all FragmentState objects
         ArrayList<FragmentState> savedState = mFragmentStore.getAllSavedState();
-
         if (savedState.isEmpty()) {
-            if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "saveAllState: no fragments!");
-            return null;
-        }
+            if (isLoggingEnabled(Log.VERBOSE)) {
+                Log.v(TAG, "saveAllState: no fragments!");
+            }
+        } else {
+            // Build list of currently added fragments.
+            ArrayList<String> added = mFragmentStore.saveAddedFragments();
 
-        // Build list of currently added fragments.
-        ArrayList<String> added = mFragmentStore.saveAddedFragments();
-
-        // Now save back stack.
-        BackStackRecordState[] backStack = null;
-        if (mBackStack != null) {
-            int size = mBackStack.size();
-            if (size > 0) {
-                backStack = new BackStackRecordState[size];
-                for (int i = 0; i < size; i++) {
-                    backStack[i] = new BackStackRecordState(mBackStack.get(i));
-                    if (isLoggingEnabled(Log.VERBOSE)) {
-                        Log.v(TAG, "saveAllState: adding back stack #" + i
-                                + ": " + mBackStack.get(i));
+            // Now save back stack.
+            BackStackRecordState[] backStack = null;
+            if (mBackStack != null) {
+                int size = mBackStack.size();
+                if (size > 0) {
+                    backStack = new BackStackRecordState[size];
+                    for (int i = 0; i < size; i++) {
+                        backStack[i] = new BackStackRecordState(mBackStack.get(i));
+                        if (isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(TAG, "saveAllState: adding back stack #" + i
+                                    + ": " + mBackStack.get(i));
+                        }
                     }
                 }
             }
+
+            FragmentManagerState fms = new FragmentManagerState();
+            fms.mSavedState = savedState;
+            fms.mActive = active;
+            fms.mAdded = added;
+            fms.mBackStack = backStack;
+            fms.mBackStackIndex = mBackStackIndex.get();
+            if (mPrimaryNav != null) {
+                fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
+            }
+            fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
+            fms.mBackStackStates.addAll(mBackStackStates.values());
+            fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
+            bundle.putParcelable(FRAGMENT_MANAGER_STATE_TAG, fms);
+
+            for (String resultName : mResults.keySet()) {
+                bundle.putBundle(RESULT_NAME_PREFIX + resultName, mResults.get(resultName));
+            }
         }
 
-        FragmentManagerState fms = new FragmentManagerState();
-        fms.mSavedState = savedState;
-        fms.mActive = active;
-        fms.mAdded = added;
-        fms.mBackStack = backStack;
-        fms.mBackStackIndex = mBackStackIndex.get();
-        if (mPrimaryNav != null) {
-            fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
-        }
-        fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
-        fms.mBackStackStates.addAll(mBackStackStates.values());
-        fms.mResultKeys.addAll(mResults.keySet());
-        fms.mResults.addAll(mResults.values());
-        fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
-        return fms;
+        return bundle;
     }
 
     @SuppressWarnings("deprecation")
@@ -2425,11 +2434,25 @@
         restoreSaveStateInternal(state);
     }
 
+    @SuppressWarnings("deprecation")
     void restoreSaveStateInternal(@Nullable Parcelable state) {
         // If there is no saved state at all, then there's nothing else to do
         if (state == null) return;
-        FragmentManagerState fms = (FragmentManagerState) state;
-        if (fms.mSavedState == null) return;
+        Bundle bundle = (Bundle) state;
+
+        for (String bundleKey : bundle.keySet()) {
+            if (bundleKey.startsWith(RESULT_NAME_PREFIX)) {
+                Bundle savedResult = bundle.getBundle(bundleKey);
+                if (savedResult != null) {
+                    savedResult.setClassLoader(mHost.getContext().getClassLoader());
+                    String resultKey = bundleKey.substring(RESULT_NAME_PREFIX.length());
+                    mResults.put(resultKey, savedResult);
+                }
+            }
+        }
+
+        FragmentManagerState fms = bundle.getParcelable(FRAGMENT_MANAGER_STATE_TAG);
+        if (fms == null || fms.mSavedState == null) return;
 
         // Restore the saved state of all fragments
         mFragmentStore.restoreSaveState(fms.mSavedState);
@@ -2526,14 +2549,6 @@
             }
         }
 
-        ArrayList<String> savedResultKeys = fms.mResultKeys;
-        if (savedResultKeys != null) {
-            for (int i = 0; i < savedResultKeys.size(); i++) {
-                Bundle savedResult = fms.mResults.get(i);
-                savedResult.setClassLoader(mHost.getContext().getClassLoader());
-                mResults.put(savedResultKeys.get(i), savedResult);
-            }
-        }
         mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
     }
 
@@ -2614,20 +2629,14 @@
             SavedStateRegistry registry =
                     ((SavedStateRegistryOwner) mHost).getSavedStateRegistry();
             registry.registerSavedStateProvider(SAVED_STATE_TAG, () -> {
-                        Bundle outState = new Bundle();
-                        Parcelable p = saveAllStateInternal();
-                        if (p != null) {
-                            outState.putParcelable(SAVED_STATE_TAG, p);
-                        }
-                        return outState;
+                        return saveAllStateInternal();
                     }
             );
 
             Bundle savedInstanceState = registry
                     .consumeRestoredStateForKey(SAVED_STATE_TAG);
             if (savedInstanceState != null) {
-                Parcelable p = savedInstanceState.getParcelable(SAVED_STATE_TAG);
-                restoreSaveStateInternal(p);
+                restoreSaveStateInternal(savedInstanceState);
             }
         }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
index a90909a..117e31c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
@@ -17,7 +17,6 @@
 package androidx.fragment.app;
 
 import android.annotation.SuppressLint;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -33,8 +32,6 @@
     String mPrimaryNavActiveWho = null;
     ArrayList<String> mBackStackStateKeys = new ArrayList<>();
     ArrayList<BackStackState> mBackStackStates = new ArrayList<>();
-    ArrayList<String> mResultKeys = new ArrayList<>();
-    ArrayList<Bundle> mResults = new ArrayList<>();
     ArrayList<FragmentManager.LaunchedFragmentInfo> mLaunchedFragments;
 
     public FragmentManagerState() {
@@ -49,8 +46,6 @@
         mPrimaryNavActiveWho = in.readString();
         mBackStackStateKeys = in.createStringArrayList();
         mBackStackStates = in.createTypedArrayList(BackStackState.CREATOR);
-        mResultKeys = in.createStringArrayList();
-        mResults = in.createTypedArrayList(Bundle.CREATOR);
         mLaunchedFragments = in.createTypedArrayList(FragmentManager.LaunchedFragmentInfo.CREATOR);
     }
 
@@ -69,8 +64,6 @@
         dest.writeString(mPrimaryNavActiveWho);
         dest.writeStringList(mBackStackStateKeys);
         dest.writeTypedList(mBackStackStates);
-        dest.writeStringList(mResultKeys);
-        dest.writeTypedList(mResults);
         dest.writeTypedList(mLaunchedFragments);
     }
 
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index f426772..431a244 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -13,6 +13,7 @@
          <trust group="^com[.]android($|([.].*))" regex="true"/> <!-- b/215430394 -->
          <trust group="com.google.testing.platform"/> <!-- b/215430394 -->
          <trust group="com.google.android.gms"/> <!-- b/215442095 -->
+         <trust file=".*kotlin-native-prebuilt-macos-.*" regex="true"/> <!-- b/228184608 -->
       </trusted-artifacts>
       <trusted-keys>
          <trusted-key id="00089ee8c3afa95a854d0f1df800dd0933ecf7f7" group="com.google.guava" name="guava"/>
diff --git a/health/health-data-client/OWNERS b/health/health-connect-client/OWNERS
similarity index 100%
rename from health/health-data-client/OWNERS
rename to health/health-connect-client/OWNERS
diff --git a/health/health-data-client/api/current.txt b/health/health-connect-client/api/current.txt
similarity index 65%
rename from health/health-data-client/api/current.txt
rename to health/health-connect-client/api/current.txt
index d8d0caf..aea504e 100644
--- a/health/health-data-client/api/current.txt
+++ b/health/health-connect-client/api/current.txt
@@ -1,46 +1,46 @@
 // Signature format: 4.0
-package androidx.health.data.client {
+package androidx.health.connect.client {
 
-  public interface HealthDataClient {
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, androidx.health.data.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.ChangesResponse>);
-    method public suspend Object? getChangesToken(androidx.health.data.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
-    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse>);
+  public interface HealthConnectClient {
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, androidx.health.connect.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ChangesResponse>);
+    method public suspend Object? getChangesToken(androidx.health.connect.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method public default static boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public default static boolean isAvailable(android.content.Context context);
-    field public static final androidx.health.data.client.HealthDataClient.Companion Companion;
+    field public static final androidx.health.connect.client.HealthConnectClient.Companion Companion;
   }
 
-  public static final class HealthDataClient.Companion {
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
+  public static final class HealthConnectClient.Companion {
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public boolean isAvailable(android.content.Context context);
   }
 
 }
 
-package androidx.health.data.client.changes {
+package androidx.health.connect.client.changes {
 
   public interface Change {
   }
 
-  public final class DeletionChange implements androidx.health.data.client.changes.Change {
+  public final class DeletionChange implements androidx.health.connect.client.changes.Change {
     method public String getDeletedUid();
     property public final String deletedUid;
   }
 
-  public final class UpsertionChange implements androidx.health.data.client.changes.Change {
-    method public androidx.health.data.client.records.Record getRecord();
-    property public final androidx.health.data.client.records.Record record;
+  public final class UpsertionChange implements androidx.health.connect.client.changes.Change {
+    method public androidx.health.connect.client.records.Record getRecord();
+    property public final androidx.health.connect.client.records.Record record;
   }
 
 }
 
-package androidx.health.data.client.metadata {
+package androidx.health.connect.client.metadata {
 
   public final class DataOrigin {
     ctor public DataOrigin(String packageName);
@@ -64,7 +64,7 @@
     field public static final String CHEST_STRAP = "CHEST_STRAP";
     field public static final String FITNESS_BAND = "FITNESS_BAND";
     field public static final String HEAD_MOUNTED = "HEAD_MOUNTED";
-    field public static final androidx.health.data.client.metadata.DeviceTypes INSTANCE;
+    field public static final androidx.health.connect.client.metadata.DeviceTypes INSTANCE;
     field public static final String PHONE = "PHONE";
     field public static final String RING = "RING";
     field public static final String SCALE = "SCALE";
@@ -74,24 +74,24 @@
   }
 
   public final class Metadata {
-    ctor public Metadata(optional String? uid, optional androidx.health.data.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.data.client.metadata.Device? device);
+    ctor public Metadata(optional String? uid, optional androidx.health.connect.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.connect.client.metadata.Device? device);
     method public String? getClientId();
     method public long getClientVersion();
-    method public androidx.health.data.client.metadata.DataOrigin getDataOrigin();
-    method public androidx.health.data.client.metadata.Device? getDevice();
+    method public androidx.health.connect.client.metadata.DataOrigin getDataOrigin();
+    method public androidx.health.connect.client.metadata.Device? getDevice();
     method public java.time.Instant getLastModifiedTime();
     method public String? getUid();
     property public final String? clientId;
     property public final long clientVersion;
-    property public final androidx.health.data.client.metadata.DataOrigin dataOrigin;
-    property public final androidx.health.data.client.metadata.Device? device;
+    property public final androidx.health.connect.client.metadata.DataOrigin dataOrigin;
+    property public final androidx.health.connect.client.metadata.Device? device;
     property public final java.time.Instant lastModifiedTime;
     property public final String? uid;
   }
 
 }
 
-package androidx.health.data.client.records {
+package androidx.health.connect.client.records {
 
   public final class ActivityTypes {
     field public static final String BACK_EXTENSION = "back_extension";
@@ -133,7 +133,7 @@
     field public static final String HIKING = "hiking";
     field public static final String ICE_HOCKEY = "ice_hockey";
     field public static final String ICE_SKATING = "ice_skating";
-    field public static final androidx.health.data.client.records.ActivityTypes INSTANCE;
+    field public static final androidx.health.connect.client.records.ActivityTypes INSTANCE;
     field public static final String JUMPING_JACK = "jumping_jack";
     field public static final String JUMP_ROPE = "jump_rope";
     field public static final String LAT_PULL_DOWN = "lat_pull_down";
@@ -181,7 +181,7 @@
   }
 
   public final class BloodPressureMeasurementLocations {
-    field public static final androidx.health.data.client.records.BloodPressureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BloodPressureMeasurementLocations INSTANCE;
     field public static final String LEFT_UPPER_ARM = "left_upper_arm";
     field public static final String LEFT_WRIST = "left_wrist";
     field public static final String RIGHT_UPPER_ARM = "right_upper_arm";
@@ -189,22 +189,22 @@
   }
 
   public final class BodyPositions {
-    field public static final androidx.health.data.client.records.BodyPositions INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyPositions INSTANCE;
     field public static final String LYING_DOWN = "lying_down";
     field public static final String RECLINING = "reclining";
     field public static final String SITTING_DOWN = "sitting_down";
     field public static final String STANDING_UP = "standing_up";
   }
 
-  public final class BodyTemperature implements androidx.health.data.client.records.Record {
-    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class BodyTemperature implements androidx.health.connect.client.records.Record {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public double getTemperatureDegreesCelsius();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public final double temperatureDegreesCelsius;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
@@ -215,7 +215,7 @@
     field public static final String EAR = "ear";
     field public static final String FINGER = "finger";
     field public static final String FOREHEAD = "forehead";
-    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyTemperatureMeasurementLocations INSTANCE;
     field public static final String MOUTH = "mouth";
     field public static final String RECTUM = "rectum";
     field public static final String TEMPORAL_ARTERY = "temporal_artery";
@@ -224,96 +224,96 @@
     field public static final String WRIST = "wrist";
   }
 
-  public final class Distance implements androidx.health.data.client.records.Record {
-    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Distance implements androidx.health.connect.client.records.Record {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getDistanceMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double distanceMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class ElevationGained implements androidx.health.data.client.records.Record {
-    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class ElevationGained implements androidx.health.connect.client.records.Record {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getElevationMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double elevationMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Height implements androidx.health.data.client.records.Record {
-    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Height implements androidx.health.connect.client.records.Record {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getHeightMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double heightMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
-  public final class HipCircumference implements androidx.health.data.client.records.Record {
-    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class HipCircumference implements androidx.health.connect.client.records.Record {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getCircumferenceMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double circumferenceMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
   public final class OvulationTestResults {
-    field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
+    field public static final androidx.health.connect.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
     field public static final String POSITIVE = "positive";
   }
 
   public interface Record {
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.connect.client.metadata.Metadata metadata;
   }
 
-  public final class Steps implements androidx.health.data.client.records.Record {
-    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Steps implements androidx.health.connect.client.records.Record {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public long getCount();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final long count;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Weight implements androidx.health.data.client.records.Record {
-    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+  public final class Weight implements androidx.health.connect.client.records.Record {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public double getWeightKg();
     method public java.time.ZoneOffset? getZoneOffset();
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public final double weightKg;
     property public java.time.ZoneOffset? zoneOffset;
@@ -321,22 +321,22 @@
 
 }
 
-package androidx.health.data.client.request {
+package androidx.health.connect.client.request {
 
   public final class ChangesTokenRequest {
-    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.data.client.metadata.DataOrigin> dataOriginFilters);
+    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.connect.client.metadata.DataOrigin> dataOriginFilters);
   }
 
 }
 
-package androidx.health.data.client.response {
+package androidx.health.connect.client.response {
 
   public final class ChangesResponse {
-    method public java.util.List<androidx.health.data.client.changes.Change> getChanges();
+    method public java.util.List<androidx.health.connect.client.changes.Change> getChanges();
     method public boolean getChangesTokenExpired();
     method public boolean getHasMore();
     method public String getNextChangesToken();
-    property public final java.util.List<androidx.health.data.client.changes.Change> changes;
+    property public final java.util.List<androidx.health.connect.client.changes.Change> changes;
     property public final boolean changesTokenExpired;
     property public final boolean hasMore;
     property public final String nextChangesToken;
@@ -349,25 +349,25 @@
 
 }
 
-package androidx.health.data.client.time {
+package androidx.health.connect.client.time {
 
   public final class TimeRangeFilter {
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
-    field public static final androidx.health.data.client.time.TimeRangeFilter.Companion Companion;
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    field public static final androidx.health.connect.client.time.TimeRangeFilter.Companion Companion;
   }
 
   public static final class TimeRangeFilter.Companion {
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
   }
 
 }
diff --git a/health/health-data-client/api/current.txt b/health/health-connect-client/api/public_plus_experimental_current.txt
similarity index 65%
copy from health/health-data-client/api/current.txt
copy to health/health-connect-client/api/public_plus_experimental_current.txt
index d8d0caf..aea504e 100644
--- a/health/health-data-client/api/current.txt
+++ b/health/health-connect-client/api/public_plus_experimental_current.txt
@@ -1,46 +1,46 @@
 // Signature format: 4.0
-package androidx.health.data.client {
+package androidx.health.connect.client {
 
-  public interface HealthDataClient {
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, androidx.health.data.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.ChangesResponse>);
-    method public suspend Object? getChangesToken(androidx.health.data.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
-    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse>);
+  public interface HealthConnectClient {
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, androidx.health.connect.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ChangesResponse>);
+    method public suspend Object? getChangesToken(androidx.health.connect.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method public default static boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public default static boolean isAvailable(android.content.Context context);
-    field public static final androidx.health.data.client.HealthDataClient.Companion Companion;
+    field public static final androidx.health.connect.client.HealthConnectClient.Companion Companion;
   }
 
-  public static final class HealthDataClient.Companion {
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
+  public static final class HealthConnectClient.Companion {
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public boolean isAvailable(android.content.Context context);
   }
 
 }
 
-package androidx.health.data.client.changes {
+package androidx.health.connect.client.changes {
 
   public interface Change {
   }
 
-  public final class DeletionChange implements androidx.health.data.client.changes.Change {
+  public final class DeletionChange implements androidx.health.connect.client.changes.Change {
     method public String getDeletedUid();
     property public final String deletedUid;
   }
 
-  public final class UpsertionChange implements androidx.health.data.client.changes.Change {
-    method public androidx.health.data.client.records.Record getRecord();
-    property public final androidx.health.data.client.records.Record record;
+  public final class UpsertionChange implements androidx.health.connect.client.changes.Change {
+    method public androidx.health.connect.client.records.Record getRecord();
+    property public final androidx.health.connect.client.records.Record record;
   }
 
 }
 
-package androidx.health.data.client.metadata {
+package androidx.health.connect.client.metadata {
 
   public final class DataOrigin {
     ctor public DataOrigin(String packageName);
@@ -64,7 +64,7 @@
     field public static final String CHEST_STRAP = "CHEST_STRAP";
     field public static final String FITNESS_BAND = "FITNESS_BAND";
     field public static final String HEAD_MOUNTED = "HEAD_MOUNTED";
-    field public static final androidx.health.data.client.metadata.DeviceTypes INSTANCE;
+    field public static final androidx.health.connect.client.metadata.DeviceTypes INSTANCE;
     field public static final String PHONE = "PHONE";
     field public static final String RING = "RING";
     field public static final String SCALE = "SCALE";
@@ -74,24 +74,24 @@
   }
 
   public final class Metadata {
-    ctor public Metadata(optional String? uid, optional androidx.health.data.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.data.client.metadata.Device? device);
+    ctor public Metadata(optional String? uid, optional androidx.health.connect.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.connect.client.metadata.Device? device);
     method public String? getClientId();
     method public long getClientVersion();
-    method public androidx.health.data.client.metadata.DataOrigin getDataOrigin();
-    method public androidx.health.data.client.metadata.Device? getDevice();
+    method public androidx.health.connect.client.metadata.DataOrigin getDataOrigin();
+    method public androidx.health.connect.client.metadata.Device? getDevice();
     method public java.time.Instant getLastModifiedTime();
     method public String? getUid();
     property public final String? clientId;
     property public final long clientVersion;
-    property public final androidx.health.data.client.metadata.DataOrigin dataOrigin;
-    property public final androidx.health.data.client.metadata.Device? device;
+    property public final androidx.health.connect.client.metadata.DataOrigin dataOrigin;
+    property public final androidx.health.connect.client.metadata.Device? device;
     property public final java.time.Instant lastModifiedTime;
     property public final String? uid;
   }
 
 }
 
-package androidx.health.data.client.records {
+package androidx.health.connect.client.records {
 
   public final class ActivityTypes {
     field public static final String BACK_EXTENSION = "back_extension";
@@ -133,7 +133,7 @@
     field public static final String HIKING = "hiking";
     field public static final String ICE_HOCKEY = "ice_hockey";
     field public static final String ICE_SKATING = "ice_skating";
-    field public static final androidx.health.data.client.records.ActivityTypes INSTANCE;
+    field public static final androidx.health.connect.client.records.ActivityTypes INSTANCE;
     field public static final String JUMPING_JACK = "jumping_jack";
     field public static final String JUMP_ROPE = "jump_rope";
     field public static final String LAT_PULL_DOWN = "lat_pull_down";
@@ -181,7 +181,7 @@
   }
 
   public final class BloodPressureMeasurementLocations {
-    field public static final androidx.health.data.client.records.BloodPressureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BloodPressureMeasurementLocations INSTANCE;
     field public static final String LEFT_UPPER_ARM = "left_upper_arm";
     field public static final String LEFT_WRIST = "left_wrist";
     field public static final String RIGHT_UPPER_ARM = "right_upper_arm";
@@ -189,22 +189,22 @@
   }
 
   public final class BodyPositions {
-    field public static final androidx.health.data.client.records.BodyPositions INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyPositions INSTANCE;
     field public static final String LYING_DOWN = "lying_down";
     field public static final String RECLINING = "reclining";
     field public static final String SITTING_DOWN = "sitting_down";
     field public static final String STANDING_UP = "standing_up";
   }
 
-  public final class BodyTemperature implements androidx.health.data.client.records.Record {
-    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class BodyTemperature implements androidx.health.connect.client.records.Record {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public double getTemperatureDegreesCelsius();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public final double temperatureDegreesCelsius;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
@@ -215,7 +215,7 @@
     field public static final String EAR = "ear";
     field public static final String FINGER = "finger";
     field public static final String FOREHEAD = "forehead";
-    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyTemperatureMeasurementLocations INSTANCE;
     field public static final String MOUTH = "mouth";
     field public static final String RECTUM = "rectum";
     field public static final String TEMPORAL_ARTERY = "temporal_artery";
@@ -224,96 +224,96 @@
     field public static final String WRIST = "wrist";
   }
 
-  public final class Distance implements androidx.health.data.client.records.Record {
-    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Distance implements androidx.health.connect.client.records.Record {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getDistanceMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double distanceMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class ElevationGained implements androidx.health.data.client.records.Record {
-    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class ElevationGained implements androidx.health.connect.client.records.Record {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getElevationMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double elevationMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Height implements androidx.health.data.client.records.Record {
-    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Height implements androidx.health.connect.client.records.Record {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getHeightMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double heightMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
-  public final class HipCircumference implements androidx.health.data.client.records.Record {
-    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class HipCircumference implements androidx.health.connect.client.records.Record {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getCircumferenceMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double circumferenceMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
   public final class OvulationTestResults {
-    field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
+    field public static final androidx.health.connect.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
     field public static final String POSITIVE = "positive";
   }
 
   public interface Record {
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.connect.client.metadata.Metadata metadata;
   }
 
-  public final class Steps implements androidx.health.data.client.records.Record {
-    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Steps implements androidx.health.connect.client.records.Record {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public long getCount();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final long count;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Weight implements androidx.health.data.client.records.Record {
-    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+  public final class Weight implements androidx.health.connect.client.records.Record {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public double getWeightKg();
     method public java.time.ZoneOffset? getZoneOffset();
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public final double weightKg;
     property public java.time.ZoneOffset? zoneOffset;
@@ -321,22 +321,22 @@
 
 }
 
-package androidx.health.data.client.request {
+package androidx.health.connect.client.request {
 
   public final class ChangesTokenRequest {
-    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.data.client.metadata.DataOrigin> dataOriginFilters);
+    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.connect.client.metadata.DataOrigin> dataOriginFilters);
   }
 
 }
 
-package androidx.health.data.client.response {
+package androidx.health.connect.client.response {
 
   public final class ChangesResponse {
-    method public java.util.List<androidx.health.data.client.changes.Change> getChanges();
+    method public java.util.List<androidx.health.connect.client.changes.Change> getChanges();
     method public boolean getChangesTokenExpired();
     method public boolean getHasMore();
     method public String getNextChangesToken();
-    property public final java.util.List<androidx.health.data.client.changes.Change> changes;
+    property public final java.util.List<androidx.health.connect.client.changes.Change> changes;
     property public final boolean changesTokenExpired;
     property public final boolean hasMore;
     property public final String nextChangesToken;
@@ -349,25 +349,25 @@
 
 }
 
-package androidx.health.data.client.time {
+package androidx.health.connect.client.time {
 
   public final class TimeRangeFilter {
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
-    field public static final androidx.health.data.client.time.TimeRangeFilter.Companion Companion;
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    field public static final androidx.health.connect.client.time.TimeRangeFilter.Companion Companion;
   }
 
   public static final class TimeRangeFilter.Companion {
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
   }
 
 }
diff --git a/health/health-data-client/api/res-current.txt b/health/health-connect-client/api/res-current.txt
similarity index 100%
rename from health/health-data-client/api/res-current.txt
rename to health/health-connect-client/api/res-current.txt
diff --git a/health/health-data-client/api/restricted_current.txt b/health/health-connect-client/api/restricted_current.txt
similarity index 66%
rename from health/health-data-client/api/restricted_current.txt
rename to health/health-connect-client/api/restricted_current.txt
index 0cb9a6f..0cc077d 100644
--- a/health/health-data-client/api/restricted_current.txt
+++ b/health/health-connect-client/api/restricted_current.txt
@@ -1,46 +1,46 @@
 // Signature format: 4.0
-package androidx.health.data.client {
+package androidx.health.connect.client {
 
-  public interface HealthDataClient {
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, androidx.health.data.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.ChangesResponse>);
-    method public suspend Object? getChangesToken(androidx.health.data.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
-    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse>);
+  public interface HealthConnectClient {
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, androidx.health.connect.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ChangesResponse>);
+    method public suspend Object? getChangesToken(androidx.health.connect.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method public default static boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public default static boolean isAvailable(android.content.Context context);
-    field public static final androidx.health.data.client.HealthDataClient.Companion Companion;
+    field public static final androidx.health.connect.client.HealthConnectClient.Companion Companion;
   }
 
-  public static final class HealthDataClient.Companion {
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
+  public static final class HealthConnectClient.Companion {
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
+    method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
     method public boolean isAvailable(android.content.Context context);
   }
 
 }
 
-package androidx.health.data.client.changes {
+package androidx.health.connect.client.changes {
 
   public interface Change {
   }
 
-  public final class DeletionChange implements androidx.health.data.client.changes.Change {
+  public final class DeletionChange implements androidx.health.connect.client.changes.Change {
     method public String getDeletedUid();
     property public final String deletedUid;
   }
 
-  public final class UpsertionChange implements androidx.health.data.client.changes.Change {
-    method public androidx.health.data.client.records.Record getRecord();
-    property public final androidx.health.data.client.records.Record record;
+  public final class UpsertionChange implements androidx.health.connect.client.changes.Change {
+    method public androidx.health.connect.client.records.Record getRecord();
+    property public final androidx.health.connect.client.records.Record record;
   }
 
 }
 
-package androidx.health.data.client.metadata {
+package androidx.health.connect.client.metadata {
 
   public final class DataOrigin {
     ctor public DataOrigin(String packageName);
@@ -64,7 +64,7 @@
     field public static final String CHEST_STRAP = "CHEST_STRAP";
     field public static final String FITNESS_BAND = "FITNESS_BAND";
     field public static final String HEAD_MOUNTED = "HEAD_MOUNTED";
-    field public static final androidx.health.data.client.metadata.DeviceTypes INSTANCE;
+    field public static final androidx.health.connect.client.metadata.DeviceTypes INSTANCE;
     field public static final String PHONE = "PHONE";
     field public static final String RING = "RING";
     field public static final String SCALE = "SCALE";
@@ -74,24 +74,24 @@
   }
 
   public final class Metadata {
-    ctor public Metadata(optional String? uid, optional androidx.health.data.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.data.client.metadata.Device? device);
+    ctor public Metadata(optional String? uid, optional androidx.health.connect.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.connect.client.metadata.Device? device);
     method public String? getClientId();
     method public long getClientVersion();
-    method public androidx.health.data.client.metadata.DataOrigin getDataOrigin();
-    method public androidx.health.data.client.metadata.Device? getDevice();
+    method public androidx.health.connect.client.metadata.DataOrigin getDataOrigin();
+    method public androidx.health.connect.client.metadata.Device? getDevice();
     method public java.time.Instant getLastModifiedTime();
     method public String? getUid();
     property public final String? clientId;
     property public final long clientVersion;
-    property public final androidx.health.data.client.metadata.DataOrigin dataOrigin;
-    property public final androidx.health.data.client.metadata.Device? device;
+    property public final androidx.health.connect.client.metadata.DataOrigin dataOrigin;
+    property public final androidx.health.connect.client.metadata.Device? device;
     property public final java.time.Instant lastModifiedTime;
     property public final String? uid;
   }
 
 }
 
-package androidx.health.data.client.records {
+package androidx.health.connect.client.records {
 
   public final class ActivityTypes {
     field public static final String BACK_EXTENSION = "back_extension";
@@ -133,7 +133,7 @@
     field public static final String HIKING = "hiking";
     field public static final String ICE_HOCKEY = "ice_hockey";
     field public static final String ICE_SKATING = "ice_skating";
-    field public static final androidx.health.data.client.records.ActivityTypes INSTANCE;
+    field public static final androidx.health.connect.client.records.ActivityTypes INSTANCE;
     field public static final String JUMPING_JACK = "jumping_jack";
     field public static final String JUMP_ROPE = "jump_rope";
     field public static final String LAT_PULL_DOWN = "lat_pull_down";
@@ -181,7 +181,7 @@
   }
 
   public final class BloodPressureMeasurementLocations {
-    field public static final androidx.health.data.client.records.BloodPressureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BloodPressureMeasurementLocations INSTANCE;
     field public static final String LEFT_UPPER_ARM = "left_upper_arm";
     field public static final String LEFT_WRIST = "left_wrist";
     field public static final String RIGHT_UPPER_ARM = "right_upper_arm";
@@ -189,22 +189,22 @@
   }
 
   public final class BodyPositions {
-    field public static final androidx.health.data.client.records.BodyPositions INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyPositions INSTANCE;
     field public static final String LYING_DOWN = "lying_down";
     field public static final String RECLINING = "reclining";
     field public static final String SITTING_DOWN = "sitting_down";
     field public static final String STANDING_UP = "standing_up";
   }
 
-  public final class BodyTemperature implements androidx.health.data.client.records.InstantaneousRecord {
-    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class BodyTemperature implements androidx.health.connect.client.records.InstantaneousRecord {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public double getTemperatureDegreesCelsius();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public final double temperatureDegreesCelsius;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
@@ -215,7 +215,7 @@
     field public static final String EAR = "ear";
     field public static final String FINGER = "finger";
     field public static final String FOREHEAD = "forehead";
-    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final androidx.health.connect.client.records.BodyTemperatureMeasurementLocations INSTANCE;
     field public static final String MOUTH = "mouth";
     field public static final String RECTUM = "rectum";
     field public static final String TEMPORAL_ARTERY = "temporal_artery";
@@ -224,70 +224,70 @@
     field public static final String WRIST = "wrist";
   }
 
-  public final class Distance implements androidx.health.data.client.records.IntervalRecord {
-    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Distance implements androidx.health.connect.client.records.IntervalRecord {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getDistanceMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double distanceMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class ElevationGained implements androidx.health.data.client.records.IntervalRecord {
-    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class ElevationGained implements androidx.health.connect.client.records.IntervalRecord {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getElevationMeters();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final double elevationMeters;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Height implements androidx.health.data.client.records.InstantaneousRecord {
-    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Height implements androidx.health.connect.client.records.InstantaneousRecord {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getHeightMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double heightMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
-  public final class HipCircumference implements androidx.health.data.client.records.InstantaneousRecord {
-    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class HipCircumference implements androidx.health.connect.client.records.InstantaneousRecord {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public double getCircumferenceMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final double circumferenceMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
 
-  @kotlin.PublishedApi internal interface InstantaneousRecord extends androidx.health.data.client.records.Record {
+  @kotlin.PublishedApi internal interface InstantaneousRecord extends androidx.health.connect.client.records.Record {
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public abstract java.time.Instant time;
     property public abstract java.time.ZoneOffset? zoneOffset;
   }
 
-  @kotlin.PublishedApi internal interface IntervalRecord extends androidx.health.data.client.records.Record {
+  @kotlin.PublishedApi internal interface IntervalRecord extends androidx.health.connect.client.records.Record {
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
     method public java.time.Instant getStartTime();
@@ -299,39 +299,39 @@
   }
 
   public final class OvulationTestResults {
-    field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
+    field public static final androidx.health.connect.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
     field public static final String POSITIVE = "positive";
   }
 
   public interface Record {
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.connect.client.metadata.Metadata metadata;
   }
 
-  public final class Steps implements androidx.health.data.client.records.IntervalRecord {
-    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+  public final class Steps implements androidx.health.connect.client.records.IntervalRecord {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
     method public long getCount();
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public final long count;
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
   }
 
-  public final class Weight implements androidx.health.data.client.records.InstantaneousRecord {
-    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
+  public final class Weight implements androidx.health.connect.client.records.InstantaneousRecord {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.metadata.Metadata metadata);
+    method public androidx.health.connect.client.metadata.Metadata getMetadata();
     method public java.time.Instant getTime();
     method public double getWeightKg();
     method public java.time.ZoneOffset? getZoneOffset();
-    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public androidx.health.connect.client.metadata.Metadata metadata;
     property public java.time.Instant time;
     property public final double weightKg;
     property public java.time.ZoneOffset? zoneOffset;
@@ -339,22 +339,22 @@
 
 }
 
-package androidx.health.data.client.request {
+package androidx.health.connect.client.request {
 
   public final class ChangesTokenRequest {
-    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.data.client.metadata.DataOrigin> dataOriginFilters);
+    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.connect.client.metadata.DataOrigin> dataOriginFilters);
   }
 
 }
 
-package androidx.health.data.client.response {
+package androidx.health.connect.client.response {
 
   public final class ChangesResponse {
-    method public java.util.List<androidx.health.data.client.changes.Change> getChanges();
+    method public java.util.List<androidx.health.connect.client.changes.Change> getChanges();
     method public boolean getChangesTokenExpired();
     method public boolean getHasMore();
     method public String getNextChangesToken();
-    property public final java.util.List<androidx.health.data.client.changes.Change> changes;
+    property public final java.util.List<androidx.health.connect.client.changes.Change> changes;
     property public final boolean changesTokenExpired;
     property public final boolean hasMore;
     property public final String nextChangesToken;
@@ -367,25 +367,25 @@
 
 }
 
-package androidx.health.data.client.time {
+package androidx.health.connect.client.time {
 
   public final class TimeRangeFilter {
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
-    field public static final androidx.health.data.client.time.TimeRangeFilter.Companion Companion;
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public static androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    field public static final androidx.health.connect.client.time.TimeRangeFilter.Companion Companion;
   }
 
   public static final class TimeRangeFilter.Companion {
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.Instant startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
+    method public androidx.health.connect.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
   }
 
 }
diff --git a/health/health-data-client/build.gradle b/health/health-connect-client/build.gradle
similarity index 93%
rename from health/health-data-client/build.gradle
rename to health/health-connect-client/build.gradle
index f410180..ef4bf1d 100644
--- a/health/health-data-client/build.gradle
+++ b/health/health-connect-client/build.gradle
@@ -57,7 +57,7 @@
         aidl = true
     }
     testOptions.unitTests.includeAndroidResources = true
-    namespace "androidx.health.data.client"
+    namespace "androidx.health.connect.client"
 }
 
 protobuf {
@@ -80,11 +80,11 @@
 }
 
 androidx {
-    name = "AndroidX Health Data Client Library"
+    name = "AndroidX Health Connect Client Library"
     type = LibraryType.PUBLISHED_LIBRARY
-    mavenVersion = LibraryVersions.HEALTH_DATA_CLIENT
+    mavenVersion = LibraryVersions.HEALTH_CONNECT_CLIENT
     mavenGroup = LibraryGroups.HEALTH
-    inceptionYear = "2021"
+    inceptionYear = "2022"
     description = "read or write user's health and fitness records."
 }
 
diff --git a/health/health-data-client/lint-baseline.xml b/health/health-connect-client/lint-baseline.xml
similarity index 100%
rename from health/health-data-client/lint-baseline.xml
rename to health/health-connect-client/lint-baseline.xml
diff --git a/health/health-data-client/src/androidTest/AndroidManifest.xml b/health/health-connect-client/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from health/health-data-client/src/androidTest/AndroidManifest.xml
rename to health/health-connect-client/src/androidTest/AndroidManifest.xml
diff --git a/health/health-data-client/src/main/AndroidManifest.xml b/health/health-connect-client/src/main/AndroidManifest.xml
similarity index 100%
rename from health/health-data-client/src/main/AndroidManifest.xml
rename to health/health-connect-client/src/main/AndroidManifest.xml
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/changes/ChangesEvent.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/changes/ChangesEvent.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/changes/ChangesEvent.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/changes/ChangesEvent.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/error/ErrorStatus.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/error/ErrorStatus.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/error/ErrorStatus.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/error/ErrorStatus.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetIsInForegroundCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetIsInForegroundCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetIsInForegroundCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetIsInForegroundCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetPermissionTokenCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetPermissionTokenCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetPermissionTokenCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IGetPermissionTokenCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IHealthDataSdkService.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IHealthDataSdkService.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IHealthDataSdkService.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/IHealthDataSdkService.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/ISetPermissionTokenCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/ISetPermissionTokenCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/ISetPermissionTokenCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/impl/sdkservice/ISetPermissionTokenCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/permission/Permission.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/permission/Permission.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/permission/Permission.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/permission/Permission.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/AggregateDataRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/AggregateDataRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/AggregateDataRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/AggregateDataRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRangeRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRangeRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRangeRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRangeRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/DeleteDataRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/GetChangesRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/GetChangesRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/GetChangesRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/GetChangesRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/GetChangesTokenRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/GetChangesTokenRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/GetChangesTokenRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/GetChangesTokenRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRangeRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRangeRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRangeRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRangeRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/ReadDataRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/RequestContext.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/RequestContext.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/RequestContext.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/RequestContext.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/request/UpsertDataRequest.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/UpsertDataRequest.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/request/UpsertDataRequest.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/request/UpsertDataRequest.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/AggregateDataResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/AggregateDataResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/AggregateDataResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/AggregateDataResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/GetChangesResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/GetChangesResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/GetChangesResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/GetChangesResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/GetChangesTokenResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/GetChangesTokenResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/GetChangesTokenResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/GetChangesTokenResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/InsertDataResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/InsertDataResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/InsertDataResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/InsertDataResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/ReadDataRangeResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/ReadDataRangeResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/ReadDataRangeResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/ReadDataRangeResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/response/ReadDataResponse.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/ReadDataResponse.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/response/ReadDataResponse.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/response/ReadDataResponse.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IAggregateDataCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IAggregateDataCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IAggregateDataCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IAggregateDataCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IClearOnChangesListenerCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IClearOnChangesListenerCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IClearOnChangesListenerCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IClearOnChangesListenerCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataRangeCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataRangeCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataRangeCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IDeleteDataRangeCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesTokenCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesTokenCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesTokenCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetChangesTokenCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetGrantedPermissionsCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetGrantedPermissionsCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IGetGrantedPermissionsCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IGetGrantedPermissionsCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IHealthDataService.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IHealthDataService.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IHealthDataService.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IHealthDataService.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IInsertDataCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IInsertDataCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IInsertDataCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IInsertDataCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IOnChangesListener.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IOnChangesListener.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IOnChangesListener.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IOnChangesListener.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IReadDataCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IReadDataCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IReadDataCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IReadDataCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IReadDataRangeCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IReadDataRangeCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IReadDataRangeCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IReadDataRangeCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IRevokeAllPermissionsCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IRevokeAllPermissionsCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IRevokeAllPermissionsCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IRevokeAllPermissionsCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/ISetOnChangesListenerCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/ISetOnChangesListenerCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/ISetOnChangesListenerCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/ISetOnChangesListenerCallback.aidl
diff --git a/health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IUpdateDataCallback.aidl b/health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IUpdateDataCallback.aidl
similarity index 100%
rename from health/health-data-client/src/main/aidl/androidx/health/platform/client/service/IUpdateDataCallback.aidl
rename to health/health-connect-client/src/main/aidl/androidx/health/platform/client/service/IUpdateDataCallback.aidl
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
similarity index 90%
rename from health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
index 647c275..98c47a3 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
@@ -13,37 +13,37 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client
+package androidx.health.connect.client
 
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.Build
 import androidx.annotation.ChecksSdkIntAtLeast
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.AggregateDataRow
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByDuration
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByPeriod
-import androidx.health.data.client.aggregate.AggregateMetric
-import androidx.health.data.client.impl.HealthDataClientImpl
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.permission.Permission
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.request.AggregateGroupByDurationRequest
-import androidx.health.data.client.request.AggregateGroupByPeriodRequest
-import androidx.health.data.client.request.AggregateRequest
-import androidx.health.data.client.request.ChangesTokenRequest
-import androidx.health.data.client.request.ReadRecordsRequest
-import androidx.health.data.client.response.ChangesResponse
-import androidx.health.data.client.response.InsertRecordsResponse
-import androidx.health.data.client.response.ReadRecordResponse
-import androidx.health.data.client.response.ReadRecordsResponse
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.aggregate.AggregateDataRow
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByDuration
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByPeriod
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.impl.HealthConnectClientImpl
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.permission.Permission
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.response.ChangesResponse
+import androidx.health.connect.client.response.InsertRecordsResponse
+import androidx.health.connect.client.response.ReadRecordResponse
+import androidx.health.connect.client.response.ReadRecordsResponse
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.HealthDataService
 import java.lang.IllegalStateException
 import kotlin.reflect.KClass
 
 /** Interface to access health and fitness records. */
-interface HealthDataClient {
+interface HealthConnectClient {
     /**
      * Returns a set of [Permission] granted by the user to this app, out of the input [permissions]
      * set.
@@ -306,7 +306,7 @@
         public fun getOrCreate(
             context: Context,
             packageNames: List<String> = listOf(DEFAULT_PROVIDER_PACKAGE_NAME),
-        ): HealthDataClient {
+        ): HealthConnectClient {
             if (!isSdkVersionSufficient()) {
                 throw UnsupportedOperationException("SDK version too low")
             }
@@ -315,7 +315,7 @@
             }
             val enabledPackage =
                 packageNames.first { isPackageInstalled(context.packageManager, it) }
-            return HealthDataClientImpl(HealthDataService.getClient(context, enabledPackage))
+            return HealthConnectClientImpl(HealthDataService.getClient(context, enabledPackage))
         }
 
         @ChecksSdkIntAtLeast
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRow.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRow.kt
similarity index 93%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRow.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRow.kt
index 9af5c4e..42aabf7 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRow.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRow.kt
@@ -13,16 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.DataOrigin
+import androidx.health.connect.client.metadata.DataOrigin
 import java.time.Duration
 
 /**
  * Represents an aggregation result row.
  *
- * @see [androidx.health.data.client.HealthDataClient.aggregate]
+ * @see [androidx.health.connect.client.HealthConnectClient.aggregate]
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class AggregateDataRow
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByDuration.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByDuration.kt
similarity index 88%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByDuration.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByDuration.kt
index ae36daf..e032c46 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByDuration.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByDuration.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 import java.time.Instant
@@ -22,7 +22,7 @@
 /**
  * Represents an aggregation result row.
  *
- * @see [androidx.health.data.client.HealthDataClient.aggregateGroupByDuration]
+ * @see [androidx.health.connect.client.HealthConnectClient.aggregateGroupByDuration]
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class AggregateDataRowGroupByDuration
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriod.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriod.kt
similarity index 88%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriod.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriod.kt
index 349f37c..e8d7d73 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriod.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriod.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 import java.time.LocalDateTime
@@ -21,7 +21,7 @@
 /**
  * Represents an aggregation result row.
  *
- * @see [androidx.health.data.client.HealthDataClient.aggregateGroupByPeriod]
+ * @see [androidx.health.connect.client.HealthConnectClient.aggregateGroupByPeriod]
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class AggregateDataRowGroupByPeriod
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateMetric.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateMetric.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateMetric.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateMetric.kt
index 94decdf..3691144 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/AggregateMetric.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/AggregateMetric.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DoubleAggregateMetric.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DoubleAggregateMetric.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DoubleAggregateMetric.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DoubleAggregateMetric.kt
index e16de76..ab7694d 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DoubleAggregateMetric.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DoubleAggregateMetric.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DurationAggregateMetric.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DurationAggregateMetric.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DurationAggregateMetric.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DurationAggregateMetric.kt
index ac50645..6a91c5e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/DurationAggregateMetric.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/DurationAggregateMetric.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/LongAggregateMetric.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/LongAggregateMetric.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/LongAggregateMetric.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/LongAggregateMetric.kt
index 41f16ef..5a2623c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/LongAggregateMetric.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/LongAggregateMetric.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.annotation.RestrictTo
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/aggregate/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/aggregate/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/aggregate/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/Change.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/changes/Change.kt
index aa65dc9..c5e0f6f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/Change.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
+package androidx.health.connect.client.changes
 
 /**
  * Abstraction to represent a change to Android Health Platform.
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/ChangesEvent.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/ChangesEvent.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/changes/ChangesEvent.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/changes/ChangesEvent.kt
index c8ab7e1..63b8a73 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/ChangesEvent.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/ChangesEvent.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
+package androidx.health.connect.client.changes
 
 import androidx.annotation.RestrictTo
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/DeletionChange.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/DeletionChange.kt
similarity index 86%
rename from health/health-data-client/src/main/java/androidx/health/data/client/changes/DeletionChange.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/changes/DeletionChange.kt
index 9dd38e3..d18ed9c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/DeletionChange.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/DeletionChange.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
+package androidx.health.connect.client.changes
 
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.connect.client.records.Record
 
 /**
  * A [Change] with [Metadata.uid] of deleted [Record]. For privacy, only unique identifiers of the
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/UpsertionChange.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/UpsertionChange.kt
similarity index 88%
rename from health/health-data-client/src/main/java/androidx/health/data/client/changes/UpsertionChange.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/changes/UpsertionChange.kt
index b29c37f..a0b877a 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/UpsertionChange.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/changes/UpsertionChange.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
+package androidx.health.connect.client.changes
 
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 
 /**
  * A [Change] with inserted or updated [Record].
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/health-data-client-documentation.md b/health/health-connect-client/src/main/java/androidx/health/connect/client/health-data-client-documentation.md
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/health-data-client-documentation.md
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/health-data-client-documentation.md
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientImpl.kt
similarity index 67%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientImpl.kt
index 1782b14..25e449a 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientImpl.kt
@@ -13,39 +13,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl
+package androidx.health.connect.client.impl
 
-import androidx.health.data.client.HealthDataClient
-import androidx.health.data.client.aggregate.AggregateDataRow
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByDuration
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByPeriod
-import androidx.health.data.client.impl.converters.aggregate.retrieveAggregateDataRow
-import androidx.health.data.client.impl.converters.aggregate.toAggregateDataRowGroupByDuration
-import androidx.health.data.client.impl.converters.aggregate.toAggregateDataRowGroupByPeriod
-import androidx.health.data.client.impl.converters.datatype.toDataTypeIdPairProtoList
-import androidx.health.data.client.impl.converters.datatype.toDataTypeName
-import androidx.health.data.client.impl.converters.permission.toJetpackPermission
-import androidx.health.data.client.impl.converters.permission.toProtoPermission
-import androidx.health.data.client.impl.converters.records.toProto
-import androidx.health.data.client.impl.converters.records.toRecord
-import androidx.health.data.client.impl.converters.request.toDeleteDataRangeRequestProto
-import androidx.health.data.client.impl.converters.request.toProto
-import androidx.health.data.client.impl.converters.request.toReadDataRangeRequestProto
-import androidx.health.data.client.impl.converters.request.toReadDataRequestProto
-import androidx.health.data.client.impl.converters.response.toChangesResponse
-import androidx.health.data.client.impl.converters.response.toReadRecordsResponse
-import androidx.health.data.client.permission.Permission
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.request.AggregateGroupByDurationRequest
-import androidx.health.data.client.request.AggregateGroupByPeriodRequest
-import androidx.health.data.client.request.AggregateRequest
-import androidx.health.data.client.request.ChangesTokenRequest
-import androidx.health.data.client.request.ReadRecordsRequest
-import androidx.health.data.client.response.ChangesResponse
-import androidx.health.data.client.response.InsertRecordsResponse
-import androidx.health.data.client.response.ReadRecordResponse
-import androidx.health.data.client.response.ReadRecordsResponse
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.aggregate.AggregateDataRow
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByDuration
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByPeriod
+import androidx.health.connect.client.impl.converters.aggregate.retrieveAggregateDataRow
+import androidx.health.connect.client.impl.converters.aggregate.toAggregateDataRowGroupByDuration
+import androidx.health.connect.client.impl.converters.aggregate.toAggregateDataRowGroupByPeriod
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeIdPairProtoList
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeName
+import androidx.health.connect.client.impl.converters.permission.toJetpackPermission
+import androidx.health.connect.client.impl.converters.permission.toProtoPermission
+import androidx.health.connect.client.impl.converters.records.toProto
+import androidx.health.connect.client.impl.converters.records.toRecord
+import androidx.health.connect.client.impl.converters.request.toDeleteDataRangeRequestProto
+import androidx.health.connect.client.impl.converters.request.toProto
+import androidx.health.connect.client.impl.converters.request.toReadDataRangeRequestProto
+import androidx.health.connect.client.impl.converters.request.toReadDataRequestProto
+import androidx.health.connect.client.impl.converters.response.toChangesResponse
+import androidx.health.connect.client.impl.converters.response.toReadRecordsResponse
+import androidx.health.connect.client.permission.Permission
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.response.ChangesResponse
+import androidx.health.connect.client.response.InsertRecordsResponse
+import androidx.health.connect.client.response.ReadRecordResponse
+import androidx.health.connect.client.response.ReadRecordsResponse
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.HealthDataAsyncClient
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
@@ -58,9 +58,9 @@
  *
  * @suppress
  */
-class HealthDataClientImpl(
+class HealthConnectClientImpl(
     private val delegate: HealthDataAsyncClient,
-) : HealthDataClient {
+) : HealthConnectClient {
 
     override suspend fun getGrantedPermissions(permissions: Set<Permission>): Set<Permission> {
         return delegate
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricToProto.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricToProto.kt
similarity index 87%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricToProto.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricToProto.kt
index c2d0811..c1e1663 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricToProto.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricToProto.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.aggregate
+package androidx.health.connect.client.impl.converters.aggregate
 
-import androidx.health.data.client.aggregate.AggregateMetric
+import androidx.health.connect.client.aggregate.AggregateMetric
 import androidx.health.platform.client.proto.RequestProto
 
 fun AggregateMetric.toProto(): RequestProto.AggregateMetricSpec =
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt
similarity index 85%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt
index 7ba1fe4..b46beb6 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/aggregate/ProtoToAggregateDataRow.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.aggregate
+package androidx.health.connect.client.impl.converters.aggregate
 
-import androidx.health.data.client.aggregate.AggregateDataRow
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByDuration
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByPeriod
-import androidx.health.data.client.metadata.DataOrigin
+import androidx.health.connect.client.aggregate.AggregateDataRow
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByDuration
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByPeriod
+import androidx.health.connect.client.metadata.DataOrigin
 import androidx.health.platform.client.proto.DataProto
 import java.time.Instant
 import java.time.LocalDateTime
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/changes/ChangesEventConverter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/changes/ChangesEventConverter.kt
similarity index 77%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/changes/ChangesEventConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/changes/ChangesEventConverter.kt
index 5f2f9bc..d101792 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/changes/ChangesEventConverter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/changes/ChangesEventConverter.kt
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.changes
+package androidx.health.connect.client.impl.converters.changes
 
-import androidx.health.data.client.changes.Change
-import androidx.health.data.client.changes.ChangesEvent
-import androidx.health.data.client.changes.DeletionChange
-import androidx.health.data.client.changes.UpsertionChange
-import androidx.health.data.client.impl.converters.records.toRecord
+import androidx.health.connect.client.changes.Change
+import androidx.health.connect.client.changes.ChangesEvent
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.impl.converters.records.toRecord
 import androidx.health.platform.client.proto.ChangeProto
 
 /** Converts proto response to public API object. */
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeConverter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeConverter.kt
similarity index 89%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeConverter.kt
index 52ef73c..66f971c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeConverter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeConverter.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.datatype
+package androidx.health.connect.client.impl.converters.datatype
 
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 import kotlin.reflect.KClass
 
 /** Converts public API object into internal proto for ipc. */
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeIdPairConverter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeIdPairConverter.kt
similarity index 93%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeIdPairConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeIdPairConverter.kt
index 1b1c87e..c943e5e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/DataTypeIdPairConverter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/DataTypeIdPairConverter.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.datatype
+package androidx.health.connect.client.impl.converters.datatype
 
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
 import kotlin.reflect.KClass
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt
new file mode 100644
index 0000000..0882ee3
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.connect.client.impl.converters.datatype
+
+import androidx.health.connect.client.records.ActiveCaloriesBurned
+import androidx.health.connect.client.records.ActivityEvent
+import androidx.health.connect.client.records.ActivityLap
+import androidx.health.connect.client.records.ActivitySession
+import androidx.health.connect.client.records.BasalBodyTemperature
+import androidx.health.connect.client.records.BasalMetabolicRate
+import androidx.health.connect.client.records.BloodGlucose
+import androidx.health.connect.client.records.BloodPressure
+import androidx.health.connect.client.records.BodyFat
+import androidx.health.connect.client.records.BodyTemperature
+import androidx.health.connect.client.records.BodyWaterMass
+import androidx.health.connect.client.records.BoneMass
+import androidx.health.connect.client.records.CervicalMucus
+import androidx.health.connect.client.records.CervicalPosition
+import androidx.health.connect.client.records.CyclingPedalingCadence
+import androidx.health.connect.client.records.Distance
+import androidx.health.connect.client.records.ElevationGained
+import androidx.health.connect.client.records.FloorsClimbed
+import androidx.health.connect.client.records.HeartRateSeries
+import androidx.health.connect.client.records.HeartRateVariabilityDifferentialIndex
+import androidx.health.connect.client.records.HeartRateVariabilityRmssd
+import androidx.health.connect.client.records.HeartRateVariabilityS
+import androidx.health.connect.client.records.HeartRateVariabilitySd2
+import androidx.health.connect.client.records.HeartRateVariabilitySdann
+import androidx.health.connect.client.records.HeartRateVariabilitySdnn
+import androidx.health.connect.client.records.HeartRateVariabilitySdnnIndex
+import androidx.health.connect.client.records.HeartRateVariabilitySdsd
+import androidx.health.connect.client.records.HeartRateVariabilityTinn
+import androidx.health.connect.client.records.Height
+import androidx.health.connect.client.records.HipCircumference
+import androidx.health.connect.client.records.Hydration
+import androidx.health.connect.client.records.LeanBodyMass
+import androidx.health.connect.client.records.Menstruation
+import androidx.health.connect.client.records.Nutrition
+import androidx.health.connect.client.records.OvulationTest
+import androidx.health.connect.client.records.OxygenSaturation
+import androidx.health.connect.client.records.Power
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.Repetitions
+import androidx.health.connect.client.records.RespiratoryRate
+import androidx.health.connect.client.records.RestingHeartRate
+import androidx.health.connect.client.records.SexualActivity
+import androidx.health.connect.client.records.SleepSession
+import androidx.health.connect.client.records.SleepStage
+import androidx.health.connect.client.records.Speed
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.records.StepsCadence
+import androidx.health.connect.client.records.SwimmingStrokes
+import androidx.health.connect.client.records.TotalCaloriesBurned
+import androidx.health.connect.client.records.TotalEnergyBurned
+import androidx.health.connect.client.records.Vo2Max
+import androidx.health.connect.client.records.WaistCircumference
+import androidx.health.connect.client.records.Weight
+import androidx.health.connect.client.records.WheelchairPushes
+import kotlin.reflect.KClass
+
+private val ALL_RECORDS_TYPES =
+    setOf(
+        ActiveCaloriesBurned::class,
+        ActivityEvent::class,
+        ActivityLap::class,
+        ActivitySession::class,
+        BasalBodyTemperature::class,
+        BasalMetabolicRate::class,
+        BloodGlucose::class,
+        BloodPressure::class,
+        BodyFat::class,
+        BodyTemperature::class,
+        BodyWaterMass::class,
+        BoneMass::class,
+        CervicalMucus::class,
+        CervicalPosition::class,
+        CyclingPedalingCadence::class,
+        Distance::class,
+        ElevationGained::class,
+        FloorsClimbed::class,
+        HeartRateSeries::class,
+        HeartRateVariabilityDifferentialIndex::class,
+        HeartRateVariabilityRmssd::class,
+        HeartRateVariabilityS::class,
+        HeartRateVariabilitySd2::class,
+        HeartRateVariabilitySdann::class,
+        HeartRateVariabilitySdnn::class,
+        HeartRateVariabilitySdnnIndex::class,
+        HeartRateVariabilitySdsd::class,
+        HeartRateVariabilityTinn::class,
+        Height::class,
+        HipCircumference::class,
+        Hydration::class,
+        LeanBodyMass::class,
+        Menstruation::class,
+        Nutrition::class,
+        OvulationTest::class,
+        OxygenSaturation::class,
+        Power::class,
+        Repetitions::class,
+        RespiratoryRate::class,
+        RestingHeartRate::class,
+        SexualActivity::class,
+        SleepSession::class,
+        SleepStage::class,
+        Speed::class,
+        Steps::class,
+        StepsCadence::class,
+        SwimmingStrokes::class,
+        TotalCaloriesBurned::class,
+        TotalEnergyBurned::class,
+        Vo2Max::class,
+        WaistCircumference::class,
+        WheelchairPushes::class,
+        Weight::class,
+    )
+
+val RECORDS_TYPE_NAME_MAP: Map<String, KClass<out Record>> =
+    ALL_RECORDS_TYPES.associateBy { it.simpleName!! }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/permission/PermissionConverter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/permission/PermissionConverter.kt
similarity index 84%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/permission/PermissionConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/permission/PermissionConverter.kt
index 9c17b4a..ec24cbc 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/permission/PermissionConverter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/permission/PermissionConverter.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.permission
+package androidx.health.connect.client.impl.converters.permission
 
-import androidx.health.data.client.impl.converters.datatype.toDataTypeKClass
-import androidx.health.data.client.impl.converters.datatype.toDataTypeName
-import androidx.health.data.client.permission.AccessTypes
-import androidx.health.data.client.permission.Permission
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeKClass
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeName
+import androidx.health.connect.client.permission.AccessTypes
+import androidx.health.connect.client.permission.Permission
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.PermissionProto
 import java.lang.IllegalStateException
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
similarity index 81%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
index 7eed099..e1af71d 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
@@ -13,67 +13,69 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
-import androidx.health.data.client.records.ActiveCaloriesBurned
-import androidx.health.data.client.records.ActivityEvent
-import androidx.health.data.client.records.ActivityLap
-import androidx.health.data.client.records.ActivitySession
-import androidx.health.data.client.records.BasalBodyTemperature
-import androidx.health.data.client.records.BasalMetabolicRate
-import androidx.health.data.client.records.BloodGlucose
-import androidx.health.data.client.records.BloodPressure
-import androidx.health.data.client.records.BodyFat
-import androidx.health.data.client.records.BodyTemperature
-import androidx.health.data.client.records.BodyWaterMass
-import androidx.health.data.client.records.BoneMass
-import androidx.health.data.client.records.CervicalMucus
-import androidx.health.data.client.records.CervicalPosition
-import androidx.health.data.client.records.CyclingPedalingCadence
-import androidx.health.data.client.records.Distance
-import androidx.health.data.client.records.ElevationGained
-import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
-import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
-import androidx.health.data.client.records.HeartRateVariabilityRmssd
-import androidx.health.data.client.records.HeartRateVariabilityS
-import androidx.health.data.client.records.HeartRateVariabilitySd2
-import androidx.health.data.client.records.HeartRateVariabilitySdann
-import androidx.health.data.client.records.HeartRateVariabilitySdnn
-import androidx.health.data.client.records.HeartRateVariabilitySdnnIndex
-import androidx.health.data.client.records.HeartRateVariabilitySdsd
-import androidx.health.data.client.records.HeartRateVariabilityTinn
-import androidx.health.data.client.records.Height
-import androidx.health.data.client.records.HipCircumference
-import androidx.health.data.client.records.Hydration
-import androidx.health.data.client.records.LeanBodyMass
-import androidx.health.data.client.records.Menstruation
-import androidx.health.data.client.records.Nutrition
-import androidx.health.data.client.records.OvulationTest
-import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Power
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.records.Repetitions
-import androidx.health.data.client.records.RespiratoryRate
-import androidx.health.data.client.records.RestingHeartRate
-import androidx.health.data.client.records.SexualActivity
-import androidx.health.data.client.records.SleepSession
-import androidx.health.data.client.records.SleepStage
-import androidx.health.data.client.records.Speed
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.records.StepsCadence
-import androidx.health.data.client.records.SwimmingStrokes
-import androidx.health.data.client.records.TotalCaloriesBurned
-import androidx.health.data.client.records.Vo2Max
-import androidx.health.data.client.records.WaistCircumference
-import androidx.health.data.client.records.Weight
-import androidx.health.data.client.records.WheelchairPushes
+import androidx.health.connect.client.records.ActiveCaloriesBurned
+import androidx.health.connect.client.records.ActivityEvent
+import androidx.health.connect.client.records.ActivityLap
+import androidx.health.connect.client.records.ActivitySession
+import androidx.health.connect.client.records.BasalBodyTemperature
+import androidx.health.connect.client.records.BasalMetabolicRate
+import androidx.health.connect.client.records.BloodGlucose
+import androidx.health.connect.client.records.BloodPressure
+import androidx.health.connect.client.records.BodyFat
+import androidx.health.connect.client.records.BodyTemperature
+import androidx.health.connect.client.records.BodyWaterMass
+import androidx.health.connect.client.records.BoneMass
+import androidx.health.connect.client.records.CervicalMucus
+import androidx.health.connect.client.records.CervicalPosition
+import androidx.health.connect.client.records.CyclingPedalingCadence
+import androidx.health.connect.client.records.Distance
+import androidx.health.connect.client.records.ElevationGained
+import androidx.health.connect.client.records.FloorsClimbed
+import androidx.health.connect.client.records.HeartRate
+import androidx.health.connect.client.records.HeartRateSeries
+import androidx.health.connect.client.records.HeartRateVariabilityDifferentialIndex
+import androidx.health.connect.client.records.HeartRateVariabilityRmssd
+import androidx.health.connect.client.records.HeartRateVariabilityS
+import androidx.health.connect.client.records.HeartRateVariabilitySd2
+import androidx.health.connect.client.records.HeartRateVariabilitySdann
+import androidx.health.connect.client.records.HeartRateVariabilitySdnn
+import androidx.health.connect.client.records.HeartRateVariabilitySdnnIndex
+import androidx.health.connect.client.records.HeartRateVariabilitySdsd
+import androidx.health.connect.client.records.HeartRateVariabilityTinn
+import androidx.health.connect.client.records.Height
+import androidx.health.connect.client.records.HipCircumference
+import androidx.health.connect.client.records.Hydration
+import androidx.health.connect.client.records.LeanBodyMass
+import androidx.health.connect.client.records.Menstruation
+import androidx.health.connect.client.records.Nutrition
+import androidx.health.connect.client.records.OvulationTest
+import androidx.health.connect.client.records.OxygenSaturation
+import androidx.health.connect.client.records.Power
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.Repetitions
+import androidx.health.connect.client.records.RespiratoryRate
+import androidx.health.connect.client.records.RestingHeartRate
+import androidx.health.connect.client.records.SexualActivity
+import androidx.health.connect.client.records.SleepSession
+import androidx.health.connect.client.records.SleepStage
+import androidx.health.connect.client.records.Speed
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.records.StepsCadence
+import androidx.health.connect.client.records.SwimmingStrokes
+import androidx.health.connect.client.records.TotalCaloriesBurned
+import androidx.health.connect.client.records.TotalEnergyBurned
+import androidx.health.connect.client.records.Vo2Max
+import androidx.health.connect.client.records.WaistCircumference
+import androidx.health.connect.client.records.Weight
+import androidx.health.connect.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
-import java.lang.RuntimeException
+import java.time.Instant
 
 /** Converts public API object into internal proto for ipc. */
-fun toRecord(proto: DataProto.DataPoint): Record {
-    return with(proto) {
+fun toRecord(proto: DataProto.DataPoint): Record =
+    with(proto) {
         when (dataType.name) {
             "BasalBodyTemperature" ->
                 BasalBodyTemperature(
@@ -163,12 +165,20 @@
                     zoneOffset = zoneOffset,
                     metadata = metadata
                 )
-            "HeartRate" ->
-                HeartRate(
-                    beatsPerMinute = getLong("bpm"),
-                    time = time,
-                    zoneOffset = zoneOffset,
-                    metadata = metadata
+            "HeartRateSeries" ->
+                HeartRateSeries(
+                    startTime = startTime,
+                    startZoneOffset = startZoneOffset,
+                    endTime = endTime,
+                    endZoneOffset = endZoneOffset,
+                    samples =
+                        seriesValuesList.map { value ->
+                            HeartRate(
+                                time = Instant.ofEpochMilli(value.instantTimeMillis),
+                                beatsPerMinute = value.getLong("bpm"),
+                            )
+                        },
+                    metadata = metadata,
                 )
             "Height" ->
                 Height(
@@ -521,6 +531,15 @@
                     endZoneOffset = endZoneOffset,
                     metadata = metadata
                 )
+            "TotalEnergyBurned" ->
+                TotalEnergyBurned(
+                    energyKcal = getDouble("energy"),
+                    startTime = startTime,
+                    startZoneOffset = startZoneOffset,
+                    endTime = endTime,
+                    endZoneOffset = endZoneOffset,
+                    metadata = metadata
+                )
             "WheelchairPushes" ->
                 WheelchairPushes(
                     count = getLong("count"),
@@ -533,4 +552,3 @@
             else -> throw RuntimeException("Unknown data type ${dataType.name}")
         }
     }
-}
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordUtils.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordUtils.kt
new file mode 100644
index 0000000..081d281
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordUtils.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.connect.client.impl.converters.records
+
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.metadata.Device
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.platform.client.proto.DataProto
+import androidx.health.platform.client.proto.DataProto.DataPointOrBuilder
+import androidx.health.platform.client.proto.DataProto.SeriesValueOrBuilder
+import java.time.Instant
+import java.time.ZoneOffset
+
+/** Internal helper functions to convert proto to records. */
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.startTime: Instant
+    get() = Instant.ofEpochMilli(startTimeMillis)
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.endTime: Instant
+    get() = Instant.ofEpochMilli(endTimeMillis)
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.time: Instant
+    get() = Instant.ofEpochMilli(instantTimeMillis)
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.startZoneOffset: ZoneOffset?
+    get() =
+        if (hasStartZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(startZoneOffsetSeconds) else null
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.endZoneOffset: ZoneOffset?
+    get() = if (hasEndZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(endZoneOffsetSeconds) else null
+
+@get:SuppressWarnings("GoodTime") // HealthDataClientImplSafe to use for deserialization
+internal val DataProto.DataPoint.zoneOffset: ZoneOffset?
+    get() = if (hasZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(zoneOffsetSeconds) else null
+
+internal fun DataPointOrBuilder.getLong(key: String, defaultVal: Long = 0): Long =
+    valuesMap[key]?.longVal ?: defaultVal
+
+internal fun DataPointOrBuilder.getDouble(key: String, defaultVal: Double = 0.0): Double =
+    valuesMap[key]?.doubleVal ?: defaultVal
+
+internal fun DataPointOrBuilder.getString(key: String): String? = valuesMap[key]?.stringVal
+
+internal fun DataPointOrBuilder.getEnum(key: String): String? {
+    return valuesMap[key]?.enumVal
+}
+
+internal fun SeriesValueOrBuilder.getLong(key: String, defaultVal: Long = 0): Long =
+    valuesMap[key]?.longVal ?: defaultVal
+
+internal fun SeriesValueOrBuilder.getDouble(key: String, defaultVal: Double = 0.0): Double =
+    valuesMap[key]?.doubleVal ?: defaultVal
+
+internal fun SeriesValueOrBuilder.getString(key: String): String? = valuesMap[key]?.stringVal
+
+internal fun SeriesValueOrBuilder.getEnum(key: String): String? = valuesMap[key]?.enumVal
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
+internal val DataProto.DataPoint.metadata: Metadata
+    get() =
+        Metadata(
+            uid = if (hasUid()) uid else null,
+            dataOrigin = DataOrigin(dataOrigin.applicationId),
+            lastModifiedTime = Instant.ofEpochMilli(updateTimeMillis),
+            clientId = if (hasClientId()) clientId else null,
+            clientVersion = clientVersion,
+            device = toDevice(device)
+        )
+
+private fun toDevice(proto: DataProto.Device): Device {
+    return with(proto) {
+        Device(
+            identifier = if (hasIdentifier()) identifier else null,
+            manufacturer = if (hasManufacturer()) manufacturer else null,
+            model = if (hasModel()) model else null,
+            type = if (hasType()) type else null
+        )
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
similarity index 81%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
index 2b78f78..eb883bb 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
@@ -13,68 +13,68 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
-import androidx.health.data.client.records.ActiveCaloriesBurned
-import androidx.health.data.client.records.ActivityEvent
-import androidx.health.data.client.records.ActivityLap
-import androidx.health.data.client.records.ActivitySession
-import androidx.health.data.client.records.BasalBodyTemperature
-import androidx.health.data.client.records.BasalMetabolicRate
-import androidx.health.data.client.records.BloodGlucose
-import androidx.health.data.client.records.BloodPressure
-import androidx.health.data.client.records.BodyFat
-import androidx.health.data.client.records.BodyTemperature
-import androidx.health.data.client.records.BodyWaterMass
-import androidx.health.data.client.records.BoneMass
-import androidx.health.data.client.records.CervicalMucus
-import androidx.health.data.client.records.CervicalPosition
-import androidx.health.data.client.records.CyclingPedalingCadence
-import androidx.health.data.client.records.Distance
-import androidx.health.data.client.records.ElevationGained
-import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
-import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
-import androidx.health.data.client.records.HeartRateVariabilityRmssd
-import androidx.health.data.client.records.HeartRateVariabilityS
-import androidx.health.data.client.records.HeartRateVariabilitySd2
-import androidx.health.data.client.records.HeartRateVariabilitySdann
-import androidx.health.data.client.records.HeartRateVariabilitySdnn
-import androidx.health.data.client.records.HeartRateVariabilitySdnnIndex
-import androidx.health.data.client.records.HeartRateVariabilitySdsd
-import androidx.health.data.client.records.HeartRateVariabilityTinn
-import androidx.health.data.client.records.Height
-import androidx.health.data.client.records.HipCircumference
-import androidx.health.data.client.records.Hydration
-import androidx.health.data.client.records.LeanBodyMass
-import androidx.health.data.client.records.Menstruation
-import androidx.health.data.client.records.Nutrition
-import androidx.health.data.client.records.OvulationTest
-import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Power
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.records.Repetitions
-import androidx.health.data.client.records.RespiratoryRate
-import androidx.health.data.client.records.RestingHeartRate
-import androidx.health.data.client.records.SexualActivity
-import androidx.health.data.client.records.SleepSession
-import androidx.health.data.client.records.SleepStage
-import androidx.health.data.client.records.Speed
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.records.StepsCadence
-import androidx.health.data.client.records.SwimmingStrokes
-import androidx.health.data.client.records.TotalCaloriesBurned
-import androidx.health.data.client.records.Vo2Max
-import androidx.health.data.client.records.WaistCircumference
-import androidx.health.data.client.records.Weight
-import androidx.health.data.client.records.WheelchairPushes
+import androidx.health.connect.client.records.ActiveCaloriesBurned
+import androidx.health.connect.client.records.ActivityEvent
+import androidx.health.connect.client.records.ActivityLap
+import androidx.health.connect.client.records.ActivitySession
+import androidx.health.connect.client.records.BasalBodyTemperature
+import androidx.health.connect.client.records.BasalMetabolicRate
+import androidx.health.connect.client.records.BloodGlucose
+import androidx.health.connect.client.records.BloodPressure
+import androidx.health.connect.client.records.BodyFat
+import androidx.health.connect.client.records.BodyTemperature
+import androidx.health.connect.client.records.BodyWaterMass
+import androidx.health.connect.client.records.BoneMass
+import androidx.health.connect.client.records.CervicalMucus
+import androidx.health.connect.client.records.CervicalPosition
+import androidx.health.connect.client.records.CyclingPedalingCadence
+import androidx.health.connect.client.records.Distance
+import androidx.health.connect.client.records.ElevationGained
+import androidx.health.connect.client.records.FloorsClimbed
+import androidx.health.connect.client.records.HeartRateSeries
+import androidx.health.connect.client.records.HeartRateVariabilityDifferentialIndex
+import androidx.health.connect.client.records.HeartRateVariabilityRmssd
+import androidx.health.connect.client.records.HeartRateVariabilityS
+import androidx.health.connect.client.records.HeartRateVariabilitySd2
+import androidx.health.connect.client.records.HeartRateVariabilitySdann
+import androidx.health.connect.client.records.HeartRateVariabilitySdnn
+import androidx.health.connect.client.records.HeartRateVariabilitySdnnIndex
+import androidx.health.connect.client.records.HeartRateVariabilitySdsd
+import androidx.health.connect.client.records.HeartRateVariabilityTinn
+import androidx.health.connect.client.records.Height
+import androidx.health.connect.client.records.HipCircumference
+import androidx.health.connect.client.records.Hydration
+import androidx.health.connect.client.records.LeanBodyMass
+import androidx.health.connect.client.records.Menstruation
+import androidx.health.connect.client.records.Nutrition
+import androidx.health.connect.client.records.OvulationTest
+import androidx.health.connect.client.records.OxygenSaturation
+import androidx.health.connect.client.records.Power
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.Repetitions
+import androidx.health.connect.client.records.RespiratoryRate
+import androidx.health.connect.client.records.RestingHeartRate
+import androidx.health.connect.client.records.SeriesRecord
+import androidx.health.connect.client.records.SexualActivity
+import androidx.health.connect.client.records.SleepSession
+import androidx.health.connect.client.records.SleepStage
+import androidx.health.connect.client.records.Speed
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.records.StepsCadence
+import androidx.health.connect.client.records.SwimmingStrokes
+import androidx.health.connect.client.records.TotalCaloriesBurned
+import androidx.health.connect.client.records.TotalEnergyBurned
+import androidx.health.connect.client.records.Vo2Max
+import androidx.health.connect.client.records.WaistCircumference
+import androidx.health.connect.client.records.Weight
+import androidx.health.connect.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
-import java.lang.RuntimeException
 
 /** Converts public API object into internal proto for ipc. */
-@SuppressWarnings("NewApi") // Safe to use with java8 desugar
-fun Record.toProto(): DataProto.DataPoint {
-    return when (this) {
+fun Record.toProto(): DataProto.DataPoint =
+    when (this) {
         is BasalBodyTemperature ->
             instantaneousProto()
                 .setDataType(protoDataType("BasalBodyTemperature"))
@@ -153,11 +153,13 @@
                 .setDataType(protoDataType("CyclingPedalingCadence"))
                 .apply { putValues("rpm", doubleVal(revolutionsPerMinute)) }
                 .build()
-        is HeartRate ->
-            instantaneousProto()
-                .setDataType(protoDataType("HeartRate"))
-                .apply { putValues("bpm", longVal(beatsPerMinute)) }
-                .build()
+        is HeartRateSeries ->
+            toProto(dataTypeName = "HeartRateSeries") { sample ->
+                DataProto.SeriesValue.newBuilder()
+                    .putValues("bpm", longVal(sample.beatsPerMinute))
+                    .setInstantTimeMillis(sample.time.toEpochMilli())
+                    .build()
+            }
         is Height ->
             instantaneousProto()
                 .setDataType(protoDataType("Height"))
@@ -501,6 +503,11 @@
                 .setDataType(protoDataType("TotalCaloriesBurned"))
                 .apply { putValues("energy", doubleVal(energyKcal)) }
                 .build()
+        is TotalEnergyBurned ->
+            intervalProto()
+                .setDataType(protoDataType("TotalEnergyBurned"))
+                .apply { putValues("energy", doubleVal(energyKcal)) }
+                .build()
         is WheelchairPushes ->
             intervalProto()
                 .setDataType(protoDataType("WheelchairPushes"))
@@ -508,4 +515,16 @@
                 .build()
         else -> throw RuntimeException("Unsupported yet!")
     }
-}
+
+private fun <T : Any> SeriesRecord<T>.toProto(
+    dataTypeName: String,
+    getSeriesValue: (sample: T) -> DataProto.SeriesValue,
+): DataProto.DataPoint =
+    intervalProto()
+        .setDataType(protoDataType(dataTypeName = dataTypeName))
+        .apply {
+            for (sample in samples) {
+                addSeriesValues(getSeriesValue(sample))
+            }
+        }
+        .build()
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoUtils.kt
similarity index 82%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoUtils.kt
index a882c33..89bc9ec 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoUtils.kt
@@ -13,19 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
-import androidx.health.data.client.metadata.Device
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.data.client.records.InstantaneousRecord
-import androidx.health.data.client.records.IntervalRecord
+import androidx.health.connect.client.metadata.Device
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.connect.client.records.InstantaneousRecord
+import androidx.health.connect.client.records.IntervalRecord
 import androidx.health.platform.client.proto.DataProto
 import java.time.Instant
 
 internal fun protoDataType(dataTypeName: String): DataProto.DataType =
     DataProto.DataType.newBuilder().setName(dataTypeName).build()
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 internal fun InstantaneousRecord.instantaneousProto(): DataProto.DataPoint.Builder {
     val builder =
         DataProto.DataPoint.newBuilder()
@@ -35,7 +35,7 @@
     return builder
 }
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 internal fun IntervalRecord.intervalProto(): DataProto.DataPoint.Builder {
     val builder =
         DataProto.DataPoint.newBuilder()
@@ -47,7 +47,7 @@
     return builder
 }
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 private fun DataProto.DataPoint.Builder.setMetadata(metadata: Metadata) = apply {
     metadata.uid?.let { setUid(it) }
     if (metadata.dataOrigin.packageName.isNotEmpty()) {
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ValueExt.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ValueExt.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ValueExt.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ValueExt.kt
index 554ac83..be01808 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ValueExt.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ValueExt.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
 import androidx.health.platform.client.proto.DataProto
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/AggregateRequestToProto.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/AggregateRequestToProto.kt
similarity index 80%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/AggregateRequestToProto.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/AggregateRequestToProto.kt
index b5ace22..41d58b6 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/AggregateRequestToProto.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/AggregateRequestToProto.kt
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.request
+package androidx.health.connect.client.impl.converters.request
 
-import androidx.health.data.client.impl.converters.aggregate.toProto
-import androidx.health.data.client.impl.converters.time.toProto
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.request.AggregateGroupByDurationRequest
-import androidx.health.data.client.request.AggregateGroupByPeriodRequest
-import androidx.health.data.client.request.AggregateRequest
+import androidx.health.connect.client.impl.converters.aggregate.toProto
+import androidx.health.connect.client.impl.converters.time.toProto
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/DeleteDataRangeRequestToProto.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/DeleteDataRangeRequestToProto.kt
similarity index 78%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/DeleteDataRangeRequestToProto.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/DeleteDataRangeRequestToProto.kt
index d605e2e..9e640b4 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/DeleteDataRangeRequestToProto.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/DeleteDataRangeRequestToProto.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.request
+package androidx.health.connect.client.impl.converters.request
 
-import androidx.health.data.client.impl.converters.datatype.toDataTypeName
-import androidx.health.data.client.impl.converters.time.toProto
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeName
+import androidx.health.connect.client.impl.converters.time.toProto
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
 import kotlin.reflect.KClass
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRangeRequestToProto.kt
similarity index 81%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRangeRequestToProto.kt
index fa38d639..a8d4b74 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRangeRequestToProto.kt
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.request
+package androidx.health.connect.client.impl.converters.request
 
-import androidx.health.data.client.impl.converters.datatype.toDataTypeName
-import androidx.health.data.client.impl.converters.time.toProto
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.request.ReadRecordsRequest
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeName
+import androidx.health.connect.client.impl.converters.time.toProto
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.request.ReadRecordsRequest
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRequestToProto.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRequestToProto.kt
similarity index 83%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRequestToProto.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRequestToProto.kt
index d404d97..80a7a47 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRequestToProto.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/request/ReadDataRequestToProto.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.request
+package androidx.health.connect.client.impl.converters.request
 
-import androidx.health.data.client.impl.converters.datatype.toDataTypeIdPairProto
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.impl.converters.datatype.toDataTypeIdPairProto
+import androidx.health.connect.client.records.Record
 import androidx.health.platform.client.proto.RequestProto
 import kotlin.reflect.KClass
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToChangesResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToChangesResponse.kt
similarity index 78%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToChangesResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToChangesResponse.kt
index 338eb4c..9def251 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToChangesResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToChangesResponse.kt
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.response
+package androidx.health.connect.client.impl.converters.response
 
-import androidx.health.data.client.changes.Change
-import androidx.health.data.client.changes.DeletionChange
-import androidx.health.data.client.changes.UpsertionChange
-import androidx.health.data.client.impl.converters.records.toRecord
-import androidx.health.data.client.response.ChangesResponse
+import androidx.health.connect.client.changes.Change
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.impl.converters.records.toRecord
+import androidx.health.connect.client.response.ChangesResponse
 import androidx.health.platform.client.proto.ChangeProto
 import androidx.health.platform.client.proto.ResponseProto
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToReadRecordsResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToReadRecordsResponse.kt
similarity index 80%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToReadRecordsResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToReadRecordsResponse.kt
index ccd8f1d..e0394f0 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/response/ProtoToReadRecordsResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/response/ProtoToReadRecordsResponse.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.response
+package androidx.health.connect.client.impl.converters.response
 
-import androidx.health.data.client.impl.converters.records.toRecord
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.response.ReadRecordsResponse
+import androidx.health.connect.client.impl.converters.records.toRecord
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.response.ReadRecordsResponse
 import androidx.health.platform.client.proto.ResponseProto
 
 /** Converts public API object into internal proto for ipc. */
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/time/TimeRangeFilterConverter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/time/TimeRangeFilterConverter.kt
similarity index 91%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/time/TimeRangeFilterConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/time/TimeRangeFilterConverter.kt
index 7dd84ff..b54e758 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/time/TimeRangeFilterConverter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/time/TimeRangeFilterConverter.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.time
+package androidx.health.connect.client.impl.converters.time
 
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.proto.TimeProto
 
 /** Converts public API object into internal proto for ipc. */
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/impl/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/impl/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/DataOrigin.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DataOrigin.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/metadata/DataOrigin.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DataOrigin.kt
index ad487ac..bdd1281 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/DataOrigin.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DataOrigin.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.metadata
+package androidx.health.connect.client.metadata
 
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 
 /**
  * Specifies the original source of any [Record]: application that inserted it and device on which
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/Device.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Device.kt
similarity index 97%
rename from health/health-data-client/src/main/java/androidx/health/data/client/metadata/Device.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Device.kt
index 6316884..d13ba61 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/Device.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Device.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.metadata
+package androidx.health.connect.client.metadata
 
 /**
  * A physical device (such as phone, watch, scale, or chest strap) which captured associated health
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/DeviceType.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DeviceType.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/metadata/DeviceType.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DeviceType.kt
index e02c630..b0736cc 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/DeviceType.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/DeviceType.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.metadata
+package androidx.health.connect.client.metadata
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/Metadata.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Metadata.kt
similarity index 97%
rename from health/health-data-client/src/main/java/androidx/health/data/client/metadata/Metadata.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Metadata.kt
index 9e5e745..42cc0bb 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/Metadata.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/Metadata.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.metadata
+package androidx.health.connect.client.metadata
 
 import java.time.Instant
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/metadata/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/metadata/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/metadata/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/permission/AccessTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/AccessTypes.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/permission/AccessTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/permission/AccessTypes.kt
index 838e731..f2b9b94 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/permission/AccessTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/AccessTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.permission
+package androidx.health.connect.client.permission
 
 import androidx.annotation.IntDef
 import androidx.annotation.RestrictTo
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/HealthDataRequestPermissions.kt
similarity index 87%
rename from health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/permission/HealthDataRequestPermissions.kt
index 148e6bc..c215b9e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/HealthDataRequestPermissions.kt
@@ -13,22 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.permission
+package androidx.health.connect.client.permission
 
 import android.content.Context
 import android.content.Intent
 import androidx.activity.result.contract.ActivityResultContract
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.HealthDataClient.Companion.DEFAULT_PROVIDER_PACKAGE_NAME
-import androidx.health.data.client.impl.converters.permission.toJetpackPermission
-import androidx.health.data.client.impl.converters.permission.toProtoPermission
+import androidx.health.connect.client.HealthConnectClient.Companion.DEFAULT_PROVIDER_PACKAGE_NAME
+import androidx.health.connect.client.impl.converters.permission.toJetpackPermission
+import androidx.health.connect.client.impl.converters.permission.toProtoPermission
 import androidx.health.platform.client.permission.Permission as ProtoPermission
 import androidx.health.platform.client.service.HealthDataServiceConstants.ACTION_REQUEST_PERMISSIONS
 import androidx.health.platform.client.service.HealthDataServiceConstants.KEY_GRANTED_PERMISSIONS_JETPACK
 import androidx.health.platform.client.service.HealthDataServiceConstants.KEY_REQUESTED_PERMISSIONS_JETPACK
 
 /**
- * An [ActivityResultContract] to request Health Data permissions.
+ * An [ActivityResultContract] to request Health Connect permissions.
  *
  * @param providerPackageName Optional provider package name for the backing implementation of
  * choice.
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/permission/Permission.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/Permission.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/permission/Permission.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/permission/Permission.kt
index 49c0193..bf42e71 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/permission/Permission.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/Permission.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.permission
+package androidx.health.connect.client.permission
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 import kotlin.reflect.KClass
 
 /**
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/permission/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/permission/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/permission/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/permission/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActiveCaloriesBurned.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveCaloriesBurned.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActiveCaloriesBurned.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveCaloriesBurned.kt
index c26a4d6..cb4f524 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActiveCaloriesBurned.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveCaloriesBurned.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEvent.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEvent.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEvent.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEvent.kt
index 1e4acfb..1819cf8 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEvent.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEvent.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEventTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEventTypes.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEventTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEventTypes.kt
index 3ec8d8c..3e6a5cb 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityEventTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityEventTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityLap.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityLap.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityLap.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityLap.kt
index 956fdb3..4794730 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityLap.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityLap.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivitySession.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivitySession.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActivitySession.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivitySession.kt
index ad2a5b8..57282f2 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivitySession.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivitySession.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityTypes.kt
similarity index 99%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityTypes.kt
index c51ac08..185b2f3 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActivityTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BasalBodyTemperature.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperature.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BasalBodyTemperature.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperature.kt
index 4d1fa5c..9fdf165 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BasalBodyTemperature.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperature.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BasalMetabolicRate.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalMetabolicRate.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BasalMetabolicRate.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalMetabolicRate.kt
index adf5806..5220c57 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BasalMetabolicRate.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalMetabolicRate.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodGlucose.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodGlucose.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BloodGlucose.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodGlucose.kt
index ac4e53d..bd8b5e7 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodGlucose.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodGlucose.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressure.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressure.kt
similarity index 93%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressure.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressure.kt
index bd49bfd..32361fe 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressure.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressure.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -80,32 +80,32 @@
 
     companion object {
         /** Metric identifier to retrieve average systolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_SYSTOLIC_AVG: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "avg", "systolic")
 
         /** Metric identifier to retrieve minimum systolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_SYSTOLIC_MIN: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "min", "systolic")
 
         /** Metric identifier to retrieve maximum systolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_SYSTOLIC_MAX: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "max", "systolic")
 
         /** Metric identifier to retrieve average diastolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_DIASTOLIC_AVG: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "avg", "diastolic")
 
         /** Metric identifier to retrieve minimum diastolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_DIASTOLIC_MIN: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "min", "diastolic")
 
         /** Metric identifier to retrieve maximum diastolic from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val BLOOD_PRESSURE_DIASTOLIC_MAX: DoubleAggregateMetric =
             DoubleAggregateMetric("BloodPressure", "max", "diastolic")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressureMeasurementLocations.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressureMeasurementLocations.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressureMeasurementLocations.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressureMeasurementLocations.kt
index b9b9d6e..ac2b63d 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BloodPressureMeasurementLocations.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BloodPressureMeasurementLocations.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.StringDef
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyFat.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFat.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BodyFat.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFat.kt
index 86d315b..c74a861 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyFat.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFat.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyPositions.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyPositions.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BodyPositions.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyPositions.kt
index 76a9e6c..03b1882 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyPositions.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyPositions.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.StringDef
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperature.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperature.kt
index a7dc556..e77344c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperature.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureMeasurementLocations.kt
similarity index 97%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureMeasurementLocations.kt
index 707ad7f..32eca43 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureMeasurementLocations.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyWaterMass.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyWaterMass.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BodyWaterMass.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyWaterMass.kt
index befc04e..a37b647 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyWaterMass.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyWaterMass.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BoneMass.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BoneMass.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/BoneMass.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/BoneMass.kt
index 5b26c0e..02462b7 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BoneMass.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BoneMass.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalDilations.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalDilations.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalDilations.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalDilations.kt
index 7002953..41c3b89 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalDilations.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalDilations.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalFirmnesses.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalFirmnesses.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalFirmnesses.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalFirmnesses.kt
index 4168585..55b714e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalFirmnesses.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalFirmnesses.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucus.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucus.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucus.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucus.kt
index f48bb39..c6476e3 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucus.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucus.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusAmounts.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusAmounts.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusAmounts.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusAmounts.kt
index f5ab667..4f6caa5 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusAmounts.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusAmounts.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusTextures.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusTextures.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusTextures.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusTextures.kt
index aead46d..d5173dd5 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalMucusTextures.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalMucusTextures.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPosition.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPosition.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPosition.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPosition.kt
index dd89502..fd0ef33 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPosition.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPosition.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPositionValues.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPositionValues.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPositionValues.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPositionValues.kt
index 5ca0f16..9560f97 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CervicalPositionValues.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CervicalPositionValues.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/CyclingPedalingCadence.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CyclingPedalingCadence.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/CyclingPedalingCadence.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/CyclingPedalingCadence.kt
index b25059d..a66cf182 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/CyclingPedalingCadence.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/CyclingPedalingCadence.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Distance.kt
similarity index 93%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Distance.kt
index 8cbb3ea..d3d8d63 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Distance.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -65,7 +65,7 @@
 
     internal companion object {
         /** Metric identifier to retrieve total distance from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val DISTANCE_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("Distance", "total", "distance")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ElevationGained.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/ElevationGained.kt
index f5886d14..6a26e81 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ElevationGained.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -56,7 +56,7 @@
 
     internal companion object {
         /** Metric identifier to retrieve total elevation gained from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val ELEVATION_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("ElevationGained", "total", "elevation")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/FloorsClimbed.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/FloorsClimbed.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/FloorsClimbed.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/FloorsClimbed.kt
index 585f62f..5b16ebb 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/FloorsClimbed.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/FloorsClimbed.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -58,7 +58,7 @@
 
     companion object {
         /** Metric identifier to retrieve total floors climbed from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val DISTANCE_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("FloorsClimbed", "total", "floors")
     }
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateSeries.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateSeries.kt
new file mode 100644
index 0000000..d1f1827
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateSeries.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.connect.client.records
+
+import androidx.annotation.RestrictTo
+import androidx.health.connect.client.aggregate.LongAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
+import java.time.Instant
+import java.time.ZoneOffset
+
+/** Captures the user's heart rate. Each record represents a series of measurements. */
+@RestrictTo(RestrictTo.Scope.LIBRARY) // Will be made public after API reviews
+public class HeartRateSeries(
+    override val startTime: Instant,
+    override val startZoneOffset: ZoneOffset?,
+    override val endTime: Instant,
+    override val endZoneOffset: ZoneOffset?,
+    override val samples: List<HeartRate>,
+    override val metadata: Metadata = Metadata.EMPTY,
+) : SeriesRecord<HeartRate> {
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is HeartRateSeries) return false
+
+        if (startTime != other.startTime) return false
+        if (startZoneOffset != other.startZoneOffset) return false
+        if (endTime != other.endTime) return false
+        if (endZoneOffset != other.endZoneOffset) return false
+        if (samples != other.samples) return false
+        if (metadata != other.metadata) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        var result = startTime.hashCode()
+        result = 31 * result + (startZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + endTime.hashCode()
+        result = 31 * result + (endZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + samples.hashCode()
+        result = 31 * result + metadata.hashCode()
+        return result
+    }
+
+    internal companion object {
+        /** Metric identifier to retrieve average heart rate from [AggregateDataRow]. */
+        @JvmField
+        internal val BPM_AVG: LongAggregateMetric = LongAggregateMetric("HeartRate", "avg", "bpm")
+
+        /** Metric identifier to retrieve minimum heart rate from [AggregateDataRow]. */
+        @JvmField
+        internal val BPM_MIN: LongAggregateMetric = LongAggregateMetric("HeartRate", "min", "bpm")
+
+        /** Metric identifier to retrieve maximum heart rate from [AggregateDataRow]. */
+        @JvmField
+        internal val BPM_MAX: LongAggregateMetric = LongAggregateMetric("HeartRate", "max", "bpm")
+    }
+}
+
+/**
+ * Represents a single measurement of the heart rate.
+ *
+ * @param beatsPerMinute Heart beats per minute. Validation range: 1-300.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY) // Will be made public after API reviews
+public class HeartRate(
+    val time: Instant,
+    val beatsPerMinute: Long,
+) {
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is HeartRate) return false
+
+        if (time != other.time) return false
+        if (beatsPerMinute != other.beatsPerMinute) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        var result = time.hashCode()
+        result = 31 * result + beatsPerMinute.hashCode()
+        return result
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityDifferentialIndex.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityDifferentialIndex.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityDifferentialIndex.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityDifferentialIndex.kt
index 9ef4404..a762ef2 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityDifferentialIndex.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityDifferentialIndex.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityRmssd.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityRmssd.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityRmssd.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityRmssd.kt
index 7d6ed10..c053a57 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityRmssd.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityRmssd.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityS.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityS.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityS.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityS.kt
index 986def2..3f0864b 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityS.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityS.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySd2.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySd2.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySd2.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySd2.kt
index 2e68c95..bb2ede8 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySd2.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySd2.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdann.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdann.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdann.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdann.kt
index ab0e8c4..0c43270 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdann.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdann.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnn.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnn.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnn.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnn.kt
index 76181dc..f88c6e8 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnn.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnn.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnnIndex.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnnIndex.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnnIndex.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnnIndex.kt
index 3973853..26e1cf8 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdnnIndex.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdnnIndex.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdsd.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdsd.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdsd.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdsd.kt
index 2389a17..726684a 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilitySdsd.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilitySdsd.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityTinn.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityTinn.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityTinn.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityTinn.kt
index 57bba14..44253d0 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateVariabilityTinn.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HeartRateVariabilityTinn.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Height.kt
similarity index 90%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Height.kt
index 8d9b426..ce2ad32 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Height.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -51,17 +51,17 @@
 
     internal companion object {
         /** Metric identifier to retrieve average height from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val HEIGHT_AVG: DoubleAggregateMetric =
             DoubleAggregateMetric("Height", "avg", "height")
 
         /** Metric identifier to retrieve minimum height from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val HEIGHT_MIN: DoubleAggregateMetric =
             DoubleAggregateMetric("Height", "min", "height")
 
         /** Metric identifier to retrieve maximum height from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val HEIGHT_MAX: DoubleAggregateMetric =
             DoubleAggregateMetric("Height", "max", "height")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HipCircumference.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/HipCircumference.kt
index e82d523..66742d8 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/HipCircumference.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Hydration.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Hydration.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Hydration.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Hydration.kt
index 0229889..ce53f8e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Hydration.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Hydration.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/InstantaneousRecord.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/InstantaneousRecord.kt
index ef549f0..822b760 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/InstantaneousRecord.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import java.time.Instant
 import java.time.ZoneOffset
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/IntervalRecord.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/IntervalRecord.kt
index 7ead665..7d621df 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/IntervalRecord.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import java.time.Instant
 import java.time.ZoneOffset
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/LeanBodyMass.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/LeanBodyMass.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/LeanBodyMass.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/LeanBodyMass.kt
index d2e730f..a735cd7 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/LeanBodyMass.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/LeanBodyMass.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/MealTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/MealTypes.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/MealTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/MealTypes.kt
index fa49b5f..81e934c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/MealTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/MealTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Menstruation.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Menstruation.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Menstruation.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Menstruation.kt
index 0753441..c9e0125 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Menstruation.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Menstruation.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/MenstruationFlows.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/MenstruationFlows.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/MenstruationFlows.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/MenstruationFlows.kt
index c2a8f3c..f95e66f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/MenstruationFlows.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/MenstruationFlows.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Nutrition.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Nutrition.kt
similarity index 98%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Nutrition.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Nutrition.kt
index 0bd018c..c431f44 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Nutrition.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Nutrition.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTest.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTest.kt
index d98bb8b..02a0e2e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTest.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTestResults.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTestResults.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTestResults.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTestResults.kt
index 236f3f2..5e8fff9 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/OvulationTestResults.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OvulationTestResults.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/OxygenSaturation.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturation.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/OxygenSaturation.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturation.kt
index eebe476..6b76045 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/OxygenSaturation.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturation.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Power.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Power.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Power.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Power.kt
index 5e729bd..7b69957 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Power.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Power.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Record.kt
similarity index 88%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Record.kt
index ba8099d..db2cc2f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Record.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 
 /** Common interface shared by readable or writable records. */
 public interface Record {
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/RelationToMeals.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RelationToMeals.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/RelationToMeals.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/RelationToMeals.kt
index 67b4930..94b4156 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/RelationToMeals.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RelationToMeals.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Repetitions.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Repetitions.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Repetitions.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Repetitions.kt
index efb033c..da712fd 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Repetitions.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Repetitions.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/RespiratoryRate.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RespiratoryRate.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/RespiratoryRate.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/RespiratoryRate.kt
index ed3c6d5..ddfea29 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/RespiratoryRate.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RespiratoryRate.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/RestingHeartRate.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RestingHeartRate.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/RestingHeartRate.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/RestingHeartRate.kt
index 828e1d9..05601c0 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/RestingHeartRate.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/RestingHeartRate.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SeriesRecord.kt
similarity index 70%
copy from health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
copy to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SeriesRecord.kt
index aa65dc9..9fb8ee6 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/changes/Change.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SeriesRecord.kt
@@ -13,13 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.changes
+package androidx.health.connect.client.records
 
-/**
- * Abstraction to represent a change to Android Health Platform.
- *
- * @see androidx.health.data.client.response.ChangesResponse
- * @see UpsertionChange
- * @see DeletionChange
- */
-interface Change
+/** A record that contains a series of measurements. */
+// Consider exposing this one and other similar interfaces!
+internal interface SeriesRecord<out T : Any> : IntervalRecord {
+
+    val samples: List<T>
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivity.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivity.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivity.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivity.kt
index 565cceb..512c35b 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivity.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivity.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivityProtections.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivityProtections.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivityProtections.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivityProtections.kt
index bef5417..f495471 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SexualActivityProtections.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SexualActivityProtections.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepSession.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepSession.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SleepSession.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepSession.kt
index 43c3dc8..043531ee 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepSession.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepSession.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStage.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStage.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStage.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStage.kt
index e257212..e409064 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStage.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStage.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStageTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStageTypes.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStageTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStageTypes.kt
index 909b48f..de32752 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SleepStageTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SleepStageTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SpecimenSources.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpecimenSources.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SpecimenSources.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpecimenSources.kt
index 0e34611..a24ef839 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SpecimenSources.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpecimenSources.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Speed.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Speed.kt
similarity index 91%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Speed.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Speed.kt
index f9e17dc..b36d366 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Speed.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Speed.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -57,15 +57,15 @@
 
     companion object {
         /** Metric identifier to retrieve average speed from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val SPEED_AVG: DoubleAggregateMetric = DoubleAggregateMetric("Speed", "avg", "speed")
 
         /** Metric identifier to retrieve minimum speed from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val SPEED_MIN: DoubleAggregateMetric = DoubleAggregateMetric("Speed", "min", "speed")
 
         /** Metric identifier to retrieve maximum speed from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val SPEED_MAX: DoubleAggregateMetric = DoubleAggregateMetric("Speed", "max", "speed")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Steps.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Steps.kt
index 18376eb..0028d35 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Steps.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.aggregate.LongAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.LongAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -64,7 +64,7 @@
 
     internal companion object {
         /** Metric identifier to retrieve total steps count from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val STEPS_COUNT_TOTAL: LongAggregateMetric =
             LongAggregateMetric("Steps", "total", "count")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/StepsCadence.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/StepsCadence.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/StepsCadence.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/StepsCadence.kt
index b51799a..894619e 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/StepsCadence.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/StepsCadence.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingStrokes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingStrokes.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingStrokes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingStrokes.kt
index 6e20230..2675b05 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingStrokes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingStrokes.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingTypes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingTypes.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingTypes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingTypes.kt
index be332f1..15225a1 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/SwimmingTypes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SwimmingTypes.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalCaloriesBurned.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalCaloriesBurned.kt
index dce8edd..9056e1b 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalCaloriesBurned.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -61,7 +61,7 @@
 
     companion object {
         /** Metric identifier to retrieve total energy from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         val ENERGY_BURNED_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("TotalEnergyBurned", "total", "energy")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalEnergyBurned.kt
similarity index 89%
copy from health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt
copy to health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalEnergyBurned.kt
index dce8edd..ad463e4 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/TotalCaloriesBurned.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalEnergyBurned.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -26,7 +26,7 @@
  * Each record represents the total kilocalories burned over a time interval.
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
-public class TotalCaloriesBurned(
+public class TotalEnergyBurned(
     /** Energy in kilocalories. Required field. Valid range: 0-1000000. */
     public val energyKcal: Double,
     override val startTime: Instant,
@@ -37,7 +37,7 @@
 ) : IntervalRecord {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
-        if (other !is TotalCaloriesBurned) return false
+        if (other !is TotalEnergyBurned) return false
 
         if (energyKcal != other.energyKcal) return false
         if (startTime != other.startTime) return false
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2Max.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2Max.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2Max.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2Max.kt
index b215fcf..327700d 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2Max.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2Max.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2MaxMeasurementMethods.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2MaxMeasurementMethods.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2MaxMeasurementMethods.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2MaxMeasurementMethods.kt
index 92943ac..2e42004 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Vo2MaxMeasurementMethods.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Vo2MaxMeasurementMethods.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.StringDef
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/WaistCircumference.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/WaistCircumference.kt
similarity index 94%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/WaistCircumference.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/WaistCircumference.kt
index 9b60dd2..c3ab62f3 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/WaistCircumference.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/WaistCircumference.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Weight.kt
similarity index 90%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/Weight.kt
index 244fb36..adb6b53 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/Weight.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
-import androidx.health.data.client.aggregate.DoubleAggregateMetric
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.aggregate.DoubleAggregateMetric
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -51,17 +51,17 @@
 
     internal companion object {
         /** Metric identifier to retrieve average weight from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val WEIGHT_AVG: DoubleAggregateMetric =
             DoubleAggregateMetric("Weight", "avg", "weight")
 
         /** Metric identifier to retrieve minimum weight from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val WEIGHT_MIN: DoubleAggregateMetric =
             DoubleAggregateMetric("Weight", "min", "weight")
 
         /** Metric identifier to retrieve maximum weight from [AggregateDataRow]. */
-        @JvmStatic
+        @JvmField
         internal val WEIGHT_MAX: DoubleAggregateMetric =
             DoubleAggregateMetric("Weight", "max", "weight")
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/WheelchairPushes.kt
similarity index 95%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/WheelchairPushes.kt
index 000cd1b..ca85d18 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/WheelchairPushes.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.records
+package androidx.health.connect.client.records
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
+import androidx.health.connect.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/package-info.java b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/data/client/records/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/records/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByDurationRequest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByDurationRequest.kt
similarity index 86%
rename from health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByDurationRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByDurationRequest.kt
index a1552c8..4557844 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByDurationRequest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByDurationRequest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.AggregateMetric
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.time.TimeRangeFilter
 import java.time.Duration
 
 /**
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByPeriodRequest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByPeriodRequest.kt
similarity index 86%
rename from health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByPeriodRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByPeriodRequest.kt
index 9084849..27ffee4 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateGroupByPeriodRequest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateGroupByPeriodRequest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.AggregateMetric
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.time.TimeRangeFilter
 import java.time.Period
 
 /**
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateRequest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateRequest.kt
similarity index 84%
rename from health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateRequest.kt
index 895e1d2..2f895e2 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/request/AggregateRequest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/AggregateRequest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.AggregateMetric
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.time.TimeRangeFilter
 
 /**
  * Request object to read aggregations for given [AggregateMetric]s in Android Health Platform.
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/ChangesTokenRequest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/ChangesTokenRequest.kt
similarity index 86%
rename from health/health-data-client/src/main/java/androidx/health/data/client/request/ChangesTokenRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/request/ChangesTokenRequest.kt
index fc469ff..25a92e4 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/request/ChangesTokenRequest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/ChangesTokenRequest.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.records.Record
 import kotlin.reflect.KClass
 
 /**
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/ReadRecordsRequest.kt
similarity index 92%
rename from health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/request/ReadRecordsRequest.kt
index 93d6b51..7c7314f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/request/ReadRecordsRequest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.records.Record
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.time.TimeRangeFilter
 import kotlin.reflect.KClass
 
 /**
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/ChangesResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ChangesResponse.kt
similarity index 93%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/ChangesResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/response/ChangesResponse.kt
index bc06095..386db68 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/ChangesResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ChangesResponse.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.response
+package androidx.health.connect.client.response
 
-import androidx.health.data.client.changes.Change
+import androidx.health.connect.client.changes.Change
 
 /**
  * Response to clients fetching changes.
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/InsertRecordsResponse.kt
similarity index 74%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/response/InsertRecordsResponse.kt
index 3806ef6..3cad7d7 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/InsertRecordsResponse.kt
@@ -13,19 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.response
+package androidx.health.connect.client.response
 
 /**
  * Response to record insertion.
  *
- * @see [HealthDataClient.insertRecord]
+ * @see [HealthConnectClient.insertRecord]
  */
 public class InsertRecordsResponse
 internal constructor(
     /*
      * Contains
-     * [androidx.health.data.client.metadata.Metadata.uid] of inserted [Record] in same order as
-     * passed to [androidx.health.data.client.HealthDataClient.insertRecords].
+     * [androidx.health.connect.client.metadata.Metadata.uid] of inserted [Record] in same order as
+     * passed to [androidx.health.connect.client.HealthDataClient.insertRecords].
      */
     val recordUidsList: List<String>
 )
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordResponse.kt
similarity index 84%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordResponse.kt
index 9aa14b4..52259fd 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordResponse.kt
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.response
+package androidx.health.connect.client.response
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 
 /**
  * Response to record read.
  *
- * @see [HealthDataClient.readRecord]
+ * @see [HealthConnectClient.readRecord]
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class ReadRecordResponse<T : Record> internal constructor(val record: T)
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordsResponse.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordsResponse.kt
similarity index 85%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordsResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordsResponse.kt
index 566d3b2..0565e97 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/ReadRecordsResponse.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/response/ReadRecordsResponse.kt
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.response
+package androidx.health.connect.client.response
 
 import androidx.annotation.RestrictTo
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 
 /**
  * Response to records read.
  *
- * @see [HealthDataClient.readRecords]
+ * @see [HealthConnectClient.readRecords]
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class ReadRecordsResponse<T : Record>
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/time/TimeRangeFilter.kt
similarity index 87%
rename from health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
rename to health/health-connect-client/src/main/java/androidx/health/connect/client/time/TimeRangeFilter.kt
index e9e1d48..5032399 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/time/TimeRangeFilter.kt
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.time
+package androidx.health.connect.client.time
 
-import androidx.health.data.client.records.Record
+import androidx.health.connect.client.records.Record
 import java.time.Instant
 import java.time.LocalDateTime
 
@@ -146,4 +146,25 @@
 
     internal fun isOpenEnded(): Boolean =
         (localStartTime == null || localEndTime == null) && (startTime == null || endTime == null)
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is TimeRangeFilter) return false
+
+        if (startTime != other.startTime) return false
+        if (endTime != other.endTime) return false
+        if (localStartTime != other.localStartTime) return false
+        if (localEndTime != other.localEndTime) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = 0
+        result = 31 * result + (startTime?.hashCode() ?: 0)
+        result = 31 * result + (endTime?.hashCode() ?: 0)
+        result = 31 * result + (localStartTime?.hashCode() ?: 0)
+        result = 31 * result + (localEndTime?.hashCode() ?: 0)
+        return result
+    }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt
similarity index 96%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt
index 5d56706..a9cb225 100644
--- a/health/health-data-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/platform/client/HealthDataAsyncClient.kt
@@ -25,7 +25,7 @@
 /**
  * Interface to access health and fitness records.
  *
- * Like [HealthDataClient] but expose ListenableFuture instead of kotlin coroutines.
+ * Like [HealthConnectClient] but expose ListenableFuture instead of kotlin coroutines.
  */
 interface HealthDataAsyncClient {
     /**
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/HealthDataService.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/HealthDataService.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/HealthDataService.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/HealthDataService.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/SdkConfig.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/SdkConfig.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/changes/ChangesEvent.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/changes/ChangesEvent.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/changes/ChangesEvent.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/changes/ChangesEvent.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/error/ErrorCode.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/error/ErrorCode.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/error/ErrorCode.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/error/ErrorCode.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/error/ErrorStatus.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/error/ErrorStatus.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/error/ErrorStatus.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/error/ErrorStatus.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/AggregateDataCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/AggregateDataCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/AggregateDataCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/AggregateDataCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ClearOnChangesListenerCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ClearOnChangesListenerCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ClearOnChangesListenerCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ClearOnChangesListenerCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/DeleteDataCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/DeleteDataCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/DeleteDataCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/DeleteDataCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/DeleteDataRangeCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/DeleteDataRangeCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/DeleteDataRangeCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/DeleteDataRangeCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetChangesCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetChangesCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetChangesCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetChangesCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetChangesTokenCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetChangesTokenCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetChangesTokenCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetChangesTokenCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetGrantedPermissionsCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetGrantedPermissionsCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/GetGrantedPermissionsCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/GetGrantedPermissionsCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/InsertDataCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/InsertDataCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/InsertDataCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/InsertDataCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/OnChangesListenerProxy.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/OnChangesListenerProxy.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/OnChangesListenerProxy.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/OnChangesListenerProxy.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ReadDataCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ReadDataCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ReadDataCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ReadDataCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ReadDataRangeCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ReadDataRangeCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ReadDataRangeCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ReadDataRangeCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/RevokeAllPermissionsCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/RevokeAllPermissionsCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/RevokeAllPermissionsCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/RevokeAllPermissionsCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClient.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClient.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClient.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClient.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/SetOnChangesListenerCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/SetOnChangesListenerCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/SetOnChangesListenerCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/SetOnChangesListenerCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/UpdateDataCallback.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/UpdateDataCallback.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/UpdateDataCallback.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/UpdateDataCallback.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/error/ErrorStatusConverter.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/error/ErrorStatusConverter.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/error/ErrorStatusConverter.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/error/ErrorStatusConverter.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/error/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/internal/ProviderConnectionManager.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/internal/ProviderConnectionManager.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/internal/ProviderConnectionManager.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/internal/ProviderConnectionManager.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ApiVersionException.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/Client.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ClientConfiguration.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteFutureOperation.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/RemoteOperation.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/ServiceOperation.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/BaseQueueOperation.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionConfiguration.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ConnectionManager.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/DefaultExecutionTracker.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ExecutionTracker.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ListenerKey.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/QueueOperation.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnection.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/ipc/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/ForegroundStateChecker.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/ForegroundStateChecker.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/ForegroundStateChecker.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/permission/foregroundstate/ForegroundStateChecker.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManager.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManager.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManager.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManager.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkService.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkService.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkService.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkService.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImpl.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImpl.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImpl.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImpl.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/permission/Permission.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/permission/Permission.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/permission/Permission.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/permission/Permission.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/permission/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/permission/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/permission/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/proto/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/proto/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/proto/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/AggregateDataRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/AggregateDataRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/AggregateDataRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/AggregateDataRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/DeleteDataRangeRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/DeleteDataRangeRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/DeleteDataRangeRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/DeleteDataRangeRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/DeleteDataRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/DeleteDataRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/DeleteDataRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/DeleteDataRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/GetChangesRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/GetChangesRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/GetChangesRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/GetChangesRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/GetChangesTokenRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/GetChangesTokenRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/GetChangesTokenRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/GetChangesTokenRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/ReadDataRangeRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/ReadDataRangeRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/ReadDataRangeRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/ReadDataRangeRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/ReadDataRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/ReadDataRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/ReadDataRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/ReadDataRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/RequestContext.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/RequestContext.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/RequestContext.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/RequestContext.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/UpsertDataRequest.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/UpsertDataRequest.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/UpsertDataRequest.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/UpsertDataRequest.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/request/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/request/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/request/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/request/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/AggregateDataResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/AggregateDataResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/AggregateDataResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/AggregateDataResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/GetChangesResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/GetChangesResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/GetChangesResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/GetChangesResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/GetChangesTokenResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/GetChangesTokenResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/GetChangesTokenResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/GetChangesTokenResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/InsertDataResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/InsertDataResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/InsertDataResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/InsertDataResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/ReadDataRangeResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/ReadDataRangeResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/ReadDataRangeResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/ReadDataRangeResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/ReadDataResponse.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/ReadDataResponse.kt
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/ReadDataResponse.kt
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/ReadDataResponse.kt
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/response/package-info.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/response/package-info.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/response/package-info.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/response/package-info.java
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java b/health/health-connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
similarity index 100%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
rename to health/health-connect-client/src/main/java/androidx/health/platform/client/service/HealthDataServiceConstants.java
diff --git a/health/health-data-client/src/main/proto/change.proto b/health/health-connect-client/src/main/proto/change.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/change.proto
rename to health/health-connect-client/src/main/proto/change.proto
diff --git a/health/health-data-client/src/main/proto/data.proto b/health/health-connect-client/src/main/proto/data.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/data.proto
rename to health/health-connect-client/src/main/proto/data.proto
diff --git a/health/health-data-client/src/main/proto/error.proto b/health/health-connect-client/src/main/proto/error.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/error.proto
rename to health/health-connect-client/src/main/proto/error.proto
diff --git a/health/health-data-client/src/main/proto/permission.proto b/health/health-connect-client/src/main/proto/permission.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/permission.proto
rename to health/health-connect-client/src/main/proto/permission.proto
diff --git a/health/health-data-client/src/main/proto/request.proto b/health/health-connect-client/src/main/proto/request.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/request.proto
rename to health/health-connect-client/src/main/proto/request.proto
diff --git a/health/health-data-client/src/main/proto/response.proto b/health/health-connect-client/src/main/proto/response.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/response.proto
rename to health/health-connect-client/src/main/proto/response.proto
diff --git a/health/health-data-client/src/main/proto/time.proto b/health/health-connect-client/src/main/proto/time.proto
similarity index 100%
rename from health/health-data-client/src/main/proto/time.proto
rename to health/health-connect-client/src/main/proto/time.proto
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/HealthDataClientTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
similarity index 75%
rename from health/health-data-client/src/test/java/androidx/health/data/client/HealthDataClientTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
index 201b5ed..ec02294 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/HealthDataClientTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client
+package androidx.health.connect.client
 
 import android.content.Context
 import android.content.pm.ApplicationInfo
@@ -34,7 +34,7 @@
 private const val PROVIDER_PACKAGE_NAME = "com.example.fake.provider"
 
 @RunWith(AndroidJUnit4::class)
-class HealthDataClientTest {
+class HealthConnectClientTest {
 
     private lateinit var context: Context
 
@@ -47,34 +47,37 @@
     fun noBackingImplementation_unavailable() {
         val packageManager = context.packageManager
         Shadows.shadowOf(packageManager).removePackage(PROVIDER_PACKAGE_NAME)
-        assertThat(HealthDataClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThat(HealthConnectClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME)))
+            .isFalse()
         assertThrows(IllegalStateException::class.java) {
-            HealthDataClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
+            HealthConnectClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
         }
     }
 
     @Test
     fun backingImplementation_notEnabled_unavailable() {
         installPackage(context, PROVIDER_PACKAGE_NAME, enabled = false)
-        assertThat(HealthDataClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThat(HealthConnectClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME)))
+            .isFalse()
         assertThrows(IllegalStateException::class.java) {
-            HealthDataClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
+            HealthConnectClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
         }
     }
 
     @Test
     fun backingImplementation_enabled_isAvailable() {
         installPackage(context, PROVIDER_PACKAGE_NAME, enabled = true)
-        assertThat(HealthDataClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isTrue()
-        HealthDataClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isTrue()
+        HealthConnectClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
     }
 
     @Test
     @Config(sdk = [Build.VERSION_CODES.O_MR1])
     fun sdkVersionTooOld_unavailable() {
-        assertThat(HealthDataClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThat(HealthConnectClient.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME)))
+            .isFalse()
         assertThrows(UnsupportedOperationException::class.java) {
-            HealthDataClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
+            HealthConnectClient.getOrCreate(context, listOf(PROVIDER_PACKAGE_NAME))
         }
     }
 
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriodTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriodTest.kt
similarity index 97%
rename from health/health-data-client/src/test/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriodTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriodTest.kt
index 94fe449..f658a92 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/aggregate/AggregateDataRowGroupByPeriodTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/aggregate/AggregateDataRowGroupByPeriodTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.aggregate
+package androidx.health.connect.client.aggregate
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import java.lang.IllegalArgumentException
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/HealthConnectClientImplTest.kt
similarity index 91%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/HealthConnectClientImplTest.kt
index fb98adf..c0c5fae 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/HealthConnectClientImplTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl
+package androidx.health.connect.client.impl
 
 import android.app.Application
 import android.content.ComponentName
@@ -22,30 +22,30 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageInfo
 import android.os.Looper
-import androidx.health.data.client.HealthDataClient
-import androidx.health.data.client.aggregate.AggregateDataRow
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByDuration
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByPeriod
-import androidx.health.data.client.changes.DeletionChange
-import androidx.health.data.client.changes.UpsertionChange
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.metadata.Device
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.data.client.permission.AccessTypes
-import androidx.health.data.client.permission.Permission
-import androidx.health.data.client.records.ActiveCaloriesBurned
-import androidx.health.data.client.records.Nutrition
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.records.Steps.Companion.STEPS_COUNT_TOTAL
-import androidx.health.data.client.records.Weight
-import androidx.health.data.client.request.AggregateGroupByDurationRequest
-import androidx.health.data.client.request.AggregateGroupByPeriodRequest
-import androidx.health.data.client.request.AggregateRequest
-import androidx.health.data.client.request.ChangesTokenRequest
-import androidx.health.data.client.request.ReadRecordsRequest
-import androidx.health.data.client.response.ReadRecordResponse
-import androidx.health.data.client.response.ReadRecordsResponse
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.aggregate.AggregateDataRow
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByDuration
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByPeriod
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.metadata.Device
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.connect.client.permission.AccessTypes
+import androidx.health.connect.client.permission.Permission
+import androidx.health.connect.client.records.ActiveCaloriesBurned
+import androidx.health.connect.client.records.Nutrition
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.records.Steps.Companion.STEPS_COUNT_TOTAL
+import androidx.health.connect.client.records.Weight
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.response.ReadRecordResponse
+import androidx.health.connect.client.response.ReadRecordsResponse
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.impl.ServiceBackedHealthDataClient
 import androidx.health.platform.client.impl.error.errorCodeExceptionMap
 import androidx.health.platform.client.impl.ipc.ClientConfiguration
@@ -86,7 +86,7 @@
 private const val PROVIDER_PACKAGE_NAME = "com.google.fake.provider"
 
 private val API_METHOD_LIST =
-    listOf<suspend HealthDataClient.() -> Unit>(
+    listOf<suspend HealthConnectClient.() -> Unit>(
         { getGrantedPermissions(setOf()) },
         { insertRecords(listOf()) },
         { updateRecords(listOf()) },
@@ -122,9 +122,9 @@
 @Suppress("GoodTime") // Safe to use in test setup
 @RunWith(AndroidJUnit4::class)
 @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
-class HealthDataClientImplTest {
+class HealthConnectClientImplTest {
 
-    private lateinit var healthDataClient: HealthDataClientImpl
+    private lateinit var healthConnectClient: HealthConnectClientImpl
     private lateinit var fakeAhpServiceStub: FakeHealthDataService
 
     @Before
@@ -132,8 +132,8 @@
         val clientConfig =
             ClientConfiguration("FakeAHPProvider", PROVIDER_PACKAGE_NAME, "FakeProvider")
 
-        healthDataClient =
-            HealthDataClientImpl(
+        healthConnectClient =
+            HealthConnectClientImpl(
                 ServiceBackedHealthDataClient(
                     ApplicationProvider.getApplicationContext(),
                     clientConfig,
@@ -169,7 +169,7 @@
             val responseList = mutableListOf<Deferred<Any>>()
             for (method in API_METHOD_LIST) {
                 responseList.add(
-                    async { assertFailsWith(error.value) { healthDataClient.method() } }
+                    async { assertFailsWith(error.value) { healthConnectClient.method() } }
                 )
             }
             advanceUntilIdle()
@@ -183,7 +183,7 @@
     @Test
     fun getGrantedPermissions_none() = runTest {
         val deferred = async {
-            healthDataClient.getGrantedPermissions(
+            healthConnectClient.getGrantedPermissions(
                 setOf(Permission.create<Steps>(AccessTypes.READ))
             )
         }
@@ -206,7 +206,7 @@
             )
         )
         val deferred = async {
-            healthDataClient.getGrantedPermissions(
+            healthConnectClient.getGrantedPermissions(
                 setOf(Permission.create<Steps>(AccessTypes.READ))
             )
         }
@@ -222,7 +222,7 @@
     fun insertRecords_steps() = runTest {
         fakeAhpServiceStub.insertDataResponse = InsertDataResponse(listOf("0"))
         val deferred = async {
-            healthDataClient.insertRecords(
+            healthConnectClient.insertRecords(
                 listOf(
                     Steps(
                         count = 100,
@@ -255,7 +255,7 @@
     fun insertRecords_weight() = runTest {
         fakeAhpServiceStub.insertDataResponse = InsertDataResponse(listOf("0"))
         val deferred = async {
-            healthDataClient.insertRecords(
+            healthConnectClient.insertRecords(
                 listOf(
                     Weight(
                         weightKg = 45.8,
@@ -285,7 +285,7 @@
     fun insertRecords_nutrition() = runTest {
         fakeAhpServiceStub.insertDataResponse = InsertDataResponse(listOf("0"))
         val deferred = async {
-            healthDataClient.insertRecords(
+            healthConnectClient.insertRecords(
                 listOf(
                     Nutrition(
                         vitaminEGrams = 10.0,
@@ -335,7 +335,7 @@
                     .build()
             )
         val deferred = async {
-            healthDataClient.readRecord(
+            healthConnectClient.readRecord(
                 Steps::class,
                 uid = "testUid",
             )
@@ -392,7 +392,7 @@
                     .build()
             )
         val deferred = async {
-            healthDataClient.readRecords(
+            healthConnectClient.readRecords(
                 ReadRecordsRequest(
                     Steps::class,
                     timeRangeFilter = TimeRangeFilter.before(endTime = Instant.ofEpochMilli(7890L)),
@@ -435,7 +435,7 @@
     @Test
     fun deleteRecordsById_steps() = runTest {
         val deferred = async {
-            healthDataClient.deleteRecords(Steps::class, listOf("myUid"), listOf("myClientId"))
+            healthConnectClient.deleteRecords(Steps::class, listOf("myUid"), listOf("myClientId"))
         }
 
         advanceUntilIdle()
@@ -462,7 +462,7 @@
     @Test
     fun deleteRecordsByRange_steps() = runTest {
         val deferred = async {
-            healthDataClient.deleteRecords(
+            healthConnectClient.deleteRecords(
                 Steps::class,
                 timeRangeFilter = TimeRangeFilter.before(endTime = Instant.ofEpochMilli(7890L)),
             )
@@ -484,7 +484,7 @@
     @Test
     fun updateRecords_steps() = runTest {
         val deferred = async {
-            healthDataClient.updateRecords(
+            healthConnectClient.updateRecords(
                 listOf(
                     Steps(
                         count = 100,
@@ -531,7 +531,7 @@
         val deferred = async {
             val startTime = Instant.ofEpochMilli(1234)
             val endTime = Instant.ofEpochMilli(4567)
-            healthDataClient.aggregate(
+            healthConnectClient.aggregate(
                 AggregateRequest(
                     setOf(Steps.STEPS_COUNT_TOTAL),
                     TimeRangeFilter.between(startTime, endTime)
@@ -595,7 +595,7 @@
         val deferred = async {
             val startTime = Instant.ofEpochMilli(1234)
             val endTime = Instant.ofEpochMilli(4567)
-            healthDataClient.aggregateGroupByDuration(
+            healthConnectClient.aggregateGroupByDuration(
                 AggregateGroupByDurationRequest(
                     setOf(STEPS_COUNT_TOTAL),
                     TimeRangeFilter.between(startTime, endTime),
@@ -668,7 +668,7 @@
         val deferred = async {
             val startTime = LocalDateTime.parse("2022-02-11T20:22:02")
             val endTime = LocalDateTime.parse("2022-02-22T20:22:02")
-            healthDataClient.aggregateGroupByPeriod(
+            healthConnectClient.aggregateGroupByPeriod(
                 AggregateGroupByPeriodRequest(
                     setOf(STEPS_COUNT_TOTAL),
                     TimeRangeFilter.between(startTime, endTime),
@@ -721,7 +721,7 @@
                     .build()
             )
         val deferred = async {
-            healthDataClient.getChangesToken(ChangesTokenRequest(setOf(Steps::class)))
+            healthConnectClient.getChangesToken(ChangesTokenRequest(setOf(Steps::class)))
         }
 
         advanceUntilIdle()
@@ -762,7 +762,7 @@
                     .setChangesTokenExpired(false)
                     .build()
             )
-        val deferred = async { healthDataClient.getChanges("steps_changes_token") }
+        val deferred = async { healthConnectClient.getChanges("steps_changes_token") }
 
         advanceUntilIdle()
         waitForMainLooperIdle()
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt
similarity index 95%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt
index f1b3512..43ea9ce 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateDataRowConverterTest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.aggregate
+package androidx.health.connect.client.impl.converters.aggregate
 
-import androidx.health.data.client.aggregate.AggregateDataRow
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByDuration
-import androidx.health.data.client.aggregate.AggregateDataRowGroupByPeriod
-import androidx.health.data.client.metadata.DataOrigin
+import androidx.health.connect.client.aggregate.AggregateDataRow
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByDuration
+import androidx.health.connect.client.aggregate.AggregateDataRowGroupByPeriod
+import androidx.health.connect.client.metadata.DataOrigin
 import androidx.health.platform.client.proto.DataProto
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricConverterTest.kt
similarity index 88%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricConverterTest.kt
index 0096887..dac85c1 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/aggregate/AggregateMetricConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/aggregate/AggregateMetricConverterTest.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.aggregate
+package androidx.health.connect.client.impl.converters.aggregate
 
-import androidx.health.data.client.aggregate.DurationAggregateMetric
-import androidx.health.data.client.records.Distance
-import androidx.health.data.client.records.Steps
+import androidx.health.connect.client.aggregate.DurationAggregateMetric
+import androidx.health.connect.client.records.Distance
+import androidx.health.connect.client.records.Steps
 import androidx.health.platform.client.proto.RequestProto
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
similarity index 80%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
index 1f8ea4c..24f4b37 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
@@ -13,72 +13,74 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.metadata.Device
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.data.client.records.ActiveCaloriesBurned
-import androidx.health.data.client.records.ActivityEvent
-import androidx.health.data.client.records.ActivityEventTypes
-import androidx.health.data.client.records.ActivityLap
-import androidx.health.data.client.records.ActivitySession
-import androidx.health.data.client.records.ActivityTypes
-import androidx.health.data.client.records.BasalBodyTemperature
-import androidx.health.data.client.records.BasalMetabolicRate
-import androidx.health.data.client.records.BloodGlucose
-import androidx.health.data.client.records.BloodPressure
-import androidx.health.data.client.records.BodyFat
-import androidx.health.data.client.records.BodyTemperature
-import androidx.health.data.client.records.BodyTemperatureMeasurementLocations
-import androidx.health.data.client.records.BodyWaterMass
-import androidx.health.data.client.records.BoneMass
-import androidx.health.data.client.records.CervicalMucus
-import androidx.health.data.client.records.CervicalMucusAmounts
-import androidx.health.data.client.records.CervicalMucusTextures
-import androidx.health.data.client.records.CervicalPosition
-import androidx.health.data.client.records.CyclingPedalingCadence
-import androidx.health.data.client.records.Distance
-import androidx.health.data.client.records.ElevationGained
-import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
-import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
-import androidx.health.data.client.records.HeartRateVariabilityRmssd
-import androidx.health.data.client.records.HeartRateVariabilityS
-import androidx.health.data.client.records.HeartRateVariabilitySd2
-import androidx.health.data.client.records.HeartRateVariabilitySdann
-import androidx.health.data.client.records.HeartRateVariabilitySdnn
-import androidx.health.data.client.records.HeartRateVariabilitySdnnIndex
-import androidx.health.data.client.records.HeartRateVariabilitySdsd
-import androidx.health.data.client.records.HeartRateVariabilityTinn
-import androidx.health.data.client.records.Height
-import androidx.health.data.client.records.HipCircumference
-import androidx.health.data.client.records.Hydration
-import androidx.health.data.client.records.LeanBodyMass
-import androidx.health.data.client.records.Menstruation
-import androidx.health.data.client.records.MenstruationFlows
-import androidx.health.data.client.records.Nutrition
-import androidx.health.data.client.records.OvulationTest
-import androidx.health.data.client.records.OvulationTestResults
-import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Power
-import androidx.health.data.client.records.Repetitions
-import androidx.health.data.client.records.RespiratoryRate
-import androidx.health.data.client.records.RestingHeartRate
-import androidx.health.data.client.records.SexualActivity
-import androidx.health.data.client.records.SleepSession
-import androidx.health.data.client.records.SleepStage
-import androidx.health.data.client.records.SleepStageTypes
-import androidx.health.data.client.records.Speed
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.records.StepsCadence
-import androidx.health.data.client.records.SwimmingStrokes
-import androidx.health.data.client.records.SwimmingTypes
-import androidx.health.data.client.records.TotalCaloriesBurned
-import androidx.health.data.client.records.Vo2Max
-import androidx.health.data.client.records.WaistCircumference
-import androidx.health.data.client.records.Weight
-import androidx.health.data.client.records.WheelchairPushes
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.metadata.Device
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.connect.client.records.ActiveCaloriesBurned
+import androidx.health.connect.client.records.ActivityEvent
+import androidx.health.connect.client.records.ActivityEventTypes
+import androidx.health.connect.client.records.ActivityLap
+import androidx.health.connect.client.records.ActivitySession
+import androidx.health.connect.client.records.ActivityTypes
+import androidx.health.connect.client.records.BasalBodyTemperature
+import androidx.health.connect.client.records.BasalMetabolicRate
+import androidx.health.connect.client.records.BloodGlucose
+import androidx.health.connect.client.records.BloodPressure
+import androidx.health.connect.client.records.BodyFat
+import androidx.health.connect.client.records.BodyTemperature
+import androidx.health.connect.client.records.BodyTemperatureMeasurementLocations
+import androidx.health.connect.client.records.BodyWaterMass
+import androidx.health.connect.client.records.BoneMass
+import androidx.health.connect.client.records.CervicalMucus
+import androidx.health.connect.client.records.CervicalMucusAmounts
+import androidx.health.connect.client.records.CervicalMucusTextures
+import androidx.health.connect.client.records.CervicalPosition
+import androidx.health.connect.client.records.CyclingPedalingCadence
+import androidx.health.connect.client.records.Distance
+import androidx.health.connect.client.records.ElevationGained
+import androidx.health.connect.client.records.FloorsClimbed
+import androidx.health.connect.client.records.HeartRate
+import androidx.health.connect.client.records.HeartRateSeries
+import androidx.health.connect.client.records.HeartRateVariabilityDifferentialIndex
+import androidx.health.connect.client.records.HeartRateVariabilityRmssd
+import androidx.health.connect.client.records.HeartRateVariabilityS
+import androidx.health.connect.client.records.HeartRateVariabilitySd2
+import androidx.health.connect.client.records.HeartRateVariabilitySdann
+import androidx.health.connect.client.records.HeartRateVariabilitySdnn
+import androidx.health.connect.client.records.HeartRateVariabilitySdnnIndex
+import androidx.health.connect.client.records.HeartRateVariabilitySdsd
+import androidx.health.connect.client.records.HeartRateVariabilityTinn
+import androidx.health.connect.client.records.Height
+import androidx.health.connect.client.records.HipCircumference
+import androidx.health.connect.client.records.Hydration
+import androidx.health.connect.client.records.LeanBodyMass
+import androidx.health.connect.client.records.Menstruation
+import androidx.health.connect.client.records.MenstruationFlows
+import androidx.health.connect.client.records.Nutrition
+import androidx.health.connect.client.records.OvulationTest
+import androidx.health.connect.client.records.OvulationTestResults
+import androidx.health.connect.client.records.OxygenSaturation
+import androidx.health.connect.client.records.Power
+import androidx.health.connect.client.records.Repetitions
+import androidx.health.connect.client.records.RespiratoryRate
+import androidx.health.connect.client.records.RestingHeartRate
+import androidx.health.connect.client.records.SexualActivity
+import androidx.health.connect.client.records.SleepSession
+import androidx.health.connect.client.records.SleepStage
+import androidx.health.connect.client.records.SleepStageTypes
+import androidx.health.connect.client.records.Speed
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.records.StepsCadence
+import androidx.health.connect.client.records.SwimmingStrokes
+import androidx.health.connect.client.records.SwimmingTypes
+import androidx.health.connect.client.records.TotalCaloriesBurned
+import androidx.health.connect.client.records.TotalEnergyBurned
+import androidx.health.connect.client.records.Vo2Max
+import androidx.health.connect.client.records.WaistCircumference
+import androidx.health.connect.client.records.Weight
+import androidx.health.connect.client.records.WheelchairPushes
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
 import java.time.Instant
@@ -272,13 +274,29 @@
     }
 
     @Test
-    fun testHeartRate() {
+    fun testHeartRateSeries() {
         val data =
-            HeartRate(
-                beatsPerMinute = 1,
-                time = START_TIME,
-                zoneOffset = END_ZONE_OFFSET,
-                metadata = TEST_METADATA
+            HeartRateSeries(
+                startTime = START_TIME,
+                startZoneOffset = START_ZONE_OFFSET,
+                endTime = END_TIME,
+                endZoneOffset = END_ZONE_OFFSET,
+                samples =
+                    listOf(
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 100L,
+                        ),
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 110L,
+                        ),
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 120L,
+                        ),
+                    ),
+                metadata = TEST_METADATA,
             )
 
         assertThat(toRecord(data.toProto())).isEqualTo(data)
@@ -870,6 +888,21 @@
     }
 
     @Test
+    fun testTotalEnergyBurned() {
+        val data =
+            TotalEnergyBurned(
+                energyKcal = 1.0,
+                startTime = START_TIME,
+                startZoneOffset = START_ZONE_OFFSET,
+                endTime = END_TIME,
+                endZoneOffset = END_ZONE_OFFSET,
+                metadata = TEST_METADATA
+            )
+
+        assertThat(toRecord(data.toProto())).isEqualTo(data)
+    }
+
+    @Test
     fun testWheelchairPushes() {
         val data =
             WheelchairPushes(
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/RecordsTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/RecordsTest.kt
similarity index 94%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/RecordsTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/RecordsTest.kt
index d4a1f7a..5964919 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/RecordsTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/RecordsTest.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.records
+package androidx.health.connect.client.impl.converters.records
 
 import androidx.health.platform.client.proto.DataProto
 import androidx.test.ext.junit.runners.AndroidJUnit4
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/request/AggregateRequestConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/request/AggregateRequestConverterTest.kt
similarity index 87%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/request/AggregateRequestConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/request/AggregateRequestConverterTest.kt
index 365ede6..c531d57 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/request/AggregateRequestConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/request/AggregateRequestConverterTest.kt
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.request
+package androidx.health.connect.client.impl.converters.request
 
-import androidx.health.data.client.impl.converters.time.toProto
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.request.AggregateGroupByDurationRequest
-import androidx.health.data.client.request.AggregateGroupByPeriodRequest
-import androidx.health.data.client.request.AggregateRequest
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.impl.converters.time.toProto
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
 import androidx.test.ext.junit.runners.AndroidJUnit4
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/response/ChangesResponseConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/response/ChangesResponseConverterTest.kt
similarity index 90%
rename from health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/response/ChangesResponseConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/response/ChangesResponseConverterTest.kt
index 9ae030b..2919e68 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/response/ChangesResponseConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/response/ChangesResponseConverterTest.kt
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.impl.converters.response
+package androidx.health.connect.client.impl.converters.response
 
-import androidx.health.data.client.changes.DeletionChange
-import androidx.health.data.client.changes.UpsertionChange
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.metadata.Device
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.data.client.records.Steps
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.metadata.DataOrigin
+import androidx.health.connect.client.metadata.Device
+import androidx.health.connect.client.metadata.Metadata
+import androidx.health.connect.client.records.Steps
 import androidx.health.platform.client.proto.ChangeProto
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.ResponseProto
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java b/health/health-connect-client/src/test/java/androidx/health/connect/client/metadata/DeviceTypeTest.java
similarity index 94%
rename from health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/metadata/DeviceTypeTest.java
index a5d6306..b569ab2 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/metadata/DeviceTypeTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.health.data.client.metadata;
+package androidx.health.connect.client.metadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/permission/HealthDataRequestPermissionsTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/permission/HealthDataRequestPermissionsTest.kt
similarity index 93%
rename from health/health-data-client/src/test/java/androidx/health/data/client/permission/HealthDataRequestPermissionsTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/permission/HealthDataRequestPermissionsTest.kt
index 254d50d..33b708c 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/permission/HealthDataRequestPermissionsTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/permission/HealthDataRequestPermissionsTest.kt
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.permission
+package androidx.health.connect.client.permission
 
 import android.content.Context
 import android.content.Intent
-import androidx.health.data.client.HealthDataClient
-import androidx.health.data.client.records.Steps
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.records.Steps
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.PermissionProto
 import androidx.health.platform.client.service.HealthDataServiceConstants
@@ -64,7 +64,7 @@
             )
 
         assertThat(intent.action).isEqualTo("androidx.health.ACTION_REQUEST_PERMISSIONS")
-        assertThat(intent.`package`).isEqualTo(HealthDataClient.DEFAULT_PROVIDER_PACKAGE_NAME)
+        assertThat(intent.`package`).isEqualTo(HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME)
     }
 
     @Test
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/request/ReadRecordsRequestTest.kt
similarity index 95%
rename from health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/connect/client/request/ReadRecordsRequestTest.kt
index 55fa8cb..2a3bd0c 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/request/ReadRecordsRequestTest.kt
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.data.client.request
+package androidx.health.connect.client.request
 
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.connect.client.records.Steps
+import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import java.time.Instant
 import org.junit.Assert.assertEquals
diff --git a/health/health-connect-client/src/test/java/androidx/health/connect/client/time/TimeRangeFilterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/time/TimeRangeFilterTest.kt
new file mode 100644
index 0000000..4b54922
--- /dev/null
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/time/TimeRangeFilterTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.connect.client.time
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import java.time.Instant
+import java.time.LocalDateTime
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNotEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TimeRangeFilterTest {
+
+    @Test
+    fun checksStartTimeBeforeEndTime() {
+        assertFailsWith<IllegalArgumentException> {
+            TimeRangeFilter.between(
+                endTime = Instant.ofEpochMilli(1234L),
+                startTime = Instant.ofEpochMilli(5679L),
+            )
+        }
+        assertFailsWith<IllegalArgumentException> {
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(1234L),
+            )
+        }
+        TimeRangeFilter.between(
+            startTime = Instant.ofEpochMilli(1234L),
+            endTime = Instant.ofEpochMilli(5679L),
+        )
+    }
+
+    @Test
+    fun checksLocalStartTimeBeforeEndTime() {
+        assertFailsWith<IllegalArgumentException> {
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T02:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T01:00:00")
+            )
+        }
+        assertFailsWith<IllegalArgumentException> {
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T02:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            )
+        }
+        TimeRangeFilter.between(
+            startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+            endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+        )
+    }
+
+    @Test
+    fun equals() {
+        assertEquals(
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            ),
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            )
+        )
+        assertEquals(
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            ),
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            )
+        )
+
+        assertNotEquals(
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5678L),
+            ),
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            )
+        )
+        assertNotEquals(
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            ),
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:30:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            )
+        )
+    }
+}
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/error/ErrorStatusTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/error/ErrorStatusTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/error/ErrorStatusTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/error/ErrorStatusTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClientTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClientTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClientTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/ServiceBackedHealthDataClientTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt
similarity index 90%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt
index 8eb9efd..6900f06 100644
--- a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/converters/permission/PermissionConverterTest.kt
@@ -15,11 +15,11 @@
  */
 package androidx.health.platform.client.impl.converters.permission
 
-import androidx.health.data.client.impl.converters.permission.toJetpackPermission
-import androidx.health.data.client.impl.converters.permission.toProtoPermission
-import androidx.health.data.client.permission.AccessTypes
-import androidx.health.data.client.permission.Permission
-import androidx.health.data.client.records.Steps
+import androidx.health.connect.client.impl.converters.permission.toJetpackPermission
+import androidx.health.connect.client.impl.converters.permission.toProtoPermission
+import androidx.health.connect.client.permission.AccessTypes
+import androidx.health.connect.client.permission.Permission
+import androidx.health.connect.client.records.Steps
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.PermissionProto
 import androidx.test.ext.junit.runners.AndroidJUnit4
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnectionTest.java b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnectionTest.java
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnectionTest.java
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/ipc/internal/ServiceConnectionTest.java
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManagerTest.java b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManagerTest.java
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManagerTest.java
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/permission/token/PermissionTokenManagerTest.java
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImplTest.java b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImplTest.java
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImplTest.java
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceStubImplTest.java
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceTest.java b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceTest.java
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceTest.java
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/sdkservice/HealthDataSdkServiceTest.java
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/impl/testing/FakeHealthDataService.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/testing/FakeHealthDataService.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/impl/testing/FakeHealthDataService.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/impl/testing/FakeHealthDataService.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/permission/PermissionTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/permission/PermissionTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/permission/PermissionTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/permission/PermissionTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/DeleteDataRangeRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/DeleteDataRangeRequestTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/DeleteDataRangeRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/DeleteDataRangeRequestTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/DeleteDataRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/DeleteDataRequestTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/DeleteDataRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/DeleteDataRequestTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/ReadDataRangeRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/ReadDataRangeRequestTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/ReadDataRangeRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/ReadDataRangeRequestTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/ReadDataRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/ReadDataRequestTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/ReadDataRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/ReadDataRequestTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/RequestContextTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/RequestContextTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/RequestContextTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/RequestContextTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/request/UpsertDataRequestTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/request/UpsertDataRequestTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/request/UpsertDataRequestTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/request/UpsertDataRequestTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/response/InsertDataResponseTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/response/InsertDataResponseTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/response/InsertDataResponseTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/response/InsertDataResponseTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/response/ReadDataRangeResponseTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/response/ReadDataRangeResponseTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/response/ReadDataRangeResponseTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/response/ReadDataRangeResponseTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/response/ReadDataResponseTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/response/ReadDataResponseTest.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/response/ReadDataResponseTest.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/response/ReadDataResponseTest.kt
diff --git a/health/health-data-client/src/test/java/androidx/health/platform/client/testing/TestConstants.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/testing/TestConstants.kt
similarity index 100%
rename from health/health-data-client/src/test/java/androidx/health/platform/client/testing/TestConstants.kt
rename to health/health-connect-client/src/test/java/androidx/health/platform/client/testing/TestConstants.kt
diff --git a/health/health-data-client/api/public_plus_experimental_current.txt b/health/health-data-client/api/public_plus_experimental_current.txt
deleted file mode 100644
index d8d0caf..0000000
--- a/health/health-data-client/api/public_plus_experimental_current.txt
+++ /dev/null
@@ -1,374 +0,0 @@
-// Signature format: 4.0
-package androidx.health.data.client {
-
-  public interface HealthDataClient {
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, java.util.List<java.lang.String> uidsList, java.util.List<java.lang.String> clientIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record> recordType, androidx.health.data.client.time.TimeRangeFilter timeRangeFilter, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.ChangesResponse>);
-    method public suspend Object? getChangesToken(androidx.health.data.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public default static androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
-    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse>);
-    method public default static boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public default static boolean isAvailable(android.content.Context context);
-    field public static final androidx.health.data.client.HealthDataClient.Companion Companion;
-  }
-
-  public static final class HealthDataClient.Companion {
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public androidx.health.data.client.HealthDataClient getOrCreate(android.content.Context context);
-    method public boolean isAvailable(android.content.Context context, optional java.util.List<java.lang.String> packageNames);
-    method public boolean isAvailable(android.content.Context context);
-  }
-
-}
-
-package androidx.health.data.client.changes {
-
-  public interface Change {
-  }
-
-  public final class DeletionChange implements androidx.health.data.client.changes.Change {
-    method public String getDeletedUid();
-    property public final String deletedUid;
-  }
-
-  public final class UpsertionChange implements androidx.health.data.client.changes.Change {
-    method public androidx.health.data.client.records.Record getRecord();
-    property public final androidx.health.data.client.records.Record record;
-  }
-
-}
-
-package androidx.health.data.client.metadata {
-
-  public final class DataOrigin {
-    ctor public DataOrigin(String packageName);
-    method public String getPackageName();
-    property public final String packageName;
-  }
-
-  public final class Device {
-    ctor public Device(optional String? identifier, optional String? manufacturer, optional String? model, optional String? type);
-    method public String? getIdentifier();
-    method public String? getManufacturer();
-    method public String? getModel();
-    method public String? getType();
-    property public final String? identifier;
-    property public final String? manufacturer;
-    property public final String? model;
-    property public final String? type;
-  }
-
-  public final class DeviceTypes {
-    field public static final String CHEST_STRAP = "CHEST_STRAP";
-    field public static final String FITNESS_BAND = "FITNESS_BAND";
-    field public static final String HEAD_MOUNTED = "HEAD_MOUNTED";
-    field public static final androidx.health.data.client.metadata.DeviceTypes INSTANCE;
-    field public static final String PHONE = "PHONE";
-    field public static final String RING = "RING";
-    field public static final String SCALE = "SCALE";
-    field public static final String SMART_DISPLAY = "SMART_DISPLAY";
-    field public static final String UNKNOWN = "UNKNOWN";
-    field public static final String WATCH = "WATCH";
-  }
-
-  public final class Metadata {
-    ctor public Metadata(optional String? uid, optional androidx.health.data.client.metadata.DataOrigin dataOrigin, optional java.time.Instant lastModifiedTime, optional String? clientId, optional long clientVersion, optional androidx.health.data.client.metadata.Device? device);
-    method public String? getClientId();
-    method public long getClientVersion();
-    method public androidx.health.data.client.metadata.DataOrigin getDataOrigin();
-    method public androidx.health.data.client.metadata.Device? getDevice();
-    method public java.time.Instant getLastModifiedTime();
-    method public String? getUid();
-    property public final String? clientId;
-    property public final long clientVersion;
-    property public final androidx.health.data.client.metadata.DataOrigin dataOrigin;
-    property public final androidx.health.data.client.metadata.Device? device;
-    property public final java.time.Instant lastModifiedTime;
-    property public final String? uid;
-  }
-
-}
-
-package androidx.health.data.client.records {
-
-  public final class ActivityTypes {
-    field public static final String BACK_EXTENSION = "back_extension";
-    field public static final String BADMINTON = "badminton";
-    field public static final String BARBELL_SHOULDER_PRESS = "barbell_shoulder_press";
-    field public static final String BASEBALL = "baseball";
-    field public static final String BASKETBALL = "basketball";
-    field public static final String BENCH_PRESS = "bench_press";
-    field public static final String BENCH_SIT_UP = "bench_sit_up";
-    field public static final String BIKING = "biking";
-    field public static final String BIKING_STATIONARY = "biking_stationary";
-    field public static final String BOOT_CAMP = "boot_camp";
-    field public static final String BOXING = "boxing";
-    field public static final String BURPEE = "burpee";
-    field public static final String CALISTHENICS = "calisthenics";
-    field public static final String CRICKET = "cricket";
-    field public static final String CRUNCH = "crunch";
-    field public static final String DANCING = "dancing";
-    field public static final String DEADLIFT = "deadlift";
-    field public static final String DUMBBELL_CURL_LEFT_ARM = "dumbbell_curl_left_arm";
-    field public static final String DUMBBELL_CURL_RIGHT_ARM = "dumbbell_curl_right_arm";
-    field public static final String DUMBBELL_FRONT_RAISE = "dumbbell_front_raise";
-    field public static final String DUMBBELL_LATERAL_RAISE = "dumbbell_lateral_raise";
-    field public static final String DUMBBELL_TRICEPS_EXTENSION_LEFT_ARM = "dumbbell_triceps_extension_left_arm";
-    field public static final String DUMBBELL_TRICEPS_EXTENSION_RIGHT_ARM = "dumbbell_triceps_extension_right_arm";
-    field public static final String DUMBBELL_TRICEPS_EXTENSION_TWO_ARM = "dumbbell_triceps_extension_two_arm";
-    field public static final String ELLIPTICAL = "elliptical";
-    field public static final String EXERCISE_CLASS = "exercise_class";
-    field public static final String FENCING = "fencing";
-    field public static final String FOOTBALL_AMERICAN = "football_american";
-    field public static final String FOOTBALL_AUSTRALIAN = "football_australian";
-    field public static final String FORWARD_TWIST = "forward_twist";
-    field public static final String FRISBEE_DISC = "frisbee_disc";
-    field public static final String GOLF = "golf";
-    field public static final String GUIDED_BREATHING = "guided_breathing";
-    field public static final String GYMNASTICS = "gymnastics";
-    field public static final String HANDBALL = "handball";
-    field public static final String HIGH_INTENSITY_INTERVAL_TRAINING = "high_intensity_interval_training";
-    field public static final String HIKING = "hiking";
-    field public static final String ICE_HOCKEY = "ice_hockey";
-    field public static final String ICE_SKATING = "ice_skating";
-    field public static final androidx.health.data.client.records.ActivityTypes INSTANCE;
-    field public static final String JUMPING_JACK = "jumping_jack";
-    field public static final String JUMP_ROPE = "jump_rope";
-    field public static final String LAT_PULL_DOWN = "lat_pull_down";
-    field public static final String LUNGE = "lunge";
-    field public static final String MARTIAL_ARTS = "martial_arts";
-    field public static final String MEDITATION = "meditation";
-    field public static final String PADDLING = "paddling";
-    field public static final String PARA_GLIDING = "para_gliding";
-    field public static final String PILATES = "pilates";
-    field public static final String PLANK = "plank";
-    field public static final String RACQUETBALL = "racquetball";
-    field public static final String ROCK_CLIMBING = "rock_climbing";
-    field public static final String ROLLER_HOCKEY = "roller_hockey";
-    field public static final String ROWING = "rowing";
-    field public static final String ROWING_MACHINE = "rowing_machine";
-    field public static final String RUGBY = "rugby";
-    field public static final String RUNNING = "running";
-    field public static final String RUNNING_TREADMILL = "running_treadmill";
-    field public static final String SAILING = "sailing";
-    field public static final String SCUBA_DIVING = "scuba_diving";
-    field public static final String SKATING = "skating";
-    field public static final String SKIING = "skiing";
-    field public static final String SNOWBOARDING = "snowboarding";
-    field public static final String SNOWSHOEING = "snowshoeing";
-    field public static final String SOCCER = "soccer";
-    field public static final String SOFTBALL = "softball";
-    field public static final String SQUASH = "squash";
-    field public static final String SQUAT = "squat";
-    field public static final String STAIR_CLIMBING = "stair_climbing";
-    field public static final String STAIR_CLIMBING_MACHINE = "stair_climbing_machine";
-    field public static final String STRENGTH_TRAINING = "strength_training";
-    field public static final String STRETCHING = "stretching";
-    field public static final String SURFING = "surfing";
-    field public static final String SWIMMING_OPEN_WATER = "swimming_open_water";
-    field public static final String SWIMMING_POOL = "swimming_pool";
-    field public static final String TABLE_TENNIS = "table_tennis";
-    field public static final String TENNIS = "tennis";
-    field public static final String UPPER_TWIST = "upper_twist";
-    field public static final String VOLLEYBALL = "volleyball";
-    field public static final String WALKING = "walking";
-    field public static final String WATER_POLO = "water_polo";
-    field public static final String WEIGHTLIFTING = "weightlifting";
-    field public static final String WORKOUT = "workout";
-    field public static final String YOGA = "yoga";
-  }
-
-  public final class BloodPressureMeasurementLocations {
-    field public static final androidx.health.data.client.records.BloodPressureMeasurementLocations INSTANCE;
-    field public static final String LEFT_UPPER_ARM = "left_upper_arm";
-    field public static final String LEFT_WRIST = "left_wrist";
-    field public static final String RIGHT_UPPER_ARM = "right_upper_arm";
-    field public static final String RIGHT_WRIST = "right_wrist";
-  }
-
-  public final class BodyPositions {
-    field public static final androidx.health.data.client.records.BodyPositions INSTANCE;
-    field public static final String LYING_DOWN = "lying_down";
-    field public static final String RECLINING = "reclining";
-    field public static final String SITTING_DOWN = "sitting_down";
-    field public static final String STANDING_UP = "standing_up";
-  }
-
-  public final class BodyTemperature implements androidx.health.data.client.records.Record {
-    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public String? getMeasurementLocation();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
-    method public java.time.Instant getTime();
-    method public java.time.ZoneOffset? getZoneOffset();
-    property public final String? measurementLocation;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
-    property public java.time.Instant time;
-    property public java.time.ZoneOffset? zoneOffset;
-  }
-
-  public final class BodyTemperatureMeasurementLocations {
-    field public static final String ARMPIT = "armpit";
-    field public static final String EAR = "ear";
-    field public static final String FINGER = "finger";
-    field public static final String FOREHEAD = "forehead";
-    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
-    field public static final String MOUTH = "mouth";
-    field public static final String RECTUM = "rectum";
-    field public static final String TEMPORAL_ARTERY = "temporal_artery";
-    field public static final String TOE = "toe";
-    field public static final String VAGINA = "vagina";
-    field public static final String WRIST = "wrist";
-  }
-
-  public final class Distance implements androidx.health.data.client.records.Record {
-    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public double getDistanceMeters();
-    method public java.time.Instant getEndTime();
-    method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getStartTime();
-    method public java.time.ZoneOffset? getStartZoneOffset();
-    property public final double distanceMeters;
-    property public java.time.Instant endTime;
-    property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant startTime;
-    property public java.time.ZoneOffset? startZoneOffset;
-  }
-
-  public final class ElevationGained implements androidx.health.data.client.records.Record {
-    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public double getElevationMeters();
-    method public java.time.Instant getEndTime();
-    method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getStartTime();
-    method public java.time.ZoneOffset? getStartZoneOffset();
-    property public final double elevationMeters;
-    property public java.time.Instant endTime;
-    property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant startTime;
-    property public java.time.ZoneOffset? startZoneOffset;
-  }
-
-  public final class Height implements androidx.health.data.client.records.Record {
-    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public double getHeightMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getTime();
-    method public java.time.ZoneOffset? getZoneOffset();
-    property public final double heightMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant time;
-    property public java.time.ZoneOffset? zoneOffset;
-  }
-
-  public final class HipCircumference implements androidx.health.data.client.records.Record {
-    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public double getCircumferenceMeters();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getTime();
-    method public java.time.ZoneOffset? getZoneOffset();
-    property public final double circumferenceMeters;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant time;
-    property public java.time.ZoneOffset? zoneOffset;
-  }
-
-  public final class OvulationTestResults {
-    field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
-    field public static final String NEGATIVE = "negative";
-    field public static final String POSITIVE = "positive";
-  }
-
-  public interface Record {
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    property public abstract androidx.health.data.client.metadata.Metadata metadata;
-  }
-
-  public final class Steps implements androidx.health.data.client.records.Record {
-    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public long getCount();
-    method public java.time.Instant getEndTime();
-    method public java.time.ZoneOffset? getEndZoneOffset();
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getStartTime();
-    method public java.time.ZoneOffset? getStartZoneOffset();
-    property public final long count;
-    property public java.time.Instant endTime;
-    property public java.time.ZoneOffset? endZoneOffset;
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant startTime;
-    property public java.time.ZoneOffset? startZoneOffset;
-  }
-
-  public final class Weight implements androidx.health.data.client.records.Record {
-    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
-    method public androidx.health.data.client.metadata.Metadata getMetadata();
-    method public java.time.Instant getTime();
-    method public double getWeightKg();
-    method public java.time.ZoneOffset? getZoneOffset();
-    property public androidx.health.data.client.metadata.Metadata metadata;
-    property public java.time.Instant time;
-    property public final double weightKg;
-    property public java.time.ZoneOffset? zoneOffset;
-  }
-
-}
-
-package androidx.health.data.client.request {
-
-  public final class ChangesTokenRequest {
-    ctor public ChangesTokenRequest(java.util.Set<? extends kotlin.reflect.KClass<? extends androidx.health.data.client.records.Record>> recordTypes, optional java.util.Set<androidx.health.data.client.metadata.DataOrigin> dataOriginFilters);
-  }
-
-}
-
-package androidx.health.data.client.response {
-
-  public final class ChangesResponse {
-    method public java.util.List<androidx.health.data.client.changes.Change> getChanges();
-    method public boolean getChangesTokenExpired();
-    method public boolean getHasMore();
-    method public String getNextChangesToken();
-    property public final java.util.List<androidx.health.data.client.changes.Change> changes;
-    property public final boolean changesTokenExpired;
-    property public final boolean hasMore;
-    property public final String nextChangesToken;
-  }
-
-  public final class InsertRecordsResponse {
-    method public java.util.List<java.lang.String> getRecordUidsList();
-    property public final java.util.List<java.lang.String> recordUidsList;
-  }
-
-}
-
-package androidx.health.data.client.time {
-
-  public final class TimeRangeFilter {
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public static androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
-    field public static final androidx.health.data.client.time.TimeRangeFilter.Companion Companion;
-  }
-
-  public static final class TimeRangeFilter.Companion {
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.Instant startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter after(java.time.LocalDateTime startTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter before(java.time.LocalDateTime endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.Instant startTime, java.time.Instant endTime);
-    method public androidx.health.data.client.time.TimeRangeFilter between(java.time.LocalDateTime startTime, java.time.LocalDateTime endTime);
-  }
-
-}
-
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
deleted file mode 100644
index 0cb371e..0000000
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.data.client.impl.converters.datatype
-
-import androidx.health.data.client.records.ActiveCaloriesBurned
-import androidx.health.data.client.records.ActivityEvent
-import androidx.health.data.client.records.ActivityLap
-import androidx.health.data.client.records.ActivitySession
-import androidx.health.data.client.records.BasalBodyTemperature
-import androidx.health.data.client.records.BasalMetabolicRate
-import androidx.health.data.client.records.BloodGlucose
-import androidx.health.data.client.records.BloodPressure
-import androidx.health.data.client.records.BodyFat
-import androidx.health.data.client.records.BodyTemperature
-import androidx.health.data.client.records.BodyWaterMass
-import androidx.health.data.client.records.BoneMass
-import androidx.health.data.client.records.CervicalMucus
-import androidx.health.data.client.records.CervicalPosition
-import androidx.health.data.client.records.CyclingPedalingCadence
-import androidx.health.data.client.records.Distance
-import androidx.health.data.client.records.ElevationGained
-import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
-import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
-import androidx.health.data.client.records.HeartRateVariabilityRmssd
-import androidx.health.data.client.records.HeartRateVariabilityS
-import androidx.health.data.client.records.HeartRateVariabilitySd2
-import androidx.health.data.client.records.HeartRateVariabilitySdann
-import androidx.health.data.client.records.HeartRateVariabilitySdnn
-import androidx.health.data.client.records.HeartRateVariabilitySdnnIndex
-import androidx.health.data.client.records.HeartRateVariabilitySdsd
-import androidx.health.data.client.records.HeartRateVariabilityTinn
-import androidx.health.data.client.records.Height
-import androidx.health.data.client.records.HipCircumference
-import androidx.health.data.client.records.Hydration
-import androidx.health.data.client.records.LeanBodyMass
-import androidx.health.data.client.records.Menstruation
-import androidx.health.data.client.records.Nutrition
-import androidx.health.data.client.records.OvulationTest
-import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Power
-import androidx.health.data.client.records.Repetitions
-import androidx.health.data.client.records.RespiratoryRate
-import androidx.health.data.client.records.RestingHeartRate
-import androidx.health.data.client.records.SexualActivity
-import androidx.health.data.client.records.SleepSession
-import androidx.health.data.client.records.SleepStage
-import androidx.health.data.client.records.Speed
-import androidx.health.data.client.records.Steps
-import androidx.health.data.client.records.StepsCadence
-import androidx.health.data.client.records.SwimmingStrokes
-import androidx.health.data.client.records.TotalCaloriesBurned
-import androidx.health.data.client.records.Vo2Max
-import androidx.health.data.client.records.WaistCircumference
-import androidx.health.data.client.records.Weight
-import androidx.health.data.client.records.WheelchairPushes
-
-private val ALL_RECORDS_TYPES =
-    setOf(
-        ActiveCaloriesBurned::class,
-        ActivityEvent::class,
-        ActivityLap::class,
-        ActivitySession::class,
-        BasalBodyTemperature::class,
-        BasalMetabolicRate::class,
-        BloodGlucose::class,
-        BloodPressure::class,
-        BodyFat::class,
-        BodyTemperature::class,
-        BodyWaterMass::class,
-        BoneMass::class,
-        CervicalMucus::class,
-        CervicalPosition::class,
-        CyclingPedalingCadence::class,
-        Distance::class,
-        ElevationGained::class,
-        FloorsClimbed::class,
-        HeartRate::class,
-        HeartRateVariabilityDifferentialIndex::class,
-        HeartRateVariabilityRmssd::class,
-        HeartRateVariabilityS::class,
-        HeartRateVariabilitySd2::class,
-        HeartRateVariabilitySdann::class,
-        HeartRateVariabilitySdnn::class,
-        HeartRateVariabilitySdnnIndex::class,
-        HeartRateVariabilitySdsd::class,
-        HeartRateVariabilityTinn::class,
-        Height::class,
-        HipCircumference::class,
-        Hydration::class,
-        LeanBodyMass::class,
-        Menstruation::class,
-        Nutrition::class,
-        OvulationTest::class,
-        OxygenSaturation::class,
-        Power::class,
-        Repetitions::class,
-        RespiratoryRate::class,
-        RestingHeartRate::class,
-        SexualActivity::class,
-        SleepSession::class,
-        SleepStage::class,
-        Speed::class,
-        Steps::class,
-        StepsCadence::class,
-        SwimmingStrokes::class,
-        TotalCaloriesBurned::class,
-        Vo2Max::class,
-        WaistCircumference::class,
-        WheelchairPushes::class,
-        Weight::class,
-    )
-
-val RECORDS_TYPE_NAME_MAP = ALL_RECORDS_TYPES.associateBy { it.simpleName!! }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt
deleted file mode 100644
index 4ad70d8..0000000
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.data.client.impl.converters.records
-
-import androidx.health.data.client.metadata.DataOrigin
-import androidx.health.data.client.metadata.Device
-import androidx.health.data.client.metadata.Metadata
-import androidx.health.platform.client.proto.DataProto
-import java.time.Instant
-import java.time.ZoneOffset
-
-/** Internal helper functions to convert proto to records. */
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.startTime: Instant
-    get() = Instant.ofEpochMilli(startTimeMillis)
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.endTime: Instant
-    get() = Instant.ofEpochMilli(endTimeMillis)
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.time: Instant
-    get() = Instant.ofEpochMilli(instantTimeMillis)
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.startZoneOffset: ZoneOffset?
-    get() =
-        if (hasStartZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(startZoneOffsetSeconds) else null
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.endZoneOffset: ZoneOffset?
-    get() = if (hasEndZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(endZoneOffsetSeconds) else null
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.zoneOffset: ZoneOffset?
-    get() = if (hasZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(zoneOffsetSeconds) else null
-
-internal fun DataProto.DataPoint.getLong(key: String, defaultVal: Long = 0): Long {
-    return valuesMap[key]?.longVal ?: defaultVal
-}
-
-internal fun DataProto.DataPoint.getDouble(key: String, defaultVal: Double = 0.0): Double {
-    return valuesMap[key]?.doubleVal ?: defaultVal
-}
-
-internal fun DataProto.DataPoint.getString(key: String): String? {
-    return valuesMap[key]?.stringVal
-}
-
-internal fun DataProto.DataPoint.getEnum(key: String): String? {
-    return valuesMap[key]?.enumVal
-}
-
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
-internal val DataProto.DataPoint.metadata: Metadata
-    get() =
-        Metadata(
-            uid = if (hasUid()) uid else null,
-            dataOrigin = DataOrigin(dataOrigin.applicationId),
-            lastModifiedTime = Instant.ofEpochMilli(updateTimeMillis),
-            clientId = if (hasClientId()) clientId else null,
-            clientVersion = clientVersion,
-            device = toDevice(device)
-        )
-
-private fun toDevice(proto: DataProto.Device): Device {
-    return with(proto) {
-        Device(
-            identifier = if (hasIdentifier()) identifier else null,
-            manufacturer = if (hasManufacturer()) manufacturer else null,
-            model = if (hasModel()) model else null,
-            type = if (hasType()) type else null
-        )
-    }
-}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt
deleted file mode 100644
index 562d5e5..0000000
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.data.client.records
-
-import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.LongAggregateMetric
-import androidx.health.data.client.metadata.Metadata
-import java.time.Instant
-import java.time.ZoneOffset
-
-/** Captures the user's heart rate. Each record represents a single instantaneous measurement. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class HeartRate(
-    /** Heart beats per minute. Required field. Validation range: 1-300. */
-    public val beatsPerMinute: Long,
-    override val time: Instant,
-    override val zoneOffset: ZoneOffset?,
-    override val metadata: Metadata = Metadata.EMPTY,
-) : InstantaneousRecord {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is HeartRate) return false
-
-        if (beatsPerMinute != other.beatsPerMinute) return false
-        if (time != other.time) return false
-        if (zoneOffset != other.zoneOffset) return false
-        if (metadata != other.metadata) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + beatsPerMinute.hashCode()
-        result = 31 * result + time.hashCode()
-        result = 31 * result + (zoneOffset?.hashCode() ?: 0)
-        result = 31 * result + metadata.hashCode()
-        return result
-    }
-
-    companion object {
-        /** Metric identifier to retrieve average heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_AVG: LongAggregateMetric = LongAggregateMetric("HeartRate", "avg", "bpm")
-
-        /** Metric identifier to retrieve minimum heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_MIN: LongAggregateMetric = LongAggregateMetric("HeartRate", "min", "bpm")
-
-        /** Metric identifier to retrieve maximum heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_MAX: LongAggregateMetric = LongAggregateMetric("HeartRate", "max", "bpm")
-    }
-}
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt b/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
deleted file mode 100644
index e2d1362..0000000
--- a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.platform.client.error
-
-/**
- * Exception thrown by Health Platform. Contains one of [ErrorCode]s and message with details on the
- * error.
- */
-open class HealthDataException(val errorCode: Int, errorMessage: String? = "") :
-    Exception("$errorCode: $errorMessage")
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt
deleted file mode 100644
index 893e039..0000000
--- a/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.data.client.time
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import java.time.Instant
-import java.time.LocalDateTime
-import kotlin.test.assertFailsWith
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class TimeRangeFilterTest {
-
-    @Test
-    fun checksStartTimeBeforeEndTime() {
-        assertFailsWith<IllegalArgumentException> {
-            TimeRangeFilter.between(
-                endTime = Instant.ofEpochMilli(1234L),
-                startTime = Instant.ofEpochMilli(5679L),
-            )
-        }
-        assertFailsWith<IllegalArgumentException> {
-            TimeRangeFilter.between(
-                startTime = Instant.ofEpochMilli(1234L),
-                endTime = Instant.ofEpochMilli(1234L),
-            )
-        }
-        TimeRangeFilter.between(
-            startTime = Instant.ofEpochMilli(1234L),
-            endTime = Instant.ofEpochMilli(5679L),
-        )
-    }
-
-    @Test
-    fun checksLocalStartTimeBeforeEndTime() {
-        assertFailsWith<IllegalArgumentException> {
-            TimeRangeFilter.between(
-                startTime = LocalDateTime.parse("2021-02-01T02:00:00"),
-                endTime = LocalDateTime.parse("2021-02-01T01:00:00")
-            )
-        }
-        assertFailsWith<IllegalArgumentException> {
-            TimeRangeFilter.between(
-                startTime = LocalDateTime.parse("2021-02-01T02:00:00"),
-                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
-            )
-        }
-        TimeRangeFilter.between(
-            startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
-            endTime = LocalDateTime.parse("2021-02-01T02:00:00")
-        )
-    }
-}
diff --git a/libraryversions.toml b/libraryversions.toml
index f3baa01..ce6b059 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -51,7 +51,7 @@
 GLANCE = "1.0.0-alpha04"
 GLANCE_TEMPLATE = "1.0.0-alpha01"
 GRIDLAYOUT = "1.1.0-alpha01"
-HEALTH_DATA_CLIENT = "1.0.0-alpha01"
+HEALTH_CONNECT_CLIENT = "1.0.0-alpha01"
 HEALTH_SERVICES_CLIENT = "1.0.0-alpha04"
 HEIFWRITER = "1.1.0-alpha02"
 HILT = "1.1.0-alpha01"
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
index 47151f7..e2285f3 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
@@ -52,7 +52,7 @@
     if (savedStateRegistry.getSavedStateProvider(SAVED_STATE_KEY) == null) {
         val provider = SavedStateHandlesProvider(savedStateRegistry, this)
         savedStateRegistry.registerSavedStateProvider(SAVED_STATE_KEY, provider)
-        savedStateRegistry.runOnNextRecreation(SavedStateHandleAttacher::class.java)
+        lifecycle.addObserver(SavedStateHandleAttacher(provider))
     }
 }
 
@@ -184,11 +184,15 @@
 }
 
 // it reconnects existent SavedStateHandles to SavedStateRegistryOwner when it is recreated
-internal class SavedStateHandleAttacher : SavedStateRegistry.AutoRecreated {
-    override fun onRecreated(owner: SavedStateRegistryOwner) {
-        // if SavedStateHandlesProvider wasn't added previously, there's nothing for us to do
-        val provider = owner.savedStateRegistry
-            .getSavedStateProvider(SAVED_STATE_KEY) as? SavedStateHandlesProvider ?: return
+internal class SavedStateHandleAttacher(
+    private val provider: SavedStateHandlesProvider
+) : LifecycleEventObserver {
+
+    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+        check(event == Lifecycle.Event.ON_CREATE) {
+            "Next event must be ON_CREATE, it was $event"
+        }
+        source.lifecycle.removeObserver(this)
         // onRecreated() is called after the Lifecycle reaches CREATED, so we
         // eagerly restore the state as part of this call to ensure it consumed
         // even if no ViewModels are actually created during this cycle of the Lifecycle
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/WriteAheadLoggingTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/WriteAheadLoggingTest.java
index 6d9f4b5..a5ba88e 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/WriteAheadLoggingTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/WriteAheadLoggingTest.java
@@ -32,6 +32,7 @@
 import android.database.Cursor;
 
 import androidx.annotation.NonNull;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.Observer;
 import androidx.room.InvalidationTracker;
@@ -49,6 +50,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -61,6 +63,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
@@ -70,6 +73,9 @@
     private static final String DATABASE_NAME = "wal.db";
     private TestDatabase mDatabase;
 
+    @Rule
+    public CountingTaskExecutorRule countingTaskExecutorRule = new CountingTaskExecutorRule();
+
     @Before
     public void openDatabase() {
         Context context = ApplicationProvider.getApplicationContext();
@@ -80,7 +86,10 @@
     }
 
     @After
-    public void closeDatabase() {
+    public void closeDatabase() throws InterruptedException, TimeoutException {
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS);
+        assertThat(countingTaskExecutorRule.isIdle(), is(true));
+
         mDatabase.close();
         Context context = ApplicationProvider.getApplicationContext();
         context.deleteDatabase(DATABASE_NAME);
diff --git a/room/room-paging-guava/build.gradle b/room/room-paging-guava/build.gradle
index 5db83cb..8f23959 100644
--- a/room/room-paging-guava/build.gradle
+++ b/room/room-paging-guava/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 import androidx.build.LibraryType
 import androidx.build.Publish
 
@@ -23,9 +24,49 @@
     id("org.jetbrains.kotlin.android")
 }
 
+// If set to `true`, we'll use KSP instead of KAPT.
+// Note that the CI does not run tests with KSP yet so this is only for local usage.
+// Once variants are properly supported by both ksp and AndroidX, we'll add support for this.
+// (b/153917176)
+def useKsp = project.properties.getOrDefault("useKsp", "false").toBoolean()
+if (useKsp) {
+    apply plugin: "com.google.devtools.ksp"
+} else {
+    apply plugin: "kotlin-kapt"
+}
+
 dependencies {
     api(libs.kotlinStdlib)
-    // Add dependencies here
+    implementation(project(":room:room-paging"))
+    implementation(project(":room:room-guava"))
+    implementation(projectOrArtifact(":paging:paging-guava"))
+
+    androidTestImplementation(libs.truth)
+    androidTestImplementation(libs.testExtJunitKtx)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.kotlinTestJunit)
+    androidTestImplementation(libs.kotlinCoroutinesTest)
+    androidTestImplementation(libs.kotlinCoroutinesGuava)
+    androidTestImplementation("androidx.arch.core:core-testing:2.0.1")
+    androidTestImplementation(project(":internal-testutils-common"))
+    // depend on the shadowed version so that it tests with the shipped artifact
+    // this is a temporary attribute until KSP and AndroidX plugin supports variants.
+    if(useKsp) {
+        kspAndroidTest(
+                project(path: ":room:room-compiler", configuration: "shadowAndImplementation")
+        )
+    } else {
+        kaptAndroidTest(
+            project(path: ":room:room-compiler", configuration: "shadowAndImplementation")
+        )
+    }
+}
+
+// Allow usage of Kotlin's @OptIn.
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"]
+    }
 }
 
 androidx {
diff --git a/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
new file mode 100644
index 0000000..a9fd319
--- /dev/null
+++ b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.paging.guava
+
+import android.database.Cursor
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule
+import androidx.paging.LoadType
+import androidx.paging.PagingConfig
+import androidx.paging.PagingSource
+import androidx.paging.PagingSource.LoadResult
+import androidx.room.Dao
+import androidx.room.Database
+import androidx.room.Entity
+import androidx.room.Insert
+import androidx.room.PrimaryKey
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.RoomSQLiteQuery
+import androidx.room.util.getColumnIndexOrThrow
+import androidx.sqlite.db.SimpleSQLiteQuery
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.TestExecutor
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import com.google.common.util.concurrent.FutureCallback
+import com.google.common.util.concurrent.Futures.addCallback
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.LinkedList
+import java.util.concurrent.CancellationException
+import java.util.concurrent.Executor
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val tableName: String = "TestItem"
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class LimitOffsetListenableFuturePagingSourceTest {
+
+    @JvmField
+    @Rule
+    val countingTaskExecutorRule = CountingTaskExecutorRule()
+
+    @Test
+    fun initialEmptyLoad_futureIsDone() = setupAndRun { db ->
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+        runTest {
+            val listenableFuture = pagingSource.refresh()
+            val page = listenableFuture.await() as LoadResult.Page
+
+            assertThat(page.data).isEmpty()
+            assertTrue(listenableFuture.isDone)
+        }
+    }
+
+    @Test
+    fun initialLoad_returnsFutureImmediately() =
+        setupAndRunWithTestExecutor { db, _, transactionExecutor ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+            val listenableFuture = pagingSource.refresh()
+            // ensure future is returned even as its result is still pending
+            assertFalse(listenableFuture.isDone)
+            assertThat(pagingSource.itemCount.get()).isEqualTo(-1)
+
+            // now execute db queries
+            transactionExecutor.executeAll() // initial transactional refresh load
+
+            val page = listenableFuture.await() as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(0, 15)
+            )
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun append_returnsFutureImmediately() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            val listenableFuture = pagingSource.append(key = 20)
+            // ensure future is returned even as its result is still pending
+            assertFalse(listenableFuture.isDone)
+
+            // load append
+            queryExecutor.executeNext()
+
+            val page = listenableFuture.await() as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(20, 25)
+            )
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun prepend_returnsFutureImmediately() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            val listenableFuture = pagingSource.prepend(key = 20)
+            // ensure future is returned even as its result is still pending
+            assertFalse(listenableFuture.isDone)
+
+            // load prepend
+            queryExecutor.executeNext()
+
+            val page = listenableFuture.await() as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(15, 20)
+            )
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun append_returnsInvalid() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            val listenableFuture = pagingSource.append(key = 50)
+
+            pagingSource.invalidate() // imitate refreshVersionsAsync invalidating the PagingSource
+            assertTrue(pagingSource.invalid)
+
+            // executing the load Callable
+            queryExecutor.executeNext()
+
+            val result = listenableFuture.await()
+            assertThat(result).isInstanceOf(LoadResult.Invalid::class.java)
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun prepend_returnsInvalid() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            val listenableFuture = pagingSource.prepend(key = 50)
+
+            pagingSource.invalidate() // imitate refreshVersionsAsync invalidating the PagingSource
+            assertTrue(pagingSource.invalid)
+
+            // executing the load Callable
+            queryExecutor.executeNext()
+
+            val result = listenableFuture.await()
+            assertThat(result).isInstanceOf(LoadResult.Invalid::class.java)
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun refresh_consecutively() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        val pagingSource2 = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+        val listenableFuture1 = pagingSource.refresh(key = 10)
+        val listenableFuture2 = pagingSource2.refresh(key = 15)
+
+        // check that first Future completes first. If the first future didn't complete first,
+        // this await() would not return.
+        val page1 = listenableFuture1.await() as LoadResult.Page
+        assertThat(page1.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(10, 25)
+        )
+
+        val page2 = listenableFuture2.await() as LoadResult.Page
+        assertThat(page2.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(15, 30)
+        )
+    }
+
+    @Test
+    fun append_consecutively() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+
+            val listenableFuture1 = pagingSource.append(key = 10)
+            val listenableFuture2 = pagingSource.append(key = 15)
+
+            // both appends should be queued
+            assertThat(queryExecutor.queuedSize()).isEqualTo(2)
+
+            // run next append in queue and make sure it is the first append
+            queryExecutor.executeNext()
+            val page1 = listenableFuture1.await() as LoadResult.Page
+            assertThat(page1.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(10, 15)
+            )
+
+            // now run the second append
+            queryExecutor.executeNext()
+            val page2 = listenableFuture2.await() as LoadResult.Page
+            assertThat(page2.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(15, 20)
+            )
+        }
+
+    @Test
+    fun prepend_consecutively() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+
+            val listenableFuture1 = pagingSource.prepend(key = 30)
+            val listenableFuture2 = pagingSource.prepend(key = 25)
+
+            // both prepends should be queued
+            assertThat(queryExecutor.queuedSize()).isEqualTo(2)
+
+            // run next prepend in queue and make sure it is the first prepend
+            queryExecutor.executeNext()
+            val page1 = listenableFuture1.await() as LoadResult.Page
+            assertThat(page1.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(25, 30)
+            )
+
+            // now run the second prepend
+            queryExecutor.executeNext()
+            val page2 = listenableFuture2.await() as LoadResult.Page
+            assertThat(page2.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(20, 25)
+            )
+        }
+
+    @Test
+    fun refresh_onSuccess() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+        val listenableFuture = pagingSource.refresh(key = 30)
+
+        var onSuccessReceived = false
+        val callbackExecutor = TestExecutor()
+        listenableFuture.onSuccess(callbackExecutor) { result ->
+            val page = result as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(30, 45)
+            )
+            onSuccessReceived = true
+        }
+
+        // wait until Room db's refresh load is complete
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
+        assertTrue(listenableFuture.isDone)
+
+        callbackExecutor.executeAll()
+
+        // make sure onSuccess callback was executed
+        assertTrue(onSuccessReceived)
+        assertTrue(listenableFuture.isDone)
+    }
+
+    @Test
+    fun append_onSuccess() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        pagingSource.itemCount.set(100) // bypass check for initial load
+
+        val listenableFuture = pagingSource.append(key = 20)
+        // ensure future is returned even as its result is still pending
+        assertFalse(listenableFuture.isDone)
+
+        var onSuccessReceived = false
+        val callbackExecutor = TestExecutor()
+        listenableFuture.onSuccess(callbackExecutor) { result ->
+            val page = result as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(20, 25)
+            )
+            onSuccessReceived = true
+        }
+        // let room db complete load
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
+        callbackExecutor.executeAll()
+
+        // make sure onSuccess callback was executed
+        assertTrue(onSuccessReceived)
+        assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun prepend_onSuccess() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        pagingSource.itemCount.set(100) // bypass check for initial load
+
+        val listenableFuture = pagingSource.prepend(key = 40)
+        // ensure future is returned even as its result is still pending
+        assertFalse(listenableFuture.isDone)
+
+        var onSuccessReceived = false
+        val callbackExecutor = TestExecutor()
+        listenableFuture.onSuccess(callbackExecutor) { result ->
+            val page = result as LoadResult.Page
+            assertThat(page.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(35, 40)
+            )
+            onSuccessReceived = true
+        }
+        // let room db complete load
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
+        callbackExecutor.executeAll()
+
+        // make sure onSuccess callback was executed
+        assertTrue(onSuccessReceived)
+        assertTrue(listenableFuture.isDone)
+    }
+
+    @Test
+    fun refresh_awaitThrowsCancellationException() =
+        setupAndRunWithTestExecutor { db, queryExecutor, transactionExecutor ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+            val listenableFuture = pagingSource.refresh(key = 50)
+            // the initial runInTransaction load
+            assertThat(transactionExecutor.queuedSize()).isEqualTo(1)
+
+            listenableFuture.cancel(true)
+
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+            assertThat(transactionExecutor.queuedSize()).isEqualTo(1)
+
+            transactionExecutor.executeNext() // initial load
+            queryExecutor.executeNext() // refreshVersionsAsync from the end runInTransaction
+
+            // await() should throw after cancellation
+            assertFailsWith<CancellationException> {
+                listenableFuture.await()
+            }
+
+            // executors should be idle
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+            assertThat(transactionExecutor.queuedSize()).isEqualTo(0)
+            assertTrue(listenableFuture.isDone)
+            // even though initial refresh load is cancelled, the paging source itself
+            // is NOT invalidated
+            assertFalse(pagingSource.invalid)
+        }
+
+    @Test
+    fun append_awaitThrowsCancellationException() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            // queue up the append first
+            val listenableFuture = pagingSource.append(key = 20)
+            assertThat(queryExecutor.queuedSize()).isEqualTo(1)
+
+            listenableFuture.cancel(true)
+            queryExecutor.executeNext()
+
+            // await() should throw after cancellation
+            assertFailsWith<CancellationException> {
+                listenableFuture.await()
+            }
+
+            // although query was executed, it should not complete due to the cancellation signal.
+            // If query was completed, paging source would call refreshVersionsAsync manually
+            // and queuedSize() would be 1 instead of 0 with InvalidationTracker queued up
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+        }
+
+    @Test
+    fun prepend_awaitThrowsCancellationException() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            // queue up the prepend first
+            val listenableFuture = pagingSource.prepend(key = 30)
+            assertThat(queryExecutor.queuedSize()).isEqualTo(1)
+
+            listenableFuture.cancel(true)
+            queryExecutor.executeNext()
+
+            // await() should throw after cancellation
+            assertFailsWith<CancellationException> {
+                listenableFuture.await()
+            }
+
+            // although query was executed, it should not complete due to the cancellation signal.
+            // If query was completed, paging source would call refreshVersionsAsync manually
+            // and queuedSize() would be 1 instead of 0 with InvalidationTracker queued up
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+        }
+
+    @Test
+    fun refresh_canceledFutureRunsOnFailureCallback() =
+        setupAndRunWithTestExecutor { db, _, transactionExecutor ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+
+            val listenableFuture = pagingSource.refresh(key = 30)
+            assertThat(transactionExecutor.queuedSize()).isEqualTo(1)
+
+            val callbackExecutor = TestExecutor()
+            var onFailureReceived = false
+            listenableFuture.onFailure(callbackExecutor) { throwable ->
+                assertThat(throwable).isInstanceOf(CancellationException::class.java)
+                onFailureReceived = true
+            }
+
+            // now cancel future and execute the refresh load. The refresh should not complete.
+            listenableFuture.cancel(true)
+            transactionExecutor.executeNext()
+            assertThat(transactionExecutor.queuedSize()).isEqualTo(0)
+
+            callbackExecutor.executeAll()
+
+            // make sure onFailure callback was executed
+            assertTrue(onFailureReceived)
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun append_canceledFutureRunsOnFailureCallback() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            // queue up the append first
+            val listenableFuture = pagingSource.append(key = 20)
+            assertThat(queryExecutor.queuedSize()).isEqualTo(1)
+
+            val callbackExecutor = TestExecutor()
+            var onFailureReceived = false
+            listenableFuture.onFailure(callbackExecutor) { throwable ->
+                assertThat(throwable).isInstanceOf(CancellationException::class.java)
+                onFailureReceived = true
+            }
+
+            // now cancel future and execute the append load. The append should not complete.
+            listenableFuture.cancel(true)
+            queryExecutor.executeNext()
+            // if load was erroneously completed, InvalidationTracker would be queued
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+
+            callbackExecutor.executeAll()
+
+            // make sure onFailure callback was executed
+            assertTrue(onFailureReceived)
+            assertTrue(listenableFuture.isDone)
+    }
+
+    @Test
+    fun prepend_canceledFutureRunsOnFailureCallback() =
+        setupAndRunWithTestExecutor { db, queryExecutor, _ ->
+            val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+            pagingSource.itemCount.set(100) // bypass check for initial load
+
+            // queue up the prepend first
+            val listenableFuture = pagingSource.prepend(key = 30)
+            assertThat(queryExecutor.queuedSize()).isEqualTo(1)
+
+            val callbackExecutor = TestExecutor()
+            var onFailureReceived = false
+            listenableFuture.onFailure(callbackExecutor) { throwable ->
+                assertThat(throwable).isInstanceOf(CancellationException::class.java)
+                onFailureReceived = true
+            }
+
+            // now cancel future and execute the prepend which should not complete.
+            listenableFuture.cancel(true)
+            queryExecutor.executeNext()
+            // if load was erroneously completed, InvalidationTracker would be queued
+            assertThat(queryExecutor.queuedSize()).isEqualTo(0)
+
+            callbackExecutor.executeAll()
+
+            // make sure onFailure callback was executed
+            assertTrue(onFailureReceived)
+            assertTrue(listenableFuture.isDone)
+        }
+
+    @Test
+    fun refresh_AfterCancellation() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        pagingSource.itemCount.set(100) // bypass check for initial load
+
+        val listenableFuture = pagingSource.prepend(key = 50)
+
+        listenableFuture.cancel(true)
+        assertFailsWith<CancellationException> {
+            listenableFuture.await()
+        }
+
+        // new gen after query from previous gen was cancelled
+        val pagingSource2 = LimitOffsetListenableFuturePagingSourceImpl(db)
+        val listenableFuture2 = pagingSource2.refresh()
+        val result = listenableFuture2.await() as LoadResult.Page
+
+        // the new generation should load as usual
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 15)
+        )
+    }
+
+    @Test
+    fun appendAgain_afterFutureCanceled() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        pagingSource.itemCount.set(100) // bypass check for initial load
+
+        val listenableFuture = pagingSource.append(key = 30)
+
+        listenableFuture.cancel(true)
+        assertFailsWith<CancellationException> {
+            listenableFuture.await()
+        }
+        assertTrue(listenableFuture.isDone)
+        assertFalse(pagingSource.invalid)
+
+        val listenableFuture2 = pagingSource.append(key = 30)
+
+        val result = listenableFuture2.await() as LoadResult.Page
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(30, 35)
+        )
+        assertTrue(listenableFuture2.isDone)
+    }
+
+    @Test
+    fun prependAgain_afterFutureCanceled() = setupAndRun { db ->
+        db.dao.addAllItems(ITEMS_LIST)
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        pagingSource.itemCount.set(100) // bypass check for initial load
+
+        val listenableFuture = pagingSource.prepend(key = 30)
+
+        listenableFuture.cancel(true)
+        assertFailsWith<CancellationException> {
+            listenableFuture.await()
+        }
+        assertFalse(pagingSource.invalid)
+        assertTrue(listenableFuture.isDone)
+
+        val listenableFuture2 = pagingSource.prepend(key = 30)
+
+        val result = listenableFuture2.await() as LoadResult.Page
+            assertThat(result.data).containsExactlyElementsIn(
+                ITEMS_LIST.subList(25, 30)
+            )
+        assertTrue(listenableFuture2.isDone)
+    }
+
+    @Test
+    fun test_jumpSupport() = setupAndRun { db ->
+        val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
+        assertTrue(pagingSource.jumpingSupported)
+    }
+
+    @Test
+    fun refresh_secondaryConstructor() = setupAndRun { db ->
+        val pagingSource = object : LimitOffsetListenableFuturePagingSource<TestItem>(
+            db = db,
+            supportSQLiteQuery = SimpleSQLiteQuery(
+                "SELECT * FROM $tableName ORDER BY id ASC"
+            )
+        ) {
+            override fun convertRows(cursor: Cursor): List<TestItem> {
+                return convertRowsHelper(cursor)
+            }
+        }
+
+        db.dao.addAllItems(ITEMS_LIST)
+        val listenableFuture = pagingSource.refresh()
+
+        val page = listenableFuture.await() as LoadResult.Page
+        assertThat(page.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 15)
+        )
+        assertTrue(listenableFuture.isDone)
+    }
+
+    @Test
+    fun append_secondaryConstructor() = setupAndRun { db ->
+        val pagingSource = object : LimitOffsetListenableFuturePagingSource<TestItem>(
+            db = db,
+            supportSQLiteQuery = SimpleSQLiteQuery(
+                "SELECT * FROM $tableName ORDER BY id ASC"
+            )
+        ) {
+            override fun convertRows(cursor: Cursor): List<TestItem> {
+                return convertRowsHelper(cursor)
+            }
+        }
+
+        db.dao.addAllItems(ITEMS_LIST)
+        pagingSource.itemCount.set(100)
+        val listenableFuture = pagingSource.append(key = 50)
+
+        val page = listenableFuture.await() as LoadResult.Page
+        assertThat(page.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(50, 55)
+        )
+        assertTrue(listenableFuture.isDone)
+    }
+
+    @Test
+    fun prepend_secondaryConstructor() = setupAndRun { db ->
+        val pagingSource = object : LimitOffsetListenableFuturePagingSource<TestItem>(
+            db = db,
+            supportSQLiteQuery = SimpleSQLiteQuery(
+                "SELECT * FROM $tableName ORDER BY id ASC"
+            )
+        ) {
+            override fun convertRows(cursor: Cursor): List<TestItem> {
+                return convertRowsHelper(cursor)
+            }
+        }
+
+        db.dao.addAllItems(ITEMS_LIST)
+        pagingSource.itemCount.set(100)
+        val listenableFuture = pagingSource.prepend(key = 50)
+
+        val page = listenableFuture.await() as LoadResult.Page
+        assertThat(page.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(45, 50)
+        )
+        assertTrue(listenableFuture.isDone)
+    }
+
+    private fun setupAndRun(
+        test: suspend (LimitOffsetTestDb) -> Unit
+    ) {
+        val db = Room.inMemoryDatabaseBuilder(
+            ApplicationProvider.getApplicationContext(),
+            LimitOffsetTestDb::class.java
+        ).build()
+
+        runTest {
+            test(db)
+        }
+        tearDown(db)
+    }
+
+    private fun setupAndRunWithTestExecutor(
+        test: suspend (LimitOffsetTestDb, TestExecutor, TestExecutor) -> Unit
+    ) {
+        val queryExecutor = TestExecutor()
+        val transactionExecutor = TestExecutor()
+        val db = Room.inMemoryDatabaseBuilder(
+            ApplicationProvider.getApplicationContext(),
+            LimitOffsetTestDb::class.java
+        )
+            .setTransactionExecutor(transactionExecutor)
+            .setQueryExecutor(queryExecutor)
+            .build()
+
+        runTest {
+            db.dao.addAllItems(ITEMS_LIST)
+            queryExecutor.executeNext() // InvalidationTracker from the addAllItems
+          test(db, queryExecutor, transactionExecutor)
+        }
+        tearDown(db)
+    }
+
+    private fun tearDown(db: LimitOffsetTestDb) {
+        if (db.isOpen) db.close()
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
+        assertThat(countingTaskExecutorRule.isIdle).isTrue()
+    }
+}
+
+private class LimitOffsetListenableFuturePagingSourceImpl(
+    db: RoomDatabase,
+    queryString: String = "SELECT * FROM $tableName ORDER BY id ASC",
+) : LimitOffsetListenableFuturePagingSource<TestItem>(
+    sourceQuery = RoomSQLiteQuery.acquire(
+        queryString,
+        0
+    ),
+    db = db,
+    tables = arrayOf(tableName)
+) {
+    override fun convertRows(cursor: Cursor): List<TestItem> {
+        return convertRowsHelper(cursor)
+    }
+}
+
+private fun convertRowsHelper(cursor: Cursor): List<TestItem> {
+    val cursorIndexOfId = getColumnIndexOrThrow(cursor, "id")
+    val data = mutableListOf<TestItem>()
+    while (cursor.moveToNext()) {
+        val tmpId = cursor.getInt(cursorIndexOfId)
+        data.add(TestItem(tmpId))
+    }
+    return data
+}
+
+@Suppress("UNCHECKED_CAST")
+private fun TestExecutor.executeNext() {
+    val tasks = javaClass.getDeclaredField("mTasks").let {
+        it.isAccessible = true
+        it.get(this)
+    } as LinkedList<Runnable>
+
+    if (!tasks.isEmpty()) {
+        val task = tasks.poll()
+        task?.run()
+    }
+}
+
+@Suppress("UNCHECKED_CAST")
+private fun TestExecutor.queuedSize(): Int {
+    val tasks = javaClass.getDeclaredField("mTasks").let {
+        it.isAccessible = true
+        it.get(this)
+    } as LinkedList<Runnable>
+
+    return tasks.size
+}
+
+private fun LimitOffsetListenableFuturePagingSource<TestItem>.refresh(
+    key: Int? = null,
+): ListenableFuture<LoadResult<Int, TestItem>> {
+    return loadFuture(
+        createLoadParam(
+            loadType = LoadType.REFRESH,
+            key = key,
+        )
+    )
+}
+
+private fun LimitOffsetListenableFuturePagingSource<TestItem>.append(
+    key: Int? = -1,
+): ListenableFuture<LoadResult<Int, TestItem>> {
+    return loadFuture(
+        createLoadParam(
+            loadType = LoadType.APPEND,
+            key = key,
+        )
+    )
+}
+
+private fun LimitOffsetListenableFuturePagingSource<TestItem>.prepend(
+    key: Int? = -1,
+): ListenableFuture<LoadResult<Int, TestItem>> {
+    return loadFuture(
+        createLoadParam(
+            loadType = LoadType.PREPEND,
+            key = key,
+        )
+    )
+}
+
+private val CONFIG = PagingConfig(
+    pageSize = 5,
+    enablePlaceholders = true,
+    initialLoadSize = 15
+)
+
+private val ITEMS_LIST = createItemsForDb(0, 100)
+
+private fun createItemsForDb(startId: Int, count: Int): List<TestItem> {
+    return List(count) {
+        TestItem(
+            id = it + startId,
+        )
+    }
+}
+
+private fun createLoadParam(
+    loadType: LoadType,
+    key: Int? = null,
+    initialLoadSize: Int = CONFIG.initialLoadSize,
+    pageSize: Int = CONFIG.pageSize,
+    placeholdersEnabled: Boolean = CONFIG.enablePlaceholders
+): PagingSource.LoadParams<Int> {
+    return when (loadType) {
+        LoadType.REFRESH -> {
+            PagingSource.LoadParams.Refresh(
+                key = key,
+                loadSize = initialLoadSize,
+                placeholdersEnabled = placeholdersEnabled
+            )
+        }
+        LoadType.APPEND -> {
+            PagingSource.LoadParams.Append(
+                key = key ?: -1,
+                loadSize = pageSize,
+                placeholdersEnabled = placeholdersEnabled
+            )
+        }
+        LoadType.PREPEND -> {
+            PagingSource.LoadParams.Prepend(
+                key = key ?: -1,
+                loadSize = pageSize,
+                placeholdersEnabled = placeholdersEnabled
+            )
+        }
+    }
+}
+
+private fun ListenableFuture<LoadResult<Int, TestItem>>.onSuccess(
+    executor: Executor,
+    onSuccessCallback: (LoadResult<Int, TestItem>?) -> Unit,
+) {
+    addCallback(
+        this,
+        object : FutureCallback<LoadResult<Int, TestItem>> {
+            override fun onSuccess(result: LoadResult<Int, TestItem>?) {
+                onSuccessCallback(result)
+            }
+
+            override fun onFailure(t: Throwable) {
+                assertWithMessage("Expected onSuccess callback instead of onFailure, " +
+                    "received ${t.localizedMessage}").fail()
+            }
+        },
+        executor
+    )
+}
+
+private fun ListenableFuture<LoadResult<Int, TestItem>>.onFailure(
+    executor: Executor,
+    onFailureCallback: (Throwable) -> Unit,
+) {
+    addCallback(
+        this,
+        object : FutureCallback<LoadResult<Int, TestItem>> {
+            override fun onSuccess(result: LoadResult<Int, TestItem>?) {
+                assertWithMessage("Expected onFailure callback instead of onSuccess, " +
+                    "received result $result").fail()
+            }
+
+            override fun onFailure(t: Throwable) {
+                onFailureCallback(t)
+            }
+        },
+        executor
+    )
+}
+
+@Database(entities = [TestItem::class], version = 1, exportSchema = false)
+abstract class LimitOffsetTestDb : RoomDatabase() {
+    abstract val dao: TestItemDao
+}
+
+@Entity(tableName = "TestItem")
+data class TestItem(
+    @PrimaryKey val id: Int,
+    val value: String = "item $id"
+)
+
+@Dao
+interface TestItemDao {
+    @Insert
+    fun addAllItems(testItems: List<TestItem>)
+}
diff --git a/room/room-paging-guava/src/main/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSource.kt b/room/room-paging-guava/src/main/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSource.kt
new file mode 100644
index 0000000..fb2d209
--- /dev/null
+++ b/room/room-paging-guava/src/main/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSource.kt
@@ -0,0 +1,151 @@
+ /*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.paging.guava
+
+import android.database.Cursor
+import androidx.annotation.NonNull
+import androidx.annotation.RestrictTo
+import androidx.paging.ListenableFuturePagingSource
+import androidx.paging.PagingState
+import androidx.room.RoomDatabase
+import androidx.room.RoomSQLiteQuery
+import androidx.room.guava.GuavaRoom.createListenableFuture
+import androidx.room.paging.util.INITIAL_ITEM_COUNT
+import androidx.room.paging.util.INVALID
+import androidx.room.paging.util.ThreadSafeInvalidationObserver
+import androidx.room.paging.util.getClippedRefreshKey
+import androidx.room.paging.util.queryDatabase
+import androidx.room.paging.util.queryItemCount
+import androidx.room.util.createCancellationSignal
+import androidx.sqlite.db.SupportSQLiteQuery
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.Callable
+import java.util.concurrent.atomic.AtomicInteger
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+abstract class LimitOffsetListenableFuturePagingSource<Value : Any>(
+    private val sourceQuery: RoomSQLiteQuery,
+    private val db: RoomDatabase,
+    vararg tables: String
+) : ListenableFuturePagingSource<Int, Value>() {
+
+    constructor(
+        supportSQLiteQuery: SupportSQLiteQuery,
+        db: RoomDatabase,
+        vararg tables: String,
+    ) : this(
+        sourceQuery = RoomSQLiteQuery.copyFrom(supportSQLiteQuery),
+        db = db,
+        tables = tables,
+    )
+
+    // internal for testing visibility
+    internal val itemCount: AtomicInteger = AtomicInteger(INITIAL_ITEM_COUNT)
+    private val observer = ThreadSafeInvalidationObserver(tables = tables, ::invalidate)
+
+    /**
+    * Returns a [ListenableFuture] immediately before loading from the database completes
+    *
+    * If PagingSource is invalidated while the [ListenableFuture] is still pending, the
+    * invalidation will cancel the load() coroutine that calls await() on this future. The
+    * cancellation of await() will transitively cancel this future as well.
+    */
+    override fun loadFuture(params: LoadParams<Int>): ListenableFuture<LoadResult<Int, Value>> {
+        observer.registerIfNecessary(db)
+        val tempCount = itemCount.get()
+        return if (tempCount == INITIAL_ITEM_COUNT) {
+            initialLoad(params)
+        } else {
+            nonInitialLoad(params, tempCount)
+        }
+    }
+
+    /**
+    * For refresh loads
+    *
+    * To guarantee a valid initial load, it is run in transaction so that db writes cannot
+    * happen in between [queryItemCount] and [queryDatabase] to ensure a valid [itemCount].
+    * [itemCount] must be correct in order to calculate correct LIMIT and OFFSET for the query.
+    *
+    *
+    * However, the database load will be canceled via the cancellation signal if the future
+    * it returned has been canceled before it has completed.
+    */
+    private fun initialLoad(params: LoadParams<Int>): ListenableFuture<LoadResult<Int, Value>> {
+        val cancellationSignal = createCancellationSignal()
+        val loadCallable = Callable<LoadResult<Int, Value>> {
+            db.runInTransaction(
+                Callable {
+                    val tempCount = queryItemCount(sourceQuery, db)
+                    itemCount.set(tempCount)
+                    queryDatabase(
+                        params, sourceQuery, db, tempCount, cancellationSignal, ::convertRows
+                    )
+                }
+            )
+        }
+
+        return createListenableFuture(
+            db,
+            true,
+            loadCallable,
+            sourceQuery,
+            false,
+            cancellationSignal,
+        )
+    }
+
+    /**
+    * For append and prepend loads
+    *
+    * The cancellation signal cancels room database operation if its running, or cancels it
+    * the moment it starts. The signal is triggered when the future is canceled.
+    */
+    private fun nonInitialLoad(
+        params: LoadParams<Int>,
+        tempCount: Int
+    ): ListenableFuture<LoadResult<Int, Value>> {
+        val cancellationSignal = createCancellationSignal()
+        val loadCallable = Callable<LoadResult<Int, Value>> {
+            val result = queryDatabase(
+                params, sourceQuery, db, tempCount, cancellationSignal, ::convertRows
+            )
+            db.invalidationTracker.refreshVersionsAsync()
+            @Suppress("UNCHECKED_CAST")
+            if (invalid) INVALID as LoadResult.Invalid<Int, Value> else result
+        }
+
+        return createListenableFuture(
+            db,
+            false,
+            loadCallable,
+            sourceQuery,
+            false,
+            cancellationSignal
+        )
+    }
+
+    @NonNull
+    protected abstract fun convertRows(cursor: Cursor): List<Value>
+
+    override val jumpingSupported: Boolean
+        get() = true
+
+    override fun getRefreshKey(state: PagingState<Int, Value>): Int? {
+         return state.getClippedRefreshKey()
+    }
+}
\ No newline at end of file
diff --git a/room/room-paging/build.gradle b/room/room-paging/build.gradle
index 8e6600f..84367bf 100644
--- a/room/room-paging/build.gradle
+++ b/room/room-paging/build.gradle
@@ -45,7 +45,7 @@
 dependencies {
     api(libs.kotlinStdlib)
 
-    implementation(project(":room:room-runtime"))
+    api(project(":room:room-runtime"))
     implementation(project(":room:room-ktx"))
     api("androidx.paging:paging-common:3.1.0")
 
diff --git a/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt b/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
index 023e5b6..6634131 100644
--- a/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
+++ b/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
@@ -24,6 +24,8 @@
 import androidx.room.RoomDatabase
 import androidx.room.RoomSQLiteQuery
 import androidx.room.getQueryDispatcher
+import androidx.room.paging.util.INITIAL_ITEM_COUNT
+import androidx.room.paging.util.INVALID
 import androidx.room.paging.util.ThreadSafeInvalidationObserver
 import androidx.room.paging.util.getClippedRefreshKey
 import androidx.room.paging.util.queryDatabase
@@ -40,9 +42,6 @@
  * for Pager's consumption. Registers observers on tables lazily and automatically invalidates
  * itself when data changes.
  */
-
-private val INVALID = PagingSource.LoadResult.Invalid<Any, Any>()
-
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 abstract class LimitOffsetPagingSource<Value : Any>(
     private val sourceQuery: RoomSQLiteQuery,
@@ -60,7 +59,7 @@
         tables = tables,
     )
 
-    internal val itemCount: AtomicInteger = AtomicInteger(-1)
+    internal val itemCount: AtomicInteger = AtomicInteger(INITIAL_ITEM_COUNT)
 
     private val observer = ThreadSafeInvalidationObserver(
         tables = tables,
@@ -72,7 +71,7 @@
             observer.registerIfNecessary(db)
             val tempCount = itemCount.get()
             // if itemCount is < 0, then it is initial load
-            if (tempCount < 0) {
+            if (tempCount == INITIAL_ITEM_COUNT) {
                 initialLoad(params)
             } else {
                 nonInitialLoad(params, tempCount)
@@ -94,7 +93,13 @@
         return db.withTransaction {
             val tempCount = queryItemCount(sourceQuery, db)
             itemCount.set(tempCount)
-            queryDatabase(params, sourceQuery, db, tempCount, ::convertRows)
+            queryDatabase(
+                params = params,
+                sourceQuery = sourceQuery,
+                db = db,
+                itemCount = tempCount,
+                convertRows = ::convertRows
+            )
         }
     }
 
@@ -102,8 +107,14 @@
         params: LoadParams<Int>,
         tempCount: Int,
     ): LoadResult<Int, Value> {
-        val loadResult = queryDatabase(params, sourceQuery, db, tempCount, ::convertRows)
-        // manually check if database has been updated. If so, the observers's
+        val loadResult = queryDatabase(
+            params = params,
+            sourceQuery = sourceQuery,
+            db = db,
+            itemCount = tempCount,
+            convertRows = ::convertRows
+        )
+        // manually check if database has been updated. If so, the observer's
         // invalidation callback will invalidate this paging source
         db.invalidationTracker.refreshVersionsSync()
         @Suppress("UNCHECKED_CAST")
diff --git a/room/room-paging/src/main/kotlin/androidx/room/paging/util/RoomPagingUtil.kt b/room/room-paging/src/main/kotlin/androidx/room/paging/util/RoomPagingUtil.kt
index 2511fc6..1722c11 100644
--- a/room/room-paging/src/main/kotlin/androidx/room/paging/util/RoomPagingUtil.kt
+++ b/room/room-paging/src/main/kotlin/androidx/room/paging/util/RoomPagingUtil.kt
@@ -18,6 +18,7 @@
 package androidx.room.paging.util
 
 import android.database.Cursor
+import android.os.CancellationSignal
 import androidx.annotation.RestrictTo
 import androidx.paging.PagingSource
 import androidx.paging.PagingSource.LoadParams
@@ -30,6 +31,18 @@
 import androidx.room.RoomSQLiteQuery
 
 /**
+ * A [LoadResult] that can be returned to trigger a new generation of PagingSource
+ *
+ * Any loaded data or queued loads prior to returning INVALID will be discarded
+ */
+val INVALID = LoadResult.Invalid<Any, Any>()
+
+/**
+ * The default itemCount value
+ */
+const val INITIAL_ITEM_COUNT = -1
+
+/**
  * Calculates query limit based on LoadType.
  *
  * Prepend: If requested loadSize is larger than available number of items to prepend, it will
@@ -102,6 +115,8 @@
  * @param itemCount the db row count, triggers a new PagingSource generation if itemCount changes,
  * i.e. items are added / removed
  *
+ * @param cancellationSignal the signal to cancel the query if the query hasn't yet completed
+ *
  * @param convertRows the function to iterate data with provided [Cursor] to return List<Value>
  */
 fun <Value : Any> queryDatabase(
@@ -109,6 +124,7 @@
     sourceQuery: RoomSQLiteQuery,
     db: RoomDatabase,
     itemCount: Int,
+    cancellationSignal: CancellationSignal? = null,
     convertRows: (Cursor) -> List<Value>,
 ): LoadResult<Int, Value> {
     val key = params.key ?: 0
@@ -121,7 +137,7 @@
         sourceQuery.argCount
     )
     sqLiteQuery.copyArgumentsFrom(sourceQuery)
-    val cursor = db.query(sqLiteQuery)
+    val cursor = db.query(sqLiteQuery, cancellationSignal)
     val data: List<Value>
     try {
         data = convertRows(cursor)
diff --git a/settings.gradle b/settings.gradle
index a45a684..8cae153 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -520,6 +520,7 @@
 includeProject(":datastore:datastore", [BuildType.MAIN])
 includeProject(":datastore:datastore-core", [BuildType.MAIN])
 includeProject(":datastore:datastore-compose-samples", [BuildType.COMPOSE])
+includeProject(":datastore:datastore-multiprocess", [BuildType.MAIN])
 includeProject(":datastore:datastore-preferences", [BuildType.MAIN])
 includeProject(":datastore:datastore-preferences-core", [BuildType.MAIN])
 includeProject(":datastore:datastore-preferences-proto", [BuildType.MAIN])
@@ -567,7 +568,7 @@
 includeProject(":glance:glance-wear-tiles:integration-tests:demos", [BuildType.MAIN, BuildType.GLANCE])
 includeProject(":glance:glance-wear-tiles", [BuildType.MAIN, BuildType.GLANCE])
 includeProject(":gridlayout:gridlayout", [BuildType.MAIN])
-includeProject(":health:health-data-client", [BuildType.MAIN])
+includeProject(":health:health-connect-client", [BuildType.MAIN])
 includeProject(":health:health-services-client", [BuildType.MAIN])
 includeProject(":heifwriter:heifwriter", [BuildType.MAIN])
 includeProject(":hilt:hilt-common", [BuildType.MAIN])
diff --git a/wear/compose/compose-foundation/api/current.txt b/wear/compose/compose-foundation/api/current.txt
index 8e6728e..78a48d4 100644
--- a/wear/compose/compose-foundation/api/current.txt
+++ b/wear/compose/compose-foundation/api/current.txt
@@ -15,18 +15,15 @@
   }
 
   @androidx.compose.runtime.Stable public interface ArcPaddingValues {
-    method public float calculateEndPadding();
-    method public float calculateInnerPadding();
-    method public float calculateOuterPadding();
-    method public float calculateStartPadding();
+    method public float calculateAfterPadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateBeforePadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateInnerPadding(int radialDirection);
+    method public float calculateOuterPadding(int radialDirection);
   }
 
   public final class BasicCurvedTextKt {
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float start, optional float end);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public interface CurvedAlignment {
@@ -120,6 +117,16 @@
   public final class CurvedModifierKt {
   }
 
+  public final class CurvedPaddingKt {
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float before, optional float after);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, androidx.wear.compose.foundation.ArcPaddingValues paddingValues);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, float outer, float inner, float before, float after);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float all);
+  }
+
   public final class CurvedParentDataKt {
     method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
     method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
diff --git a/wear/compose/compose-foundation/api/public_plus_experimental_current.txt b/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
index 8e6728e..78a48d4 100644
--- a/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
@@ -15,18 +15,15 @@
   }
 
   @androidx.compose.runtime.Stable public interface ArcPaddingValues {
-    method public float calculateEndPadding();
-    method public float calculateInnerPadding();
-    method public float calculateOuterPadding();
-    method public float calculateStartPadding();
+    method public float calculateAfterPadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateBeforePadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateInnerPadding(int radialDirection);
+    method public float calculateOuterPadding(int radialDirection);
   }
 
   public final class BasicCurvedTextKt {
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float start, optional float end);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public interface CurvedAlignment {
@@ -120,6 +117,16 @@
   public final class CurvedModifierKt {
   }
 
+  public final class CurvedPaddingKt {
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float before, optional float after);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, androidx.wear.compose.foundation.ArcPaddingValues paddingValues);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, float outer, float inner, float before, float after);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float all);
+  }
+
   public final class CurvedParentDataKt {
     method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
     method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
diff --git a/wear/compose/compose-foundation/api/restricted_current.txt b/wear/compose/compose-foundation/api/restricted_current.txt
index 8e6728e..78a48d4 100644
--- a/wear/compose/compose-foundation/api/restricted_current.txt
+++ b/wear/compose/compose-foundation/api/restricted_current.txt
@@ -15,18 +15,15 @@
   }
 
   @androidx.compose.runtime.Stable public interface ArcPaddingValues {
-    method public float calculateEndPadding();
-    method public float calculateInnerPadding();
-    method public float calculateOuterPadding();
-    method public float calculateStartPadding();
+    method public float calculateAfterPadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateBeforePadding(androidx.compose.ui.unit.LayoutDirection layoutDirection, int angularDirection);
+    method public float calculateInnerPadding(int radialDirection);
+    method public float calculateOuterPadding(int radialDirection);
   }
 
   public final class BasicCurvedTextKt {
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float start, optional float end);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
-    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
-    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow, optional kotlin.jvm.functions.Function0<androidx.wear.compose.foundation.CurvedTextStyle> style);
+    method public static void basicCurvedText(androidx.wear.compose.foundation.CurvedScope, String text, androidx.wear.compose.foundation.CurvedTextStyle style, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public interface CurvedAlignment {
@@ -120,6 +117,16 @@
   public final class CurvedModifierKt {
   }
 
+  public final class CurvedPaddingKt {
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float outer, optional float inner, optional float before, optional float after);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(float all);
+    method public static androidx.wear.compose.foundation.ArcPaddingValues ArcPaddingValues(optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, androidx.wear.compose.foundation.ArcPaddingValues paddingValues);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, float outer, float inner, float before, float after);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float radial, optional float angular);
+    method public static androidx.wear.compose.foundation.CurvedModifier padding(androidx.wear.compose.foundation.CurvedModifier, optional float all);
+  }
+
   public final class CurvedParentDataKt {
     method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
     method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
diff --git a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
index 0738444..8279fb3 100644
--- a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
+++ b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
@@ -30,7 +30,6 @@
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedAlignment
 import androidx.wear.compose.foundation.CurvedDirection
 import androidx.wear.compose.foundation.CurvedLayout
@@ -43,6 +42,7 @@
 import androidx.wear.compose.foundation.curvedColumn
 import androidx.wear.compose.foundation.curvedComposable
 import androidx.wear.compose.foundation.curvedRow
+import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.foundation.radialGradientBackground
 import androidx.wear.compose.foundation.size
 import androidx.wear.compose.foundation.weight
@@ -125,14 +125,14 @@
     CurvedLayout(modifier = Modifier.fillMaxSize()) {
         basicCurvedText(
             "Curved Text",
+            CurvedModifier.padding(10.dp),
             style = {
                 CurvedTextStyle(
                     fontSize = 16.sp,
                     color = Color.Black,
                     background = Color.White
                 )
-            },
-            contentArcPadding = ArcPaddingValues(10.dp)
+            }
         )
         curvedComposable {
             Box(modifier = Modifier.size(20.dp).background(Color.Gray))
@@ -185,9 +185,9 @@
                     color = Color.Black
                 )
             },
-            contentArcPadding = ArcPaddingValues(5.dp),
             modifier = CurvedModifier
                 .radialGradientBackground(0f to Color.White, 1f to Color.Black)
+                .padding(5.dp)
         )
         basicCurvedText(
             "Angular",
@@ -197,9 +197,9 @@
                     color = Color.Black
                 )
             },
-            contentArcPadding = ArcPaddingValues(5.dp),
             modifier = CurvedModifier
                 .angularGradientBackground(0f to Color.White, 1f to Color.Black)
+                .padding(5.dp)
         )
     }
 }
diff --git a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
index 712f70c..45360e3 100644
--- a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
+++ b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
@@ -19,7 +19,6 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 import org.junit.Assert
 
@@ -119,7 +118,7 @@
 internal class SpyCurvedChildWrapper(private val capturedInfo: CapturedInfo, wrapped: CurvedChild) :
     BaseCurvedChildWrapper(wrapped) {
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int = with(wrapped) {
diff --git a/wear/compose/compose-foundation/src/androidMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.android.kt b/wear/compose/compose-foundation/src/androidMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.android.kt
index 2b9af94..57a9954 100644
--- a/wear/compose/compose-foundation/src/androidMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.android.kt
+++ b/wear/compose/compose-foundation/src/androidMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.android.kt
@@ -38,7 +38,6 @@
     private var text: String = ""
     private var clockwise: Boolean = true
     private var fontSizePx: Float = 0f
-    private var arcPaddingPx: ArcPaddingPx = ArcPaddingPx(0f, 0f, 0f, 0f)
 
     actual var textWidth by mutableStateOf(0f)
     actual var textHeight by mutableStateOf(0f)
@@ -53,19 +52,16 @@
     actual fun updateIfNeeded(
         text: String,
         clockwise: Boolean,
-        fontSizePx: Float,
-        arcPaddingPx: ArcPaddingPx
+        fontSizePx: Float
     ) {
         if (
             text != this.text ||
             clockwise != this.clockwise ||
-            fontSizePx != this.fontSizePx ||
-            arcPaddingPx != this.arcPaddingPx
+            fontSizePx != this.fontSizePx
         ) {
             this.text = text
             this.clockwise = clockwise
             this.fontSizePx = fontSizePx
-            this.arcPaddingPx = arcPaddingPx
             doUpdate()
             lastLayoutInfo = null // Ensure paths are recomputed
         }
@@ -77,10 +73,9 @@
         val rect = android.graphics.Rect()
         paint.getTextBounds(text, 0, text.length, rect)
 
-        textWidth = rect.width() + arcPaddingPx.before + arcPaddingPx.after
-        textHeight = -paint.fontMetrics.top + paint.fontMetrics.bottom +
-            arcPaddingPx.inner + arcPaddingPx.outer
-        baseLinePosition = arcPaddingPx.outer +
+        textWidth = rect.width().toFloat()
+        textHeight = -paint.fontMetrics.top + paint.fontMetrics.bottom
+        baseLinePosition =
             if (clockwise) -paint.fontMetrics.top else paint.fontMetrics.bottom
     }
 
@@ -90,9 +85,6 @@
             with(layoutInfo) {
                 val clockwiseFactor = if (clockwise) 1f else -1f
 
-                val paddingBeforeAsAngle = (arcPaddingPx.before / measureRadius)
-                    .toDegrees()
-                    .coerceAtMost(360f)
                 val sweepDegree = sweepRadians.toDegrees().coerceAtMost(360f)
 
                 val centerX = centerOffset.x
@@ -125,8 +117,7 @@
                     centerX + measureRadius,
                     centerY + measureRadius,
                     startAngleRadians.toDegrees() +
-                        (if (clockwise) paddingBeforeAsAngle
-                        else sweepDegree - paddingBeforeAsAngle),
+                        (if (clockwise) 0f else sweepDegree),
                     clockwiseFactor * sweepDegree
                 )
             }
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/BasicCurvedText.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/BasicCurvedText.kt
index 70a9ac5..ebb4b39 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/BasicCurvedText.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/BasicCurvedText.kt
@@ -17,97 +17,11 @@
 package androidx.wear.compose.foundation
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-
-/**
- * Apply additional space along each edge of the content in [Dp].
- * See the [ArcPaddingValues] factories for convenient ways to
- * build [ArcPaddingValues].
- */
-@Stable
-public interface ArcPaddingValues {
-    /**
-     * Padding in the outward direction from the center of the [CurvedLayout]
-     */
-    fun calculateOuterPadding(): Dp
-
-    /**
-     * Padding in the inwards direction towards the center of the [CurvedLayout]
-     */
-    fun calculateInnerPadding(): Dp
-
-    /**
-     * Padding added at the start of the component.
-     */
-    fun calculateStartPadding(): Dp
-
-    /**
-     * Padding added at the end of the component.
-     */
-    fun calculateEndPadding(): Dp
-}
-
-/**
- * Apply additional space along each edge of the content in [Dp]. Note that the start and end
- * edges will be determined by the direction (clockwise or counterclockwise)
- *
- * @param outer Padding in the outward direction from the center of the
- * [CurvedLayout]
- * @param inner Padding in the inwards direction towards the center of the [CurvedLayout]
- * @param start Padding added at the start of the component.
- * @param end Padding added at the end of the component.
- */
-public fun ArcPaddingValues(
-    outer: Dp = 0.dp,
-    inner: Dp = 0.dp,
-    start: Dp = 0.dp,
-    end: Dp = 0.dp
-): ArcPaddingValues =
-    ArcPaddingValuesImpl(outer, inner, start, end)
-
-/**
- * Apply [all] dp of additional space along each edge of the content.
- */
-public fun ArcPaddingValues(all: Dp): ArcPaddingValues = ArcPaddingValuesImpl(all, all, all, all)
-
-/**
- * Apply [radial] dp of additional space on the edges towards and away from the center, and
- * [angular] dp before and after the component.
- */
-public fun ArcPaddingValues(radial: Dp = 0.dp, angular: Dp = 0.dp): ArcPaddingValues =
-    ArcPaddingValuesImpl(radial, radial, angular, angular)
-
-@Stable
-internal class ArcPaddingValuesImpl(val outer: Dp, val inner: Dp, val start: Dp, val end: Dp) :
-    ArcPaddingValues {
-    override fun equals(other: Any?): Boolean {
-        return other is ArcPaddingValuesImpl &&
-            outer == other.outer &&
-            inner == other.inner &&
-            start == other.start &&
-            end == other.end
-    }
-
-    override fun hashCode() = ((outer.hashCode() * 31 + inner.hashCode()) * 31 + start.hashCode()) *
-        31 + end.hashCode()
-
-    override fun toString(): String {
-        return "ArcPaddingValuesImpl(outer=$outer, inner=$inner, start=$start, end=$end)"
-    }
-
-    override fun calculateOuterPadding() = outer
-    override fun calculateInnerPadding() = inner
-    override fun calculateStartPadding() = start
-    override fun calculateEndPadding() = end
-}
 
 /**
  * [basicCurvedText] is a component allowing developers to easily write curved text following
@@ -123,8 +37,6 @@
  * those needs to be reversed in a Rtl layout.
  * If not specified, it will be inherited from the enclosing [curvedRow] or [CurvedLayout]
  * See [CurvedDirection.Angular].
- * @param contentArcPadding Allows to specify additional space along each "edge" of the content in
- * [Dp] see [ArcPaddingValues]
  * @param overflow How visual overflow should be handled.
  * @param style A @Composable factory to provide the style to use. This composable SHOULDN'T
  * generate any compose nodes.
@@ -133,13 +45,11 @@
     text: String,
     modifier: CurvedModifier = CurvedModifier,
     angularDirection: CurvedDirection.Angular? = null,
-    contentArcPadding: ArcPaddingValues = ArcPaddingValues(0.dp),
     overflow: TextOverflow = TextOverflow.Clip,
     style: @Composable () -> CurvedTextStyle = { CurvedTextStyle() }
 ) = add(CurvedTextChild(
     text,
     curvedLayoutDirection.copy(overrideAngular = angularDirection).clockwise(),
-    contentArcPadding,
     style,
     overflow
 ), modifier)
@@ -159,8 +69,6 @@
  * those needs to be reversed in a Rtl layout.
  * If not specified, it will be inherited from the enclosing [curvedRow] or [CurvedLayout]
  * See [CurvedDirection.Angular].
- * @param contentArcPadding Allows to specify additional space along each "edge" of the content in
- * [Dp] see [ArcPaddingValues]
  * @param overflow How visual overflow should be handled.
  */
 public fun CurvedScope.basicCurvedText(
@@ -168,33 +76,23 @@
     style: CurvedTextStyle,
     modifier: CurvedModifier = CurvedModifier,
     angularDirection: CurvedDirection.Angular? = null,
-    // TODO: reimplement as modifiers
-    contentArcPadding: ArcPaddingValues = ArcPaddingValues(0.dp),
     overflow: TextOverflow = TextOverflow.Clip,
-) = basicCurvedText(text, modifier, angularDirection, contentArcPadding, overflow) { style }
+) = basicCurvedText(text, modifier, angularDirection, overflow) { style }
 
 internal class CurvedTextChild(
     val text: String,
     val clockwise: Boolean = true,
-    val contentArcPadding: ArcPaddingValues = ArcPaddingValues(0.dp),
     val style: @Composable () -> CurvedTextStyle = { CurvedTextStyle() },
     val overflow: TextOverflow
 ) : CurvedChild() {
     private val delegate: CurvedTextDelegate = CurvedTextDelegate()
     private lateinit var actualStyle: CurvedTextStyle
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int {
-        // TODO: move padding into a CurvedModifier
-        val arcPaddingPx = ArcPaddingPx(
-            contentArcPadding.calculateOuterPadding().toPx(),
-            contentArcPadding.calculateInnerPadding().toPx(),
-            contentArcPadding.calculateStartPadding().toPx(),
-            contentArcPadding.calculateEndPadding().toPx()
-        )
-        delegate.updateIfNeeded(text, clockwise, actualStyle.fontSize.toPx(), arcPaddingPx)
+        delegate.updateIfNeeded(text, clockwise, actualStyle.fontSize.toPx())
         return index // No measurables where mapped.
     }
 
@@ -242,13 +140,6 @@
     }
 }
 
-internal data class ArcPaddingPx(
-    val outer: Float,
-    val inner: Float,
-    val before: Float,
-    val after: Float
-)
-
 internal expect class CurvedTextDelegate() {
     var textWidth: Float
     var textHeight: Float
@@ -257,8 +148,7 @@
     fun updateIfNeeded(
         text: String,
         clockwise: Boolean,
-        fontSizePx: Float,
-        arcPaddingPx: ArcPaddingPx
+        fontSizePx: Float
     )
 
     fun DrawScope.doDraw(
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedComposable.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedComposable.kt
index 5cdb192..d6c4559 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedComposable.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedComposable.kt
@@ -21,7 +21,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.TransformOrigin
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.unit.Constraints
 import kotlin.math.PI
@@ -62,7 +61,7 @@
         Box(content = content)
     }
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int {
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
index bff6b0a..a71600b 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
@@ -20,7 +20,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 
 /**
@@ -35,10 +34,6 @@
     internal fun add(node: CurvedChild, modifier: CurvedModifier) {
         nodes.add(modifier.wrap(node))
     }
-    internal fun initialize(contentBuilder: CurvedScope.() -> Unit) {
-        nodes.clear()
-        apply(contentBuilder)
-    }
 }
 
 /**
@@ -47,9 +42,9 @@
 internal abstract class ContainerChild(
     curvedLayoutDirection: CurvedLayoutDirection,
     internal val reverseLayout: Boolean,
-    private val contentBuilder: CurvedScope.() -> Unit
+    contentBuilder: CurvedScope.() -> Unit
 ) : CurvedChild() {
-    private val curvedContainerScope = CurvedScope(curvedLayoutDirection)
+    private val curvedContainerScope = CurvedScope(curvedLayoutDirection).apply(contentBuilder)
     internal val children get() = curvedContainerScope.nodes
 
     internal val childrenInLayoutOrder get() = children.indices.map { ix ->
@@ -58,20 +53,22 @@
 
     @Composable
     override fun SubComposition() {
-        // Ensure we subscribe this composition to any state reads on contentBuilder,
-        // and we keep our internal tree in sync with compose's tree.
-        curvedContainerScope.initialize(contentBuilder)
         children.forEach {
             it.SubComposition()
         }
     }
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ) = children.fold(index) { currentIndex, node ->
-            with(node) {
-                initializeMeasure(measurables, currentIndex)
+            with(CurvedMeasureScope(
+                subDensity = this,
+                curvedContainerScope.curvedLayoutDirection
+            )) {
+                with(node) {
+                    initializeMeasure(measurables, currentIndex)
+                }
             }
         }
 
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedDirection.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedDirection.kt
index 8be4e91..716be35 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedDirection.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedDirection.kt
@@ -29,6 +29,23 @@
     @Immutable
     @kotlin.jvm.JvmInline
     public value class Angular internal constructor(internal val value: Int) {
+        /**
+         * Determine if the layout is going clockwise or counter-clockwise given the layout
+         * direction and this angular layout direction.
+         *
+         * @param layoutDirection The [LayoutDirection] to resolve this with.
+         */
+        internal fun resolveClockwise(layoutDirection: LayoutDirection): Boolean {
+            val isLtr = layoutDirection == LayoutDirection.Ltr
+            return when (this) {
+                Reversed -> !isLtr
+                Clockwise -> true
+                CounterClockwise -> false
+                // Normal
+                else -> isLtr
+            }
+        }
+
         companion object {
             /**
              * Go in Clockwise direction for Ltr layout and Counter Clockwise for Rtl.
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
index 199a7da..bb0110c 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
@@ -19,10 +19,8 @@
 import androidx.compose.foundation.layout.Row
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
@@ -30,9 +28,9 @@
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.LayoutDirection
 import kotlin.math.PI
 import kotlin.math.cos
@@ -109,11 +107,11 @@
     // Note that all angles in the function are in radians, and the anchor parameter is in degrees
 
     val curvedLayoutDirection = initialCurvedLayoutDirection(angularDirection)
-    val curvedRowChild by remember(curvedLayoutDirection, radialAlignment, contentBuilder) {
-        derivedStateOf {
-            CurvedRowChild(curvedLayoutDirection, radialAlignment, contentBuilder)
-        }
-    }
+
+    // Create the curved tree and subscribe to be recomposed when any part changes, this may not be
+    // optimal but since we have only one measure block (the one here) for all the curved layout,
+    // we still need to do most of the work when content changes.
+    val curvedRowChild = CurvedRowChild(curvedLayoutDirection, radialAlignment, contentBuilder)
 
     Layout(
         modifier = modifier.drawWithContent {
@@ -135,9 +133,11 @@
 
         // Give the curved row scope the information needed to measure and map measurables
         // to children.
-        with(curvedRowChild) {
-            val mapped = initializeMeasure(measurables, 0)
-            require(mapped == measurables.size)
+        with(CurvedMeasureScope(subDensity = this, curvedLayoutDirection)) {
+            with(curvedRowChild) {
+                val mapped = initializeMeasure(measurables, 0)
+                require(mapped == measurables.size)
+            }
         }
 
         curvedRowChild.estimateThickness(radius)
@@ -166,24 +166,14 @@
 // TODO() For performance, to avoid class extra creation/destruction, we could implement this class
 //  as a bit field.
 internal class CurvedLayoutDirection(
-    private val radial: CurvedDirection.Radial,
-    private val angular: CurvedDirection.Angular,
-    private val layoutDirection: LayoutDirection
+    internal val radial: CurvedDirection.Radial,
+    internal val angular: CurvedDirection.Angular,
+    internal val layoutDirection: LayoutDirection
 ) {
-    fun clockwise(): Boolean {
-        return when (angular) {
-            CurvedDirection.Angular.Reversed -> !isLtr()
-            CurvedDirection.Angular.Clockwise -> true
-            CurvedDirection.Angular.CounterClockwise -> false
-            // CurvedDirection.Angular.Clockwise
-            else -> isLtr()
-        }
-    }
+    fun clockwise(): Boolean = angular.resolveClockwise(layoutDirection)
 
     fun outsideIn(): Boolean = radial == CurvedDirection.Radial.OutsideIn
 
-    fun isLtr(): Boolean = layoutDirection == LayoutDirection.Ltr
-
     fun copy(
         overrideRadial: CurvedDirection.Radial? = null,
         overrideAngular: CurvedDirection.Angular? = null
@@ -266,6 +256,12 @@
     val measureRadius: Float, // TODO: remove this from here or generalize
 )
 
+// Similar to IntrinsicMeasureScope
+internal class CurvedMeasureScope(
+    val subDensity: Density,
+    val curvedLayoutDirection: CurvedLayoutDirection
+) : Density by subDensity
+
 /**
  * Base class for children of a [CurvedLayout].
  *
@@ -299,6 +295,10 @@
     internal val sweepRadians: Float
         get() = partialLayoutInfo.sweepRadians
 
+    // Exposed as is needed in padding modifiers to translate distances to angles.
+    internal val measureRadius: Float
+        get() = partialLayoutInfo.measureRadius
+
     /**
      * Compose the content. This may generate some compose-ui nodes, but has to match
      * initializeMeasure's matching behavior (initializeMeasure should return the index parameter +
@@ -316,7 +316,7 @@
      * @return The new index in the measurables array, taking into account how many items we
      * mapped.
      */
-    open fun MeasureScope.initializeMeasure(
+    open fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int = index
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedModifier.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedModifier.kt
index a2a49b4..1a6ebb62 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedModifier.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedModifier.kt
@@ -21,7 +21,6 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 
 /**
@@ -84,7 +83,7 @@
     @Composable
     override fun SubComposition() { wrapped.SubComposition() }
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int = with(wrapped) {
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedPadding.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedPadding.kt
new file mode 100644
index 0000000..43be9c2
--- /dev/null
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedPadding.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.foundation
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+
+/**
+ * Apply additional space along the edges of the content.
+ *
+ * @param paddingValues The [ArcPaddingValues] to use. See that class and factory methods to see
+ * how paddings can be specified.
+ */
+public fun CurvedModifier.padding(paddingValues: ArcPaddingValues) =
+    this.then { child -> PaddingWrapper(child, paddingValues) }
+
+/**
+ * Apply additional space along the edges of the content. Dimmensions are in dp. For before and
+ * after they will be considered as if they are at the midpoint of the content (for conversion
+ * between dimension and angle).
+ *
+ * @param outer The space to add to the outer edge of the content (away from the center of the
+ * containing CurvedLayout)
+ * @param inner The space to add to the inner edge of the content (towards the center of the
+ * containing CurvedLayout)
+ * @param before The space added before the component, if it was draw clockwise. This is the edge of
+ * the component with the "smallest" angle.
+ * @param after The space added after the component, if it was draw clockwise. This is the edge of
+ * the component with the "biggest" angle.
+ */
+public fun CurvedModifier.padding(outer: Dp, inner: Dp, before: Dp, after: Dp) =
+    padding(ArcPaddingValuesImpl(outer, inner, before, after))
+
+/**
+ * Apply [angular] dp space before and after the component, and [radial] dp space to the outer and
+ * inner edges.
+ *
+ * @param radial The space added to the outer and inner edges of the content, in dp.
+ * @param angular The space added before and after the content, in dp.
+ */
+public fun CurvedModifier.padding(radial: Dp = 0.dp, angular: Dp = 0.dp) =
+    padding(radial, radial, angular, angular)
+
+/**
+ * Apply [all] dp space around the component.
+ *
+ * @param all The space added to all edges.
+ */
+public fun CurvedModifier.padding(all: Dp = 0.dp) = padding(all, all, all, all)
+
+/**
+ * Apply additional space along each edge of the content in [Dp].
+ * See the [ArcPaddingValues] factories for convenient ways to
+ * build [ArcPaddingValues].
+ */
+@Stable
+public interface ArcPaddingValues {
+    /**
+     * Padding in the outward direction from the center of the [CurvedLayout]
+     */
+    fun calculateOuterPadding(radialDirection: CurvedDirection.Radial): Dp
+
+    /**
+     * Padding in the inwards direction towards the center of the [CurvedLayout]
+     */
+    fun calculateInnerPadding(radialDirection: CurvedDirection.Radial): Dp
+
+    /**
+     * Padding added before the component, if it was draw clockwise. This is the edge of the
+     * component with the "smallest" angle.
+     */
+    fun calculateAfterPadding(
+        layoutDirection: LayoutDirection,
+        angularDirection: CurvedDirection.Angular
+    ): Dp
+
+    /**
+     * Padding added after the component, if it was draw clockwise. This is the edge of the
+     * component with the "biggest" angle.
+     */
+    fun calculateBeforePadding(
+        layoutDirection: LayoutDirection,
+        angularDirection: CurvedDirection.Angular
+    ): Dp
+}
+
+/**
+ * Apply additional space along each edge of the content in [Dp]. Note that that all dimensions are
+ * applied to a concrete edge, indepenend on layout direction and curved layout direction.
+ *
+ * @param outer Padding in the outward direction from the center of the
+ * [CurvedLayout]
+ * @param inner Padding in the inwards direction towards the center of the [CurvedLayout]
+ * @param before Padding added before the component, if it was draw clockwise.
+ * @param after Padding added after the component, if it was draw clockwise.
+ */
+public fun ArcPaddingValues(
+    outer: Dp = 0.dp,
+    inner: Dp = 0.dp,
+    before: Dp = 0.dp,
+    after: Dp = 0.dp
+): ArcPaddingValues =
+    ArcPaddingValuesImpl(outer, inner, before, after)
+
+/**
+ * Apply [all] dp of additional space along each edge of the content.
+ */
+public fun ArcPaddingValues(all: Dp): ArcPaddingValues = ArcPaddingValuesImpl(all, all, all, all)
+
+/**
+ * Apply [radial] dp of additional space on the edges towards and away from the center, and
+ * [angular] dp before and after the component.
+ */
+public fun ArcPaddingValues(radial: Dp = 0.dp, angular: Dp = 0.dp): ArcPaddingValues =
+    ArcPaddingValuesImpl(radial, radial, angular, angular)
+
+@Immutable
+internal class ArcPaddingValuesImpl(val outer: Dp, val inner: Dp, val before: Dp, val after: Dp) :
+    ArcPaddingValues {
+    override fun equals(other: Any?): Boolean {
+        return other is ArcPaddingValuesImpl &&
+            outer == other.outer &&
+            inner == other.inner &&
+            before == other.before &&
+            after == other.after
+    }
+
+    override fun hashCode() = ((outer.hashCode() * 31 + inner.hashCode()) * 31 +
+        before.hashCode()) * 31 + after.hashCode()
+
+    override fun toString(): String {
+        return "ArcPaddingValuesImpl(outer=$outer, inner=$inner, before=$before, after=$after)"
+    }
+
+    override fun calculateOuterPadding(radialDirection: CurvedDirection.Radial) = outer
+    override fun calculateInnerPadding(radialDirection: CurvedDirection.Radial) = inner
+    override fun calculateBeforePadding(
+        layoutDirection: LayoutDirection,
+        angularDirection: CurvedDirection.Angular
+    ) = before
+    override fun calculateAfterPadding(
+        layoutDirection: LayoutDirection,
+        angularDirection: CurvedDirection.Angular
+    ) = after
+}
+
+internal class PaddingWrapper(
+    child: CurvedChild,
+    val paddingValues: ArcPaddingValues
+) : BaseCurvedChildWrapper(child) {
+    private var outerPx = 0f
+    private var innerPx = 0f
+    private var beforePx = 0f
+    private var afterPx = 0f
+
+    override fun CurvedMeasureScope.initializeMeasure(
+        measurables: List<Measurable>,
+        index: Int
+    ): Int {
+        outerPx = paddingValues.calculateOuterPadding(curvedLayoutDirection.radial).toPx()
+        innerPx = paddingValues.calculateInnerPadding(curvedLayoutDirection.radial).toPx()
+        beforePx = paddingValues.calculateBeforePadding(
+            curvedLayoutDirection.layoutDirection,
+            curvedLayoutDirection.angular
+        ).toPx()
+        afterPx = paddingValues.calculateAfterPadding(
+            curvedLayoutDirection.layoutDirection,
+            curvedLayoutDirection.angular
+        ).toPx()
+        return with(wrapped) {
+            initializeMeasure(measurables, index)
+        }
+    }
+
+    override fun doEstimateThickness(maxRadius: Float) = wrapped.estimateThickness(maxRadius) +
+        outerPx + innerPx
+
+    override fun doRadialPosition(
+        parentOuterRadius: Float,
+        parentThickness: Float
+    ): PartialLayoutInfo {
+        val partialLayoutInfo = wrapped.radialPosition(
+            parentOuterRadius - outerPx,
+            parentThickness - outerPx - innerPx
+        )
+        val angularPadding = (beforePx + afterPx) / partialLayoutInfo.measureRadius
+        return PartialLayoutInfo(
+            partialLayoutInfo.sweepRadians + angularPadding,
+            partialLayoutInfo.outerRadius + outerPx,
+            partialLayoutInfo.thickness + innerPx + outerPx,
+            partialLayoutInfo.measureRadius + outerPx
+        )
+    }
+
+    override fun doAngularPosition(
+        parentStartAngleRadians: Float,
+        parentSweepRadians: Float,
+        centerOffset: Offset
+    ): Float {
+        val startAngularPadding = beforePx / measureRadius
+        val angularPadding = (beforePx + afterPx) / measureRadius
+        return wrapped.angularPosition(
+            parentStartAngleRadians + startAngularPadding,
+            parentSweepRadians - angularPadding,
+            centerOffset
+        ) - startAngularPadding
+    }
+}
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
index 1630e35..79c9786 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 
@@ -92,7 +91,7 @@
     private var minThicknessPx = 0f
     private var maxThicknessPx = 0f
 
-    override fun MeasureScope.initializeMeasure(
+    override fun CurvedMeasureScope.initializeMeasure(
         measurables: List<Measurable>,
         index: Int
     ): Int {
diff --git a/wear/compose/compose-foundation/src/desktopMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.desktop.kt b/wear/compose/compose-foundation/src/desktopMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.desktop.kt
index 695e7f4..8c4c9c4 100644
--- a/wear/compose/compose-foundation/src/desktopMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.desktop.kt
+++ b/wear/compose/compose-foundation/src/desktopMain/kotlin/androidx/wear/compose/foundation/CurvedTextDelegate.desktop.kt
@@ -28,8 +28,7 @@
     actual fun updateIfNeeded(
         text: String,
         clockwise: Boolean,
-        fontSizePx: Float,
-        arcPaddingPx: ArcPaddingPx
+        fontSizePx: Float
     ) {
         // TODO(b/194653251): Implement
         throw java.lang.RuntimeException("Not implemented")
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index b60025f..01ec528 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -40,9 +44,9 @@
   }
 
   public final class CardKt {
-    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Stable public interface ChipColors {
@@ -138,7 +142,7 @@
   }
 
   public final class CurvedTextKt {
-    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public final class DefaultTimeSourceKt {
@@ -328,7 +332,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -515,10 +519,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
diff --git a/wear/compose/compose-material/api/public_plus_experimental_current.txt b/wear/compose/compose-material/api/public_plus_experimental_current.txt
index b285cf4..0d98e8b 100644
--- a/wear/compose/compose-material/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-material/api/public_plus_experimental_current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -40,9 +44,9 @@
   }
 
   public final class CardKt {
-    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Stable public interface ChipColors {
@@ -138,7 +142,7 @@
   }
 
   public final class CurvedTextKt {
-    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public final class DefaultTimeSourceKt {
@@ -354,7 +358,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -551,10 +555,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index b60025f..01ec528 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -40,9 +44,9 @@
   }
 
   public final class CardKt {
-    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AppCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> appName, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> time, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? appImage, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long appColor, optional long timeColor, optional long titleColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TitleCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? time, optional androidx.compose.ui.graphics.painter.Painter backgroundPainter, optional long contentColor, optional long titleColor, optional long timeColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Stable public interface ChipColors {
@@ -138,7 +142,7 @@
   }
 
   public final class CurvedTextKt {
-    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding, optional int overflow);
+    method public static void curvedText(androidx.wear.compose.foundation.CurvedScope, String text, optional androidx.wear.compose.foundation.CurvedModifier modifier, optional long background, optional long color, optional long fontSize, optional androidx.wear.compose.foundation.CurvedTextStyle? style, optional androidx.wear.compose.foundation.CurvedDirection.Angular? angularDirection, optional int overflow);
   }
 
   public final class DefaultTimeSourceKt {
@@ -328,7 +332,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -515,10 +519,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
diff --git a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
index f38a020..976c4ce2 100644
--- a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
+++ b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.AutoCenteringParams
 import androidx.wear.compose.material.Chip
 import androidx.wear.compose.material.ChipDefaults
 import androidx.wear.compose.material.ListHeader
@@ -92,7 +93,8 @@
     ScalingLazyColumn(
         anchorType = ScalingLazyListAnchorType.ItemStart,
         verticalArrangement = Arrangement.spacedBy(itemSpacing),
-        state = state
+        state = state,
+        autoCentering = AutoCenteringParams(itemOffset = scrollOffset)
     ) {
         item {
             ListHeader {
@@ -119,7 +121,7 @@
 fun SimpleScalingLazyColumnWithContentPadding() {
     ScalingLazyColumn(
         contentPadding = PaddingValues(top = 20.dp, bottom = 20.dp),
-        autoCentering = false
+        autoCentering = null
     ) {
         item {
             ListHeader {
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardTest.kt
index f516fda..63805c3 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardTest.kt
@@ -184,6 +184,110 @@
     }
 }
 
+public class AppCardTest {
+    @get:Rule
+    public val rule: ComposeContentTestRule = createComposeRule()
+
+    @Test
+    public fun responds_to_click_when_enabled() {
+        var clicked = false
+
+        rule.setContentWithTheme {
+            AppCard(
+                onClick = { clicked = true },
+                enabled = true,
+                appName = {},
+                time = {},
+                title = {},
+                modifier = Modifier.testTag(TEST_TAG)
+            ) {
+                TestImage()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            assertEquals(true, clicked)
+        }
+    }
+
+    @Test
+    public fun does_not_respond_to_click_when_disabled() {
+        var clicked = false
+
+        rule.setContentWithTheme {
+            AppCard(
+                onClick = { clicked = true },
+                appName = {},
+                time = {},
+                title = {},
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            ) {
+                TestImage()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            assertEquals(false, clicked)
+        }
+    }
+}
+
+public class TitleCardTest {
+    @get:Rule
+    public val rule: ComposeContentTestRule = createComposeRule()
+
+    @Test
+    public fun responds_to_click_when_enabled() {
+        var clicked = false
+
+        rule.setContentWithTheme {
+            TitleCard(
+                onClick = { clicked = true },
+                enabled = true,
+                time = {},
+                title = {},
+                modifier = Modifier.testTag(TEST_TAG)
+            ) {
+                TestImage()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            assertEquals(true, clicked)
+        }
+    }
+
+    @Test
+    public fun does_not_respond_to_click_when_disabled() {
+        var clicked = false
+
+        rule.setContentWithTheme {
+            TitleCard(
+                onClick = { clicked = true },
+                enabled = false,
+                time = {},
+                title = {},
+                modifier = Modifier.testTag(TEST_TAG)
+            ) {
+                TestImage()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            assertEquals(false, clicked)
+        }
+    }
+}
+
 public class CardSizeTest {
     @get:Rule
     public val rule: ComposeContentTestRule = createComposeRule()
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
index dd3eb02..4ea531b 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
@@ -118,7 +118,7 @@
                 modifier = Modifier
                     .onSizeChanged { viewPortHeight = it.height }
                     .requiredSize(itemSizeDp * 3.5f + itemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(3) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -189,7 +189,7 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSize() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = true,
+            enableAutoCentering = true,
             contentPadding = PaddingValues(0.dp)
         )
     }
@@ -197,7 +197,7 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSizeWithContentPadding() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = true,
+            enableAutoCentering = true,
             contentPadding = PaddingValues(50.dp)
         )
     }
@@ -205,13 +205,13 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSizeWithContentPaddingNoAutoCenter() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = false,
+            enableAutoCentering = false,
             contentPadding = PaddingValues(50.dp)
         )
     }
 
     private fun scrollableScalingLazyColumnPositionAndSize(
-        autoCentering: Boolean,
+        enableAutoCentering: Boolean,
         contentPadding: PaddingValues
     ) {
         lateinit var state: ScalingLazyListState
@@ -230,7 +230,8 @@
                         itemSizeDp * 3f + itemSpacingDp * 2f
                     ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f),
-                autoCentering = autoCentering,
+                autoCentering = if (enableAutoCentering)
+                    AutoCenteringParams(itemIndex = 0) else null,
                 contentPadding = contentPadding
             ) {
                 items(5) {
@@ -325,7 +326,7 @@
                     .fillMaxWidth()
                     .requiredSize(itemSizeDp * 3.5f + itemSpacingDp * 2.5f)
                     .background(Color.DarkGray),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(3) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -371,7 +372,7 @@
                     )
                     .background(Color.DarkGray),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
index 8d050db..1a3cbe7 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
@@ -98,7 +98,7 @@
                 state = rememberScalingLazyListState(initialCenterItemIndex = 0)
                     .also { state = it },
                 modifier = Modifier.height(200.dp),
-                autoCentering = false,
+                autoCentering = null,
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f)
             ) {
                 itemsIndexed(items) { index, item ->
@@ -130,7 +130,7 @@
                 state = rememberScalingLazyListState(initialCenterItemIndex = 0)
                     .also { state = it },
                 modifier = Modifier.height(viewPortHeight),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(itemIndex = 0),
                 verticalArrangement = Arrangement.spacedBy(gapBetweenItems),
                 // No scaling as we are doing maths with expected item sizes
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f)
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
index 3d17741..850300e 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
@@ -87,7 +87,7 @@
                     state = rememberScalingLazyListState().also { state = it },
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(listSize),
                     anchorType = ScalingLazyListAnchorType.ItemCenter,
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(),
                     verticalArrangement = Arrangement.spacedBy(0.dp),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(
                         edgeScale = 0f,
@@ -139,7 +139,7 @@
                     state = rememberScalingLazyListState().also { state = it },
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(listSize),
                     anchorType = ScalingLazyListAnchorType.ItemStart,
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(),
                     verticalArrangement = Arrangement.spacedBy(0.dp),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(
                         edgeScale = 0f,
@@ -192,7 +192,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -224,7 +224,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = false,
+                    autoCentering = null,
                     userScrollEnabled = false
                 ) {
                     items(5) {
@@ -259,7 +259,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true
+                    autoCentering = AutoCenteringParams(itemIndex = 0)
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -292,7 +292,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(itemIndex = 0),
                     flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state)
                 ) {
                     items(5) {
@@ -337,7 +337,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(itemIndex = 0),
                     flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(
                         state = state,
                         snapOffset = snapOffset
@@ -381,7 +381,7 @@
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
                     reverseLayout = true,
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -414,6 +414,7 @@
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                    autoCentering = AutoCenteringParams(itemIndex = 0)
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp).testTag("Item:" + it))
@@ -492,7 +493,7 @@
                     modifier = Modifier
                         .testTag(TEST_TAG)
                         .requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(6) {
                         Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
index a1ae7e9..c39f251 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
@@ -77,7 +77,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true
+                autoCentering = AutoCenteringParams()
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -103,7 +103,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp)
             ) {
                 items(5) {
@@ -129,7 +129,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp)
             ) {
                 items(5) {
@@ -155,7 +155,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp),
                 reverseLayout = true
             ) {
@@ -183,7 +183,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -209,7 +209,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -234,7 +234,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -261,7 +261,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = true
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -287,7 +287,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -314,7 +314,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp * 5))
@@ -404,7 +404,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -569,6 +569,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(
@@ -661,6 +662,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -700,7 +702,7 @@
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -736,7 +738,7 @@
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + spacing * 2.5f),
                 verticalArrangement = Arrangement.spacedBy(spacing),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -773,7 +775,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -806,7 +808,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -892,7 +894,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -1026,7 +1028,7 @@
                 state = rememberScalingLazyListState(
                     initialCenterItemIndex = 0
                 ).also { state = it },
-                autoCentering = true
+                autoCentering = AutoCenteringParams()
             ) {
                 items(7) {
                     Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Card.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Card.kt
index ca6aaa8..90eadf9 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Card.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Card.kt
@@ -16,21 +16,21 @@
 
 package androidx.wear.compose.material
 
+import androidx.compose.foundation.Image
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.IntrinsicSize
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.IntrinsicSize
-import androidx.compose.foundation.layout.RowScope
 import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
@@ -174,6 +174,8 @@
  * @param title A slot for displaying the title of the card, expected to be one or two lines of
  * start aligned text of [Typography.button]
  * @param modifier Modifier to be applied to the card
+ * @param enabled Controls the enabled state of the card. When `false`, this card will not
+ * be clickable
  * @param appImage A slot for a small ([CardDefaults.AppImageSize]x[CardDefaults.AppImageSize] )
  * [Image] associated with the application.
  * @param backgroundPainter A painter used to paint the background of the card. A card will
@@ -192,6 +194,7 @@
     time: @Composable RowScope.() -> Unit,
     title: @Composable RowScope.() -> Unit,
     modifier: Modifier = Modifier,
+    enabled: Boolean = true,
     appImage: @Composable (RowScope.() -> Unit)? = null,
     backgroundPainter: Painter = CardDefaults.cardBackgroundPainter(),
     contentColor: Color = MaterialTheme.colors.onSurfaceVariant,
@@ -204,7 +207,7 @@
         onClick = onClick,
         modifier = modifier,
         backgroundPainter = backgroundPainter,
-        enabled = true,
+        enabled = enabled,
     ) {
         Column {
             Row(
@@ -283,6 +286,8 @@
  * @param title A slot for displaying the title of the card, expected to be one or two lines of text
  * of [Typography.button]
  * @param modifier Modifier to be applied to the card
+ * @param enabled Controls the enabled state of the card. When `false`, this card will not
+ * be clickable
  * @param time An optional slot for displaying the time relevant to the contents of the card,
  * expected to be a short piece of end aligned text.
  * @param backgroundPainter A painter used to paint the background of the card. A title card can
@@ -298,6 +303,7 @@
     onClick: () -> Unit,
     title: @Composable RowScope.() -> Unit,
     modifier: Modifier = Modifier,
+    enabled: Boolean = true,
     time: @Composable (RowScope.() -> Unit)? = null,
     backgroundPainter: Painter = CardDefaults.cardBackgroundPainter(),
     contentColor: Color = MaterialTheme.colors.onSurfaceVariant,
@@ -309,7 +315,7 @@
         onClick = onClick,
         modifier = modifier,
         backgroundPainter = backgroundPainter,
-        enabled = true,
+        enabled = enabled,
     ) {
         Column {
             Row(
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/CurvedText.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/CurvedText.kt
index eb8da4f..efc3cda 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/CurvedText.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/CurvedText.kt
@@ -20,16 +20,13 @@
 import androidx.compose.ui.graphics.takeOrElse
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.dp
-import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedDirection
 import androidx.wear.compose.foundation.CurvedLayout
-import androidx.wear.compose.foundation.basicCurvedText
 import androidx.wear.compose.foundation.CurvedModifier
 import androidx.wear.compose.foundation.CurvedScope
 import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.basicCurvedText
 import androidx.wear.compose.foundation.curvedRow
 
 /**
@@ -74,8 +71,6 @@
  * those needs to be reversed in a Rtl layout.
  * If not specified, it will be inherited from the enclosing [curvedRow] or [CurvedLayout]
  * See [CurvedDirection.Angular].
- * @param contentArcPadding Allows to specify additional space along each "edge" of the content in
- * [Dp] see [ArcPaddingValues]
  * @param overflow How visual overflow should be handled.
  */
 public fun CurvedScope.curvedText(
@@ -86,9 +81,8 @@
     fontSize: TextUnit = TextUnit.Unspecified,
     style: CurvedTextStyle? = null,
     angularDirection: CurvedDirection.Angular? = null,
-    contentArcPadding: ArcPaddingValues = ArcPaddingValues(0.dp),
     overflow: TextOverflow = TextOverflow.Clip,
-) = basicCurvedText(text, modifier, angularDirection, contentArcPadding, overflow) {
+) = basicCurvedText(text, modifier, angularDirection, overflow) {
     val baseStyle = style ?: CurvedTextStyle(LocalTextStyle.current)
     val textColor = color.takeOrElse {
         baseStyle.color.takeOrElse {
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
index 9b737ad..2bcb66a 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
@@ -200,6 +200,69 @@
     }
 }
 
+/**
+ * Parameters to determine which list item and offset to calculate auto-centering spacing for. The
+ * default values are [itemIndex] = 1 and [itemOffset] = 0. This will provide sufficient padding for
+ * the second item (index = 1) in the list being centerable. This is to match the Wear UX
+ * guidelines that a typical list will have a ListHeader item as the first item in the list
+ * (index = 0) and that this should not be scrollable into the middle of the viewport, instead the
+ * first list item that a user can interact with (index = 1) would be the first that would be in the
+ * center.
+ *
+ * If your use case is different and you want all list items to be able to be scrolled to the
+ * viewport middle, including the first item in the list then set [itemIndex] = 0.
+ *
+ * The higher the value for [itemIndex] you provide the less auto centering padding will be
+ * provided as the amount of padding needed to allow that item to be centered will reduce.
+ * Even for a list of short items (such as [CompactChip]) setting [itemIndex] above 3 or 4 is likely
+ * to result in no auto-centering padding being provided as items with index 3 or 4 will probably
+ * already be naturally scrollable to the center of the viewport.
+ *
+ * [itemOffset] allows adjustment of the items position relative the [ScalingLazyColumn]s
+ * [ScalingLazyListAnchorType]. This can be useful if you need fine grained control over item
+ * positioning and spacing, e.g. If you are lining up the gaps between two items on the viewport
+ * center line where you would want to set the offset to half the distance between listItems in
+ * pixels.
+ *
+ * See also [rememberScalingLazyListState] where similar fields are provided to allow control over
+ * the initially selected centered item index and offset. By default these match the auto centering
+ * defaults meaning that the second item (index = 1) will be the item scrolled to the viewport
+ * center.
+ *
+ * @param itemIndex Which list item index to enable auto-centering from. Space (padding) will be
+ * added such that items with index [itemIndex] or greater will be able to be scrolled to the center
+ * of the viewport. If the developer wants to add additional space to allow other list items to also
+ * be scrollable to the center they can use contentPadding on the ScalingLazyColumn. If the
+ * developer wants custom control over position and spacing they can switch off autoCentering
+ * and provide contentPadding.
+ *
+ * @param itemOffset What offset, if any, to apply when calculating space for auto-centering
+ * the [itemIndex] item. E.g. itemOffset can be used if the developer wants to align the viewport
+ * center in the gap between two list items.
+ *
+ * For an example of a [ScalingLazyColumn] with an explicit itemOffset see:
+ * @sample androidx.wear.compose.material.samples.ScalingLazyColumnEdgeAnchoredAndAnimatedScrollTo
+ */
+@Immutable
+public class AutoCenteringParams(
+    // @IntRange(from = 0)
+    internal val itemIndex: Int = 1,
+    internal val itemOffset: Int = 0,
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        return (other is AutoCenteringParams) &&
+            itemIndex == other.itemIndex &&
+            itemOffset == other.itemOffset
+    }
+
+    override fun hashCode(): Int {
+        var result = itemIndex
+        result = 31 * result + itemOffset
+        return result
+    }
+}
+
 internal fun convertToCenterOffset(
     anchorType: ScalingLazyListAnchorType,
     itemScrollOffset: Int,
@@ -262,14 +325,14 @@
  * @param scalingParams The parameters to configure the scaling and transparency effects for the
  * component
  * @param anchorType How to anchor list items to the center-line of the viewport
- * @param autoCentering Flag to indicate whether space/padding should be automatically added to make
- * sure that list items can be scrolled into the center of the viewport (based on their
- * [anchorType]). If true then space will be added before the first list item, if needed, to ensure
- * that items with indexes greater than or equal to the initialCenterItemIndex passed to
- * [ScalingLazyListState] will be able to be scrolled to the center. Similarly space will be added
- * at the end of the list to ensure that items can be scrolled up to the center. If false no
- * automatic space will be added and instead the developer can use [contentPadding] to manually
- * arrange the items.
+ * @param autoCentering AutoCenteringParams parameter to control whether space/padding should be
+ * automatically added to make sure that list items can be scrolled into the center of the viewport
+ * (based on their [anchorType]). If non-null then space will be added before the first list item,
+ * if needed, to ensure that items with indexes greater than or equal to the itemIndex (offset by
+ * itemOffset pixels) will be able to be scrolled to the center of the viewport. Similarly space
+ * will be added at the end of the list to ensure that items can be scrolled up to the center. If
+ * null no automatic space will be added and instead the developer can use [contentPadding] to
+ * manually arrange the items.
  */
 @Composable
 public fun ScalingLazyColumn(
@@ -287,7 +350,7 @@
     userScrollEnabled: Boolean = true,
     scalingParams: ScalingParams = ScalingLazyColumnDefaults.scalingParams(),
     anchorType: ScalingLazyListAnchorType = ScalingLazyListAnchorType.ItemCenter,
-    autoCentering: Boolean = true,
+    autoCentering: AutoCenteringParams? = AutoCenteringParams(),
     content: ScalingLazyListScope.() -> Unit
 ) {
     var initialized by remember { mutableStateOf(false) }
@@ -360,7 +423,7 @@
                 )
                 // Only add spacers if autoCentering == true as we have to consider the impact of
                 // vertical spacing between items.
-                if (autoCentering) {
+                if (autoCentering != null) {
                     item {
                         Spacer(
                             modifier = Modifier.height(state.topAutoCenteringItemSizePx.toDp())
@@ -368,7 +431,7 @@
                     }
                 }
                 scope.content()
-                if (autoCentering) {
+                if (autoCentering != null) {
                     item {
                         Spacer(
                             modifier = Modifier.height(state.bottomAutoCenteringItemSizePx.toDp())
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index f5a3607..88e9896 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -346,7 +346,7 @@
     scalingParams: ScalingParams,
     beforeContentPaddingPx: Int,
     anchorType: ScalingLazyListAnchorType,
-    autoCentering: Boolean,
+    autoCentering: AutoCenteringParams?,
     initialized: Boolean
 ): ScalingLazyListItemInfo {
     val adjustedItemStart = itemStart - verticalAdjustment
@@ -381,7 +381,7 @@
     )
     return DefaultScalingLazyListItemInfo(
         // Adjust index to take into account the Spacer before the first list item
-        index = if (autoCentering) item.index - 1 else item.index,
+        index = if (autoCentering != null) item.index - 1 else item.index,
         key = item.key,
         unadjustedOffset = unadjustedOffset,
         offset = offset,
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
index 04e33f8..6ba18f5 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
@@ -39,12 +39,7 @@
  *
  * @param initialCenterItemIndex the initial value for [ScalingLazyListState.centerItemIndex],
  * defaults to 1. This will place the 2nd list item (index == 1) in the center of the viewport and
- * the first item (index == 0) before it. Note that if [ScalingLazyColumn] autoCentering property is
- * set to true then space (padding) will be added such that items with index
- * [initialCenterItemIndex] or greater will be able to be scrolled to the center of the viewport. If
- * the developer wants to add additional space to allow other list items to also be scrollable to
- * the center they can use contentPadding on the ScalingLazyColumn. If the developer wants custom
- * control over position and spacing they can switch off autoCentering and provide contentPadding.
+ * the first item (index == 0) before it.
  *
  * @param initialCenterItemScrollOffset the initial value for
  * [ScalingLazyListState.centerItemScrollOffset] in pixels
@@ -69,11 +64,7 @@
  *
  * @param initialCenterItemIndex the initial value for [ScalingLazyListState.centerItemIndex],
  * defaults to 1. This will place the 2nd list item (index == 1) in the center of the viewport and
- * the first item (index == 0) before it. Note that if [ScalingLazyColumn] autoCentering property is
- * set to true then space (padding) will be added such that items with index
- * [initialCenterItemIndex] or greater will be able to be scrolled to the center of the viewport. If
- * the developer wants to add additional space to allow other list items to also be scrollable to
- * the center they can use contentPadding on the ScalingLazyColumn.
+ * the first item (index == 0) before it.
  *
  * If the developer wants custom control over position and spacing they can switch off autoCentering
  * and provide contentPadding.
@@ -96,7 +87,7 @@
     internal val viewportHeightPx = mutableStateOf<Int?>(null)
     internal val reverseLayout = mutableStateOf<Boolean?>(null)
     internal val anchorType = mutableStateOf<ScalingLazyListAnchorType?>(null)
-    internal val autoCentering = mutableStateOf<Boolean?>(null)
+    internal val autoCentering = mutableStateOf<AutoCenteringParams?>(null)
     internal val initialized = mutableStateOf<Boolean>(false)
 
     /**
@@ -112,7 +103,7 @@
             gapBetweenItemsPx.value == null || viewportHeightPx.value == null ||
             anchorType.value == null || reverseLayout.value == null ||
             beforeContentPaddingPx.value == null || autoCentering.value == null ||
-            !autoCentering.value!! || layoutInfo.visibleItemsInfo.isEmpty()
+            autoCentering.value == null || layoutInfo.visibleItemsInfo.isEmpty()
         ) {
             0
         } else {
@@ -150,7 +141,7 @@
         if (extraPaddingPx.value == null || scalingParams.value == null ||
             gapBetweenItemsPx.value == null || viewportHeightPx.value == null ||
             anchorType.value == null || reverseLayout.value == null ||
-            beforeContentPaddingPx.value == null || autoCentering.value == null
+            beforeContentPaddingPx.value == null
         ) {
             EmptyScalingLazyListLayoutInfo
         } else {
@@ -184,7 +175,7 @@
                     scalingParams.value!!,
                     beforeContentPaddingPx.value!!,
                     anchorType.value!!,
-                    autoCentering.value!!,
+                    autoCentering.value,
                     initialized.value
                 )
                 visibleItemsInfo.add(
@@ -227,7 +218,7 @@
                                 scalingParams.value!!,
                                 beforeContentPaddingPx.value!!,
                                 anchorType.value!!,
-                                autoCentering.value!!,
+                                autoCentering.value,
                                 initialized.value
                             )
                             visibleItemsInfo.add(0, itemInfo)
@@ -261,7 +252,7 @@
                                 scalingParams.value!!,
                                 beforeContentPaddingPx.value!!,
                                 anchorType.value!!,
-                                autoCentering.value!!,
+                                autoCentering.value,
                                 initialized.value
                             )
 
@@ -274,7 +265,7 @@
                 }
             }
             val totalItemsCount =
-                if (autoCentering.value!!) {
+                if (autoCentering.value != null) {
                     (lazyListState.layoutInfo.totalItemsCount - 2).coerceAtLeast(0)
                 } else {
                     lazyListState.layoutInfo.totalItemsCount
@@ -290,7 +281,7 @@
                 // Not already initialized
                 !initialized.value && (
                     // Not autoCentering
-                    !autoCentering.value!! || (
+                    autoCentering.value == null || (
                         lazyListState.layoutInfo.visibleItemsInfo.size >= 2 && (
                             // or Empty list (other than the 2 spacers)
                             lazyListState.layoutInfo.visibleItemsInfo.size == 2 ||
@@ -411,7 +402,7 @@
             initialCenterItemScrollOffset = scrollOffset
             return
         }
-        val lazyListStateIndex = if (autoCentering.value!!) index + 1 else index
+        val lazyListStateIndex = if (autoCentering.value != null) index + 1 else index
         val offsetToCenterOfViewport =
             beforeContentPaddingPx.value!! - (viewportHeightPx.value!! / 2)
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
@@ -462,7 +453,7 @@
     ) {
         // Convert the index to take into account the Spacer added to the underlying LazyList before
         // the first ScalingLazyColumn list item
-        val lazyListStateIndex = if (autoCentering.value!!) index + 1 else index
+        val lazyListStateIndex = if (autoCentering.value != null) index + 1 else index
         val offsetToCenterOfViewport =
             beforeContentPaddingPx.value!! - (viewportHeightPx.value!! / 2)
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
@@ -492,24 +483,24 @@
     }
 
     private fun discardAutoCenteringListItem(item: LazyListItemInfo): Boolean =
-        autoCentering.value!! &&
+        autoCentering.value != null &&
             (item.index == 0 || item.index == lazyListState.layoutInfo.totalItemsCount - 1)
 
     /**
      * Calculate the amount of top padding needed (if any) to make sure that the
-     * [initialCenterItemIndex] item can be placed in the center of the viewport at
-     * [initialCenterItemScrollOffset]
+     * [AutoCenteringParams.itemIndex] item can be placed in the center of the viewport at
+     * [AutoCenteringParams.itemOffset]
      */
     private fun calculateTopAutoCenteringPaddingPx(
         visibleItems: List<ScalingLazyListItemInfo>,
         totalItemCount: Int
     ): Int {
-        if (! autoCentering.value!! || visibleItems.isEmpty() ||
+        if (autoCentering.value == null || visibleItems.isEmpty() ||
             visibleItems.first().index != 0) return 0
 
         // Work out the index we want to find - if there are less items in the list than would be
         // needed to make initialItemIndex be visible then use the last visible item
-        val itemIndexToFind = initialCenterItemIndex.coerceAtMost(totalItemCount - 1)
+        val itemIndexToFind = autoCentering.value!!.itemIndex.coerceAtMost(totalItemCount - 1)
 
         // Find the initialCenterItem, if it is null that means it is not in view - therefore
         // we have more than enough content before it to make sure it can be scrolled to the center
@@ -534,22 +525,22 @@
 
     /**
      * Calculate the amount of top padding needed (if any) to make sure that the
-     * [initialCenterItemIndex] item can be placed in the center of the viewport at
-     * [initialCenterItemScrollOffset]
+     * [AutoCenteringParams.itemIndex] item can be placed in the center of the viewport at
+     * [AutoCenteringParams.itemOffset]
      */
     private fun calculateTopAutoCenteringPaddingFromLazyListItemInfo(
         visibleItems: List<LazyListItemInfo>,
         totalItemCount: Int
     ): Int {
         // Check is list is empty or we are not at the start of the visible items
-        if (visibleItems.isEmpty() || visibleItems.isEmpty() ||
+        if (autoCentering.value == null || visibleItems.isEmpty() ||
             visibleItems[0].index != 0) return 0
 
         // Work out the index we want to find - if there are less items in the list than would be
         // needed to make initialItemIndex be visible then use the last visible item. The -3 is to
         // allow for the spacers, i.e. an underlying list of size 3 has 2 spacers in index 0 and 2
         // and one real item in index 1.
-        val itemIndexToFind = (initialCenterItemIndex + 1).coerceAtMost(totalItemCount - 3)
+        val itemIndexToFind = (autoCentering.value!!.itemIndex + 1).coerceAtMost(totalItemCount - 3)
 
         // Find the initialCenterItem, if it is null that means it is not in view - therefore
         // we have more than enough content before it to make sure it can be scrolled to the center
@@ -578,12 +569,12 @@
         } else {
             viewportHeightPx.value!! / 2f -
                 unadjustedSize / 2f
-        } - gapBetweenItemsPx.value!! - initialCenterItemScrollOffset
+        } - gapBetweenItemsPx.value!! - autoCentering.value!!.itemOffset
 
     private fun calculateBottomAutoCenteringPaddingPx(
         visibleItemsInfo: List<ScalingLazyListItemInfo>,
         totalItemsCount: Int
-    ) = if (autoCentering.value!! && visibleItemsInfo.isNotEmpty() &&
+    ) = if (autoCentering.value != null && visibleItemsInfo.isNotEmpty() &&
         visibleItemsInfo.last().index == totalItemsCount - 1
     ) {
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
index 22075d5..824eee3 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
@@ -324,7 +324,7 @@
      */
     public suspend fun snapTo(targetValue: SwipeToDismissValue) = swipeableState.snapTo(targetValue)
 
-    companion object {
+    private companion object {
         private fun <T> SwipeableState<T>.edgeNestedScrollConnection(
             edgeTouched: State<Boolean>
         ): NestedScrollConnection =
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TimeText.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TimeText.kt
index aa03896..2eb89b8 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TimeText.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TimeText.kt
@@ -30,8 +30,10 @@
 import androidx.compose.ui.unit.dp
 import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedLayout
+import androidx.wear.compose.foundation.CurvedModifier
 import androidx.wear.compose.foundation.CurvedScope
 import androidx.wear.compose.foundation.CurvedTextStyle
+import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.material.TimeTextDefaults.CurvedTextSeparator
 import androidx.wear.compose.material.TimeTextDefaults.TextSeparator
 import androidx.wear.compose.material.TimeTextDefaults.timeFormat
@@ -209,8 +211,8 @@
     ) {
         curvedText(
             text = "·",
-            contentArcPadding = contentArcPadding,
-            style = curvedTextStyle
+            style = curvedTextStyle,
+            modifier = CurvedModifier.padding(contentArcPadding)
         )
     }
 
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
index 323f922..fac57f8 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
@@ -382,7 +382,7 @@
 ) {
     ScalingLazyColumn(
         state = scrollState,
-        autoCentering = false,
+        autoCentering = null,
         horizontalAlignment = Alignment.CenterHorizontally,
         verticalArrangement = verticalArrangement,
         contentPadding = contentPadding,
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index 550fa41..1aa204d 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -26,8 +26,8 @@
         applicationId "androidx.wear.compose.integration.demos"
         minSdk 25
         targetSdk 30
-        versionCode 5
-        versionName "1.4"
+        versionCode 6
+        versionName "1.5"
         // Change the APK name to match the *testapp regex we use to pick up APKs for testing as
         // part of CI.
         archivesBaseName = "wear-compose-demos-testapp"
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/CurvedLayoutDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/CurvedLayoutDemo.kt
index 42f434d..89a1b35 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/CurvedLayoutDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/CurvedLayoutDemo.kt
@@ -39,7 +39,6 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.wear.compose.foundation.AnchorType
-import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedAlignment
 import androidx.wear.compose.foundation.CurvedDirection
 import androidx.wear.compose.foundation.CurvedLayout
@@ -50,6 +49,7 @@
 import androidx.wear.compose.foundation.curvedColumn
 import androidx.wear.compose.foundation.curvedComposable
 import androidx.wear.compose.foundation.curvedRow
+import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.foundation.sizeIn
 import androidx.wear.compose.foundation.weight
 import androidx.wear.compose.material.Text
@@ -229,7 +229,7 @@
                 fontSize = 24.sp
             ),
             angularDirection = CurvedDirection.Angular.Reversed,
-            contentArcPadding = ArcPaddingValues(angular = 5.dp),
+            modifier = CurvedModifier.padding(angular = 5.dp),
             // TODO: Re-add when we implement alignment modifiers.
             // modifier = Modifier.radialAlignment(RadialAlignment.Inner)
         )
@@ -281,7 +281,7 @@
                         CurvedTextStyle(
                             fontSize = 24.sp
                         ),
-                        contentArcPadding = ArcPaddingValues(angular = 5.dp),
+                        modifier = CurvedModifier.padding(angular = 5.dp),
                     )
                     curvedColumn {
                         repeat(3) {
@@ -291,11 +291,11 @@
                     curvedRow {
                         basicCurvedText(
                             "after",
-                            contentArcPadding = ArcPaddingValues(angular = 4.dp)
+                            modifier = CurvedModifier.padding(angular = 4.dp),
                         )
                         basicCurvedText(
                             "end",
-                            contentArcPadding = ArcPaddingValues(angular = 4.dp)
+                            modifier = CurvedModifier.padding(angular = 4.dp),
                         )
                     }
                 }
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
index 9da029a..76fe1ef 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
@@ -93,7 +93,7 @@
     ) {
         ScalingLazyColumn(
             state = listState,
-            autoCentering = false
+            autoCentering = null
         ) {
             items(
                 count = if (smallList) 3 else 10
diff --git a/wear/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/wear/compose/integration/macrobenchmark/target/BaselineActivity.kt b/wear/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/wear/compose/integration/macrobenchmark/target/BaselineActivity.kt
index ea02b8a..756bf60 100644
--- a/wear/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/wear/compose/integration/macrobenchmark/target/BaselineActivity.kt
+++ b/wear/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/wear/compose/integration/macrobenchmark/target/BaselineActivity.kt
@@ -41,10 +41,11 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.navigation.NavHostController
-import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedLayout
+import androidx.wear.compose.foundation.CurvedModifier
 import androidx.wear.compose.foundation.CurvedTextStyle
 import androidx.wear.compose.foundation.basicCurvedText
+import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.material.AppCard
 import androidx.wear.compose.material.Button
 import androidx.wear.compose.material.Card
@@ -238,7 +239,7 @@
                 color = Color.White,
                 background = background
             ),
-            contentArcPadding = ArcPaddingValues(2.dp)
+            modifier = CurvedModifier.padding(2.dp)
         )
     }
     CurvedLayout(anchor = 310f) {
diff --git a/wear/tiles/tiles-material/build.gradle b/wear/tiles/tiles-material/build.gradle
index b03ceb2..a72bfba 100644
--- a/wear/tiles/tiles-material/build.gradle
+++ b/wear/tiles/tiles-material/build.gradle
@@ -18,22 +18,43 @@
 
 plugins {
     id("AndroidXPlugin")
+    id("kotlin-android")
     id("com.android.library")
+    id("com.google.protobuf")
 }
 
 dependencies {
     api("androidx.annotation:annotation:1.2.0")
-    api(project(":wear:tiles:tiles"))
-
+    implementation(project(":wear:tiles:tiles"))
     implementation(project(":wear:tiles:tiles-proto"))
 
+    androidTestImplementation(libs.junit)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation("androidx.core:core:1.7.0")
+    androidTestImplementation(project(":test:screenshot:screenshot"))
+    androidTestImplementation(project(":wear:tiles:tiles-renderer"))
+    androidTestRuntimeOnly(project(path: ":wear:tiles:tiles-proto", configuration: "shadow"))
+    androidTestImplementation("com.google.protobuf:protobuf-java:3.10.0")
+
     annotationProcessor(libs.nullaway)
 }
 
 android {
     defaultConfig {
-        minSdkVersion 25
+        minSdkVersion 26
     }
+
+    sourceSets {
+        androidTest.assets.srcDirs += project.rootDir.absolutePath + "/../../golden/wear/wear-tiles-material"
+    }
+
+    defaultConfig {
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
     namespace "androidx.wear.tiles.material"
 }
 
diff --git a/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml b/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
index 4d68dc2..55cb77e 100644
--- a/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
+++ b/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
@@ -14,6 +14,21 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.wear.tiles.material">
+    <application
+        android:label="Golden Tests"
+        android:supportsRtl="true"
+        android:theme="@android:style/Theme.DeviceDefault"
+        android:taskAffinity="">
+        <uses-library android:name="android.test.runner" />
 
+        <activity android:name="androidx.wear.tiles.material.testapp.GoldenTestActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
 </manifest>
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenTest.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenTest.java
new file mode 100644
index 0000000..3022faf
--- /dev/null
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.tiles.material;
+
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_HEIGHT;
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_WIDTH;
+import static androidx.wear.tiles.material.RunnerUtils.runSingleScreenshotTest;
+import static androidx.wear.tiles.material.TestCasesGenerator.generateTestCases;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.Dimension;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.screenshot.AndroidXScreenshotTestRule;
+import androidx.wear.tiles.DeviceParametersBuilders;
+import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters;
+import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class MaterialGoldenTest {
+    private final LayoutElement mLayoutElement;
+    private final String mExpected;
+
+    @Rule
+    public AndroidXScreenshotTestRule mScreenshotRule =
+            new AndroidXScreenshotTestRule("wear/wear-tiles-material");
+
+    public MaterialGoldenTest(LayoutElement layoutElement, String expected) {
+        mLayoutElement = layoutElement;
+        mExpected = expected;
+    }
+
+    @Dimension(unit = Dimension.DP)
+    static int pxToDp(int px, float scale) {
+        return (int) ((px - 0.5f) / scale);
+    }
+
+    @Parameterized.Parameters(name = "{1}")
+    public static Collection<Object[]> data() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        float scale = displayMetrics.density;
+
+        InstrumentationRegistry.getInstrumentation()
+                .getContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(displayMetrics);
+        InstrumentationRegistry.getInstrumentation()
+                .getTargetContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(displayMetrics);
+
+
+        DeviceParameters deviceParameters =
+                new DeviceParameters.Builder()
+                        .setScreenWidthDp(pxToDp(SCREEN_WIDTH, scale))
+                        .setScreenHeightDp(pxToDp(SCREEN_HEIGHT, scale))
+                        .setScreenDensity(displayMetrics.density)
+                        // Not important for components.
+                        .setScreenShape(DeviceParametersBuilders.SCREEN_SHAPE_RECT)
+                        .build();
+
+        HashMap<LayoutElement, String> testCases =
+                generateTestCases(context, deviceParameters, "");
+
+        return testCases.entrySet()
+                .stream()
+                .map(test -> new Object[]{test.getKey(), test.getValue()})
+                .collect(Collectors.toList());
+    }
+
+    @Test
+    public void test() {
+        runSingleScreenshotTest(mScreenshotRule, mLayoutElement, mExpected);
+    }
+}
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java
new file mode 100644
index 0000000..25b116e
--- /dev/null
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.tiles.material;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_HEIGHT;
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_WIDTH;
+import static androidx.wear.tiles.material.RunnerUtils.runSingleScreenshotTest;
+import static androidx.wear.tiles.material.TestCasesGenerator.XXXL_SCALE_SUFFIX;
+import static androidx.wear.tiles.material.TestCasesGenerator.generateTestCases;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.Dimension;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.screenshot.AndroidXScreenshotTestRule;
+import androidx.wear.tiles.DeviceParametersBuilders;
+import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters;
+import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class MaterialGoldenXLTest {
+    /* We set DisplayMetrics in the data() method for creating test cases. However, when running all
+    tests together, first all parametrization (data()) methods are called, and then individual
+    tests, causing that actual DisplayMetrics will be different. So we need to restore it before
+    each test. */
+    private static final DisplayMetrics DISPLAY_METRICS_FOR_TEST = new DisplayMetrics();
+    private static final DisplayMetrics OLD_DISPLAY_METRICS = new DisplayMetrics();
+
+    private static final float FONT_SCALE_XXXL = 1.24f;
+
+    private final LayoutElement mLayoutElement;
+    private final String mExpected;
+
+    @Rule
+    public AndroidXScreenshotTestRule mScreenshotRule =
+            new AndroidXScreenshotTestRule("wear/wear-tiles-material");
+
+    public MaterialGoldenXLTest(LayoutElement layoutElement, String expected) {
+        mLayoutElement = layoutElement;
+        mExpected = expected;
+    }
+
+    @Dimension(unit = Dimension.DP)
+    static int pxToDp(int px, float scale) {
+        return (int) ((px - 0.5f) / scale);
+    }
+
+    @Parameterized.Parameters(name = "{1}")
+    public static Collection<Object[]> data() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        DisplayMetrics currentDisplayMetrics = new DisplayMetrics();
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        currentDisplayMetrics.setTo(displayMetrics);
+        displayMetrics.scaledDensity *= FONT_SCALE_XXXL;
+
+        InstrumentationRegistry.getInstrumentation()
+                .getContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(displayMetrics);
+        InstrumentationRegistry.getInstrumentation()
+                .getTargetContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(displayMetrics);
+
+        DISPLAY_METRICS_FOR_TEST.setTo(displayMetrics);
+
+        float scale = displayMetrics.density;
+        DeviceParameters deviceParameters =
+                new DeviceParameters.Builder()
+                        .setScreenWidthDp(pxToDp(SCREEN_WIDTH, scale))
+                        .setScreenHeightDp(pxToDp(SCREEN_HEIGHT, scale))
+                        .setScreenDensity(displayMetrics.density)
+                        // Not important for components.
+                        .setScreenShape(DeviceParametersBuilders.SCREEN_SHAPE_RECT)
+                        .build();
+
+        HashMap<LayoutElement, String> testCases =
+                generateTestCases(context, deviceParameters, XXXL_SCALE_SUFFIX);
+
+        // Restore state before this method, so other test have correct context.
+        InstrumentationRegistry.getInstrumentation()
+                .getContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(currentDisplayMetrics);
+        InstrumentationRegistry.getInstrumentation()
+                .getTargetContext()
+                .getResources()
+                .getDisplayMetrics()
+                .setTo(currentDisplayMetrics);
+
+        return testCases.entrySet()
+                .stream()
+                .map(test -> new Object[]{test.getKey(), test.getValue()})
+                .collect(Collectors.toList());
+    }
+
+    @Parameterized.BeforeParam
+    public static void restoreBefore() {
+        OLD_DISPLAY_METRICS.setTo(getApplicationContext().getResources().getDisplayMetrics());
+        getApplicationContext().getResources().getDisplayMetrics().setTo(DISPLAY_METRICS_FOR_TEST);
+    }
+
+    @Parameterized.AfterParam
+    public static void restoreAfter() {
+        getApplicationContext().getResources().getDisplayMetrics().setTo(OLD_DISPLAY_METRICS);
+    }
+
+    @Test
+    public void test() {
+        runSingleScreenshotTest(mScreenshotRule, mLayoutElement, mExpected);
+    }
+}
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/RunnerUtils.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/RunnerUtils.java
new file mode 100644
index 0000000..f707b14
--- /dev/null
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/RunnerUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.tiles.material;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.screenshot.AndroidXScreenshotTestRule;
+import androidx.test.screenshot.matchers.MSSIMMatcher;
+import androidx.wear.tiles.LayoutElementBuilders;
+import androidx.wear.tiles.material.testapp.GoldenTestActivity;
+
+public class RunnerUtils {
+    // This isn't totally ideal right now. The screenshot tests run on a phone, so emulate some
+    // watch dimensions here.
+    public static final int SCREEN_WIDTH = 390;
+    public static final int SCREEN_HEIGHT = 390;
+
+    private RunnerUtils() {}
+
+    static void runSingleScreenshotTest(@NonNull AndroidXScreenshotTestRule rule,
+            @NonNull LayoutElementBuilders.LayoutElement layoutElement,
+            @NonNull String expected) {
+        byte[] layoutElementPayload = layoutElement.toLayoutElementProto().toByteArray();
+
+        Intent startIntent =
+                new Intent(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                        GoldenTestActivity.class);
+        startIntent.putExtra("layout", layoutElementPayload);
+
+        ActivityScenario<GoldenTestActivity> scenario = ActivityScenario.launch(startIntent);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        try {
+            // Wait 1s after launching the activity. This allows for the old white layout in the
+            // bootstrap activity to fully go away before proceeding.
+            Thread.sleep(1000);
+        } catch (Exception ex) {
+            if (ex instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.e("MaterialGoldenTest", "Error sleeping", ex);
+        }
+
+        Bitmap bitmap = Bitmap.createBitmap(
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(),
+                0, 0, SCREEN_WIDTH, SCREEN_HEIGHT
+        );
+        rule.assertBitmapAgainstGolden(bitmap, expected, new MSSIMMatcher());
+
+        // There's a weird bug (related to b/159805732) where, when calling .close() on
+        // ActivityScenario or calling finish() and immediately exiting the test, the test can hang
+        // on a white screen for 45s. Closing the activity here and waiting for 1s seems to fix
+        // this.
+        scenario.onActivity(Activity::finish);
+
+        try {
+            Thread.sleep(1000);
+        } catch (Exception ex) {
+            if (ex instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            Log.e("MaterialGoldenTest", "Error sleeping", ex);
+        }
+    }
+}
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java
new file mode 100644
index 0000000..60f61f3
--- /dev/null
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.tiles.material;
+
+import static androidx.wear.tiles.ColorBuilders.argb;
+import static androidx.wear.tiles.DimensionBuilders.dp;
+import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER;
+import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_END;
+import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_START;
+import static androidx.wear.tiles.material.ProgressIndicatorDefaults.GAP_END_ANGLE;
+import static androidx.wear.tiles.material.ProgressIndicatorDefaults.GAP_START_ANGLE;
+
+import android.content.Context;
+import android.graphics.Color;
+
+import androidx.annotation.NonNull;
+import androidx.wear.tiles.ActionBuilders.LaunchAction;
+import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters;
+import androidx.wear.tiles.LayoutElementBuilders;
+import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
+import androidx.wear.tiles.ModifiersBuilders.Clickable;
+
+import java.util.HashMap;
+
+public class TestCasesGenerator {
+    private TestCasesGenerator() {}
+
+    private static final String ICON_ID = "tile_icon";
+    private static final String AVATAR = "avatar_image";
+    public static final String NORMAL_SCALE_SUFFIX = "";
+    public static final String XXXL_SCALE_SUFFIX = "_xxxl";
+
+    /**
+     * This function will append goldenSuffix on the name of the golden images that should be
+     * different for different user font sizes. Note that some of the golden will have the same name
+     * as it should point on the same size independent image.
+     */
+    @NonNull
+    static HashMap<LayoutElement, String> generateTestCases(
+            @NonNull Context context,
+            @NonNull DeviceParameters deviceParameters,
+            @NonNull String goldenSuffix) {
+        Clickable clickable =
+                new Clickable.Builder()
+                        .setOnClick(new LaunchAction.Builder().build())
+                        .setId("action_id")
+                        .build();
+        String mainText = "Primary label";
+        String labelText = "Secondary label";
+        String largeChipText = "Action";
+        HashMap<LayoutElement, String> testCases = new HashMap<>();
+
+        testCases.put(
+                new Button.Builder(context, clickable).setIconContent(ICON_ID).build(),
+                "default_icon_button_golden" + NORMAL_SCALE_SUFFIX);
+        testCases.put(
+                new Button.Builder(context, clickable)
+                        .setButtonColors(ButtonDefaults.SECONDARY_BUTTON_COLORS)
+                        .setIconContent(ICON_ID)
+                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .build(),
+                "extralarge_secondary_icon_after_button_golden" + NORMAL_SCALE_SUFFIX);
+        testCases.put(
+                new Button.Builder(context, clickable)
+                        .setSize(ButtonDefaults.LARGE_BUTTON_SIZE)
+                        .setButtonColors(ButtonDefaults.SECONDARY_BUTTON_COLORS)
+                        .setIconContent(ICON_ID, dp(40))
+                        .build(),
+                "large_secondary_icon_40size_button_golden" + NORMAL_SCALE_SUFFIX);
+        testCases.put(
+                new Button.Builder(context, clickable)
+                        .setButtonColors(new ButtonColors(Color.YELLOW, Color.GREEN))
+                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .setContent(
+                                new Text.Builder(context, "ABC")
+                                        .setTypography(Typography.TYPOGRAPHY_DISPLAY1)
+                                        .setItalic(true)
+                                        .setColor(argb(Color.GREEN))
+                                        .build())
+                        .build(),
+                "extralarge_custom_text_custom_sizefont_button_golden" + goldenSuffix);
+        testCases.put(
+                new Button.Builder(context, clickable).setTextContent("ABC").build(),
+                "default_text_button_golden" + goldenSuffix);
+        testCases.put(
+                new Button.Builder(context, clickable).setImageContent(AVATAR).build(),
+                "default_image_button_golden" + NORMAL_SCALE_SUFFIX);
+
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setPrimaryTextContent(mainText)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .build(),
+                "default_chip_maintext_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setPrimaryTextLabelContent(mainText, labelText)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .build(),
+                "default_chip_maintextlabeltext_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setPrimaryTextIconContent(mainText, ICON_ID)
+                        .build(),
+                "default_chip_maintexticon_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
+                        .setChipColors(ChipDefaults.SECONDARY_COLORS)
+                        .setPrimaryTextContent(mainText)
+                        .build(),
+                "secondary_chip_maintext_centered_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setWidth(130)
+                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .setChipColors(
+                                new ChipColors(Color.YELLOW, Color.GREEN, Color.BLACK, Color.GRAY))
+                        .build(),
+                "custom_chip_all_overflows_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
+                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .build(),
+                "default_chip_all_centered_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_END)
+                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .build(),
+                "default_chip_all_rigthalign_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setPrimaryTextIconContent(mainText, ICON_ID)
+                        .setWidth(150)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .setChipColors(
+                                new ChipColors(Color.YELLOW, Color.GREEN, Color.BLACK, Color.GRAY))
+                        .build(),
+                "custom_chip_icon_primary_overflows_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
+                        .setContent(
+                                new LayoutElementBuilders.Box.Builder()
+                                        .addContent(
+                                                new Text.Builder(context, "random text")
+                                                        .setTypography(Typography.TYPOGRAPHY_TITLE3)
+                                                        .setItalic(true)
+                                                        .build())
+                                        .build())
+                        .build(),
+                "chip_custom_content_centered_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setChipColors(ChipDefaults.SECONDARY_COLORS)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .setContent(
+                                new LayoutElementBuilders.Row.Builder()
+                                        .addContent(
+                                                new Text.Builder(context, "text1")
+                                                        .setTypography(Typography.TYPOGRAPHY_TITLE3)
+                                                        .setItalic(true)
+                                                        .setColor(argb(Color.WHITE))
+                                                        .build())
+                                        .addContent(
+                                                new Text.Builder(context, "text2")
+                                                        .setTypography(Typography.TYPOGRAPHY_TITLE2)
+                                                        .setColor(argb(Color.YELLOW))
+                                                        .build())
+                                        .build())
+                        .setWidth(150)
+                        .build(),
+                "chip_custom_content_leftaligned_golden" + goldenSuffix);
+        testCases.put(
+                new Chip.Builder(context, clickable, deviceParameters)
+                        .setPrimaryTextContent("abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde")
+                        .build(),
+                "chip_2lines_primary_overflows_golden" + goldenSuffix);
+
+        // Different text lengths to test expanding the width based on the size of text. If it's
+        // more than 9, the rest will be deleted.
+        testCases.put(
+                new CompactChip.Builder(context, "Ab", clickable, deviceParameters).build(),
+                "compactchip_default_len2_golden" + goldenSuffix);
+        testCases.put(
+                new CompactChip.Builder(context, "Abcde", clickable, deviceParameters).build(),
+                "compactchip_default_len5_golden" + goldenSuffix);
+        testCases.put(
+                new CompactChip.Builder(context, "Abcdefghi", clickable, deviceParameters).build(),
+                "compactchip_default_len9_golden" + goldenSuffix);
+        testCases.put(
+                new CompactChip.Builder(context, "AbcdefghiEXTRA", clickable,
+                        deviceParameters).build(),
+                "compactchip_default_toolong_golden" + goldenSuffix);
+        testCases.put(
+                new CompactChip.Builder(context, "Action", clickable, deviceParameters)
+                        .setChipColors(new ChipColors(Color.YELLOW, Color.BLACK))
+                        .build(),
+                "compactchip_custom_default_golden" + goldenSuffix);
+
+        testCases.put(
+                new TitleChip.Builder(context, largeChipText, clickable, deviceParameters).build(),
+                "titlechip_default_golden" + goldenSuffix);
+        testCases.put(
+                new TitleChip.Builder(context, "abcdeabcdeabcdeEXTRA", clickable,
+                        deviceParameters).build(),
+                "titlechip_default_texttoolong_golden" + goldenSuffix);
+        testCases.put(
+                new TitleChip.Builder(context, largeChipText, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .setChipColors(ChipDefaults.TITLE_SECONDARY_COLORS)
+                        .build(),
+                "titlechip_leftalign_secondary_default_golden" + goldenSuffix);
+        testCases.put(
+                new TitleChip.Builder(context, largeChipText, clickable, deviceParameters)
+                        .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
+                        .setChipColors(new ChipColors(Color.YELLOW, Color.BLUE))
+                        .setWidth(150)
+                        .build(),
+                "titlechip_centered_custom_150_secondary_default_golden" + goldenSuffix);
+
+        testCases.put(
+                new CircularProgressIndicator.Builder().build(),
+                "default_full_circularprogressindicator");
+        testCases.put(
+                new CircularProgressIndicator.Builder()
+                        .setStartAngle(GAP_START_ANGLE)
+                        .setEndAngle(GAP_END_ANGLE)
+                        .build(),
+                "default_gap_circularprogressindicator");
+        testCases.put(
+                new CircularProgressIndicator.Builder().setProgress(0.25f).build(),
+                "default_full_90_circularprogressindicator");
+        testCases.put(
+                new CircularProgressIndicator.Builder()
+                        .setProgress(0.25f)
+                        .setStartAngle(GAP_START_ANGLE)
+                        .setEndAngle(GAP_END_ANGLE)
+                        .build(),
+                "default_gap_90_circularprogressindicator");
+        testCases.put(
+                new CircularProgressIndicator.Builder()
+                        .setStartAngle(45)
+                        .setEndAngle(270)
+                        .setProgress(0.2f)
+                        .setStrokeWidth(12)
+                        .setCircularProgressIndicatorColors(
+                                new ProgressIndicatorColors(Color.BLUE, Color.YELLOW))
+                        .build(),
+                "custom_gap_45_circularprogressindicator");
+
+        testCases.put(
+                new Text.Builder(context, "Testing").build(),
+                "default_text_golden" + goldenSuffix);
+        testCases.put(
+                new Text.Builder(context, "Testing text.")
+                        .setItalic(true)
+                        .setColor(argb(Color.YELLOW))
+                        .setTypography(Typography.TYPOGRAPHY_BODY2)
+                        .build(),
+                "custom_text_golden" + goldenSuffix);
+        testCases.put(
+                new Text.Builder(context, "abcdeabcdeabcde").build(),
+                "overflow_text_golden" + goldenSuffix);
+
+        return testCases;
+    }
+}
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java
new file mode 100644
index 0000000..f775a6f
--- /dev/null
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/testapp/GoldenTestActivity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.tiles.material.testapp;
+
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_HEIGHT;
+import static androidx.wear.tiles.material.RunnerUtils.SCREEN_WIDTH;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.wear.tiles.LayoutElementBuilders;
+import androidx.wear.tiles.LayoutElementBuilders.Layout;
+import androidx.wear.tiles.ResourceBuilders.AndroidImageResourceByResId;
+import androidx.wear.tiles.ResourceBuilders.ImageResource;
+import androidx.wear.tiles.ResourceBuilders.Resources;
+import androidx.wear.tiles.material.R;
+import androidx.wear.tiles.proto.LayoutElementProto.LayoutElement;
+import androidx.wear.tiles.renderer.TileRenderer;
+
+import java.util.concurrent.Executor;
+
+
+public class GoldenTestActivity extends Activity {
+    private static final String ICON_ID = "tile_icon";
+    private static final String AVATAR = "avatar_image";
+
+    @Override
+    @SuppressWarnings("deprecation")
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        byte[] layoutPayload = getIntent().getExtras().getByteArray("layout");
+
+        LayoutElement layoutElementProto;
+        try {
+            layoutElementProto =
+                    LayoutElement.parseFrom(layoutPayload);
+        } catch (Exception ex) {
+            // It's a test, just rethrow.
+            throw new IllegalArgumentException("Could not deserialize layout proto", ex);
+        }
+
+        LayoutElementBuilders.LayoutElement rootLayoutElement =
+                LayoutElementBuilders.LayoutElement.fromLayoutElementProto(layoutElementProto);
+
+        Context appContext = getApplicationContext();
+        FrameLayout root = new FrameLayout(appContext);
+        root.setLayoutParams(new LayoutParams(SCREEN_WIDTH, SCREEN_HEIGHT));
+
+        Layout layout = new Layout.Builder().setRoot(rootLayoutElement).build();
+
+        Executor mainExecutor = ContextCompat.getMainExecutor(getApplicationContext());
+
+        Resources resources = generateResources();
+        TileRenderer renderer =
+                new TileRenderer(
+                        appContext,
+                        layout,
+                        resources,
+                        mainExecutor,
+                        i -> {});
+
+        View firstChild = renderer.inflate(root);
+
+        // Simulate what the thing outside the renderer should do. Center the contents.
+        LayoutParams layoutParams = (LayoutParams) firstChild.getLayoutParams();
+        layoutParams.gravity = Gravity.CENTER;
+
+        // Set the activity to be full screen so when we crop the Bitmap we don't get time bar etc.
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+        setContentView(root, new ViewGroup.LayoutParams(SCREEN_WIDTH, SCREEN_HEIGHT));
+        super.onCreate(savedInstanceState);
+    }
+
+    private static Resources generateResources() {
+        return new Resources.Builder()
+                .addIdToImageMapping(
+                        ICON_ID,
+                        new ImageResource.Builder()
+                                .setAndroidResourceByResId(
+                                        new AndroidImageResourceByResId.Builder()
+                                                .setResourceId(R.drawable.tile_icon)
+                                                .build())
+                                .build())
+                .addIdToImageMapping(
+                        AVATAR,
+                        new ImageResource.Builder()
+                                .setAndroidResourceByResId(
+                                        new AndroidImageResourceByResId.Builder()
+                                                .setResourceId(R.drawable.avatar)
+                                                .build())
+                                .build())
+                .build();
+    }
+}
+
diff --git a/wear/tiles/tiles-material/src/main/res/drawable/avatar.png b/wear/tiles/tiles-material/src/main/res/drawable/avatar.png
new file mode 100644
index 0000000..a6da988
--- /dev/null
+++ b/wear/tiles/tiles-material/src/main/res/drawable/avatar.png
Binary files differ
diff --git a/wear/tiles/tiles-material/src/main/res/drawable/tile_icon.xml b/wear/tiles/tiles-material/src/main/res/drawable/tile_icon.xml
new file mode 100644
index 0000000..21eb853
--- /dev/null
+++ b/wear/tiles/tiles-material/src/main/res/drawable/tile_icon.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#000"
+      android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
diff --git a/wear/watchface/watchface-client/api/1.1.0-beta01.txt b/wear/watchface/watchface-client/api/1.1.0-beta01.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/1.1.0-beta01.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/current.txt b/wear/watchface/watchface-client/api/current.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/current.txt
+++ b/wear/watchface/watchface-client/api/current.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt b/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
index 95ff68c..92202fd 100644
--- a/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
@@ -102,7 +102,7 @@
     method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.time.Instant getPreviewReferenceInstant();
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default byte[] getUserStyleSchemaDigestHash() throws android.os.RemoteException;
     method @AnyThread public boolean isConnectionAlive();
@@ -207,19 +207,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -230,9 +217,9 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/public_plus_experimental_current.txt b/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
index 95ff68c..92202fd 100644
--- a/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
+++ b/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
@@ -102,7 +102,7 @@
     method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.time.Instant getPreviewReferenceInstant();
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default byte[] getUserStyleSchemaDigestHash() throws android.os.RemoteException;
     method @AnyThread public boolean isConnectionAlive();
@@ -207,19 +207,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -230,9 +217,9 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt b/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/restricted_current.txt b/wear/watchface/watchface-client/api/restricted_current.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/restricted_current.txt
+++ b/wear/watchface/watchface-client/api/restricted_current.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml b/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
index a2ae439..4e73052 100644
--- a/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
+++ b/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
@@ -18,6 +18,13 @@
     <application android:requestLegacyExternalStorage="true">
         <service android:name="androidx.wear.watchface.client.test.WatchFaceControlTestService"/>
         <service android:name="androidx.wear.watchface.client.test.TestNopCanvasWatchFaceService"/>
+        <service
+            android:name="androidx.wear.watchface.client.test.OutdatedWatchFaceControlTestService">
+            <meta-data android:name="androidx.wear.watchface.xml_version" android:value="99999" />
+            <meta-data
+                android:name="androidx.wear.watchface.XmlSchemaAndComplicationSlotsDefinition"
+                android:resource="@xml/xml_watchface" />
+        </service>
     </application>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt
similarity index 60%
copy from health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
copy to wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt
index a5d6306..aa19f94 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package androidx.health.data.client.metadata;
+package androidx.wear.watchface.client.test
 
-import static com.google.common.truth.Truth.assertThat;
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DeviceTypeTest {
-    @Test
-    public void javaInterlope() {
-        assertThat(DeviceTypes.CHEST_STRAP).isNotEqualTo(DeviceTypes.FITNESS_BAND);
+/**
+ * Test WatchFaceControlService which has obsolete XML version in manifest.
+ */
+public class OutdatedWatchFaceControlTestService : Service() {
+    override fun onBind(p0: Intent?): IBinder? {
+        // It is not assumed to be called
+        throw NotImplementedError()
     }
 }
diff --git a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
index 94e1489..ad5fda7 100644
--- a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
@@ -358,4 +358,22 @@
         Truth.assertThat(right.systemDataSourceFallbackDefaultType).isEqualTo(
             ComplicationType.SHORT_TEXT)
     }
+
+    @Test
+    public fun xmlVersionCompatibility() {
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(context, context.resources)).isTrue()
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(
+                context,
+                context.resources,
+                ComponentName(context, OutdatedWatchFaceControlTestService::class.java)
+            )).isFalse()
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(
+                context,
+                context.resources,
+                ComponentName("non.existing.package", "non.existing.package.Service")
+            )).isFalse()
+    }
 }
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt
similarity index 62%
copy from health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
copy to wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt
index a5d6306..fac5538 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/metadata/DeviceTypeTest.java
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-package androidx.health.data.client.metadata;
+package androidx.wear.watchface.client
 
-import static com.google.common.truth.Truth.assertThat;
+import android.os.Build
+import android.os.RemoteException
+import androidx.annotation.RequiresApi
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DeviceTypeTest {
-    @Test
-    public void javaInterlope() {
-        assertThat(DeviceTypes.CHEST_STRAP).isNotEqualTo(DeviceTypes.FITNESS_BAND);
+internal class Api30Helper {
+    @RequiresApi(Build.VERSION_CODES.R)
+    internal companion object {
+        internal fun toRuntimeExpression(e: RemoteException) = e.rethrowAsRuntimeException()
     }
 }
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
index 5b88032..f96a66a2 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
@@ -79,9 +79,13 @@
     @Throws(RemoteException::class)
     public fun getUserStyleSchemaDigestHash(): ByteArray = ByteArray(0)
 
-    /** The watch face's [UserStyleFlavors] if any. */
+    /**
+     * Returns the watch face's [UserStyleFlavors] if any.
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
+     */
     @WatchFaceFlavorsExperimental
-    @Throws(WatchFaceException::class)
     public fun getUserStyleFlavors(): UserStyleFlavors = UserStyleFlavors()
 
     /**
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
index eb5f023..53d358a 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
@@ -16,62 +16,15 @@
 
 package androidx.wear.watchface.client
 
-import android.os.DeadObjectException
+import android.os.Build
 import android.os.RemoteException
-import android.os.TransactionTooLargeException
-import androidx.annotation.IntDef
 
-/**
- * Why the remote watch face query failed.
- * @hide
- **/
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
-    WatchFaceException.WATCHFACE_DIED,
-    WatchFaceException.TRANSACTION_TOO_LARGE,
-    WatchFaceException.UNKNOWN
-)
-annotation class WatchFaceExceptionReason
-
-/**
- * The watch face threw an exception while trying to service the request.
- *
- * @property reason The [WatchFaceExceptionReason] for the exception.
- */
-public class WatchFaceException(
-    e: Exception,
-    @WatchFaceExceptionReason val reason: Int
-) : Exception(e) {
-
-    companion object {
-        /**
-         * The watchface process died. Connecting again might work, but this isn't guaranteed.
-         */
-        const val WATCHFACE_DIED = 1
-
-        /**
-         * The watchface tried to send us too much data. Currently the limit on binder
-         * transactions is 1mb. See [TransactionTooLargeException] for more details.
-         */
-        const val TRANSACTION_TOO_LARGE = 2
-
-        /**
-         * The watch face threw an exception, typically during initialization. Depending on the
-         * nature of the problem this might be a transient issue or it might occur every time
-         * for that particular watch face.
-         */
-        const val UNKNOWN = 3
-    }
-}
-
-@Throws(WatchFaceException::class)
 internal fun <R> callRemote(task: () -> R): R =
     try {
         task()
-    } catch (e: DeadObjectException) {
-        throw WatchFaceException(e, WatchFaceException.WATCHFACE_DIED)
-    } catch (e: TransactionTooLargeException) {
-        throw WatchFaceException(e, WatchFaceException.TRANSACTION_TOO_LARGE)
     } catch (e: RemoteException) {
-        throw WatchFaceException(e, WatchFaceException.UNKNOWN)
+        if (Build.VERSION.SDK_INT >= 30)
+            throw Api30Helper.toRuntimeExpression(e)
+        else
+            throw RuntimeException(e)
     }
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
index c39005c..4c670a1 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
@@ -21,10 +21,12 @@
 import android.content.Intent
 import android.content.ServiceConnection
 import android.content.pm.PackageManager
+import android.content.res.Resources
 import android.content.res.XmlResourceParser
 import android.graphics.RectF
 import android.os.Bundle
 import android.os.IBinder
+import android.util.Log
 import androidx.annotation.RestrictTo
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
@@ -55,6 +57,9 @@
 public interface WatchFaceMetadataClient : AutoCloseable {
 
     public companion object {
+        /** @hide */
+        private const val TAG = "WatchFaceMetadataClient"
+
         /**
          * Constructs a [WatchFaceMetadataClient] for fetching metadata for the specified watch
          * face.
@@ -90,11 +95,50 @@
         }
 
         /** @hide */
+        private const val ANDROIDX_WATCHFACE_XML_VERSION = "androidx.wear.watchface.xml_version"
+        /** @hide */
+        private const val ANDROIDX_WATCHFACE_CONTROL_SERVICE =
+            "androidx.wear.watchface.control.WatchFaceControlService"
+
+        @Suppress("DEPRECATION") // getServiceInfo
+        internal fun isXmlVersionCompatible(
+            context: Context,
+            resources: Resources,
+            controlServiceComponentName: ComponentName = ComponentName(
+                context, ANDROIDX_WATCHFACE_CONTROL_SERVICE)
+        ): Boolean {
+            val version = try {
+                context.packageManager.getServiceInfo(
+                    controlServiceComponentName,
+                    PackageManager.GET_META_DATA or PackageManager.MATCH_DISABLED_COMPONENTS
+                ).metaData.getInt(ANDROIDX_WATCHFACE_XML_VERSION, 0)
+            } catch (exception: PackageManager.NameNotFoundException) {
+                // WatchFaceControlService may be missing in case WF is built with
+                // pre-androidx watchface library.
+                return false
+            }
+
+            val ourVersion = resources.getInteger(
+                androidx.wear.watchface.R.integer.watch_face_xml_version)
+
+            if (version > ourVersion) {
+                Log.w(TAG, "WatchFaceControlService version ($version) " +
+                    "of $controlServiceComponentName is higher than $ourVersion")
+                return false
+            }
+
+            return true
+        }
+
+        /** @hide */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         @Suppress("DEPRECATION")
         open class ParserProvider {
             // Open to allow testing without having to install the sample app.
             open fun getParser(context: Context, watchFaceName: ComponentName): XmlResourceParser? {
+                if (!isXmlVersionCompatible(context, context.resources))
+                    return null
+
                 return context.packageManager.getServiceInfo(
                     watchFaceName,
                     PackageManager.GET_META_DATA
@@ -165,8 +209,10 @@
 
     /**
      * Returns the watch face's [UserStyleSchema].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     public fun getUserStyleSchema(): UserStyleSchema
 
     /**
@@ -179,14 +225,18 @@
     /**
      * Returns a map of [androidx.wear.watchface.ComplicationSlot] ID to [ComplicationSlotMetadata]
      * for each slot in the watch face's [androidx.wear.watchface.ComplicationSlotsManager].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     public fun getComplicationSlotMetadataMap(): Map<Int, ComplicationSlotMetadata>
 
     /**
      * Returns the watch face's [UserStyleFlavors].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     @WatchFaceFlavorsExperimental
     public fun getUserStyleFlavors(): UserStyleFlavors
 }
diff --git a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
index 47e166d..868b87e 100644
--- a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
+++ b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataTimeline.kt
@@ -137,8 +137,8 @@
                     complicationData.type == defaultComplicationData.type
                 ) {
                     "TimelineEntry's complicationData must have the same type as the " +
-                        "defaultComplicationData. Found ${complicationData.type} expected " +
-                        "${defaultComplicationData.type}."
+                        "defaultComplicationData or be NoDataComplicationData. Found " +
+                        "${complicationData.type} expected ${defaultComplicationData.type}."
                 }
 
                 require(!complicationData.hasPlaceholderFields()) {
diff --git a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
index 0c31e4b..0dad6db 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
+++ b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
@@ -262,6 +262,8 @@
     private static final String FIELD_TIMELINE_START_TIME = "TIMELINE_START_TIME";
     private static final String FIELD_TIMELINE_END_TIME = "TIMELINE_END_TIME";
     private static final String FIELD_TIMELINE_ENTRIES = "TIMELINE";
+    private static final String FIELD_TIMELINE_ENTRY_TYPE = "TIMELINE_ENTRY_TYPE";
+    private static final String FIELD_PLACEHOLDER_FIELDS = "PLACEHOLDER_FIELDS";
     private static final String FIELD_PLACEHOLDER_TYPE = "PLACEHOLDER_TYPE";
     private static final String FIELD_DATA_SOURCE = "FIELD_DATA_SOURCE";
 
@@ -351,6 +353,7 @@
                     FIELD_LONG_TITLE,
                     FIELD_MAX_VALUE,
                     FIELD_MIN_VALUE,
+                    FIELD_PLACEHOLDER_FIELDS,
                     FIELD_PLACEHOLDER_TYPE,
                     FIELD_SHORT_TEXT,
                     FIELD_SHORT_TITLE,
@@ -389,19 +392,9 @@
     }
 
     ComplicationData(int type, Bundle fields) {
+        mType = type;
         mFields = fields;
         mFields.setClassLoader(getClass().getClassLoader());
-        // If this is a placeholder, coerce to TYPE_NO_DATA.
-        // If this is defined within a timeline, we assume the type of the outer ComplicationData
-        // applies to all elements in the timeline and we can just use the passed in type. The only
-        // exception is if we get a NO_DATA ComplicationData. In that case, we can check whether
-        // the placeholder type is included the serialization to determine if NO_DATA was passed
-        // in and coerce the type to NO_DATA.
-        if (mFields.containsKey(FIELD_PLACEHOLDER_TYPE)) {
-            mType = TYPE_NO_DATA;
-        } else {
-            mType = type;
-        }
     }
 
     private ComplicationData(@NonNull Parcel in) {
@@ -411,7 +404,7 @@
 
     @RequiresApi(api = Build.VERSION_CODES.P)
     private static class SerializedForm implements Serializable {
-        private static final int VERSION_NUMBER = 5;
+        private static final int VERSION_NUMBER = 6;
 
         @NonNull
         ComplicationData mComplicationData;
@@ -480,9 +473,6 @@
             if (isFieldValidForType(FIELD_END_TIME, type)) {
                 oos.writeLong(mComplicationData.getEndDateTimeMillis());
             }
-            if (isFieldValidForType(FIELD_PLACEHOLDER_TYPE, type)) {
-                oos.writeInt(mComplicationData.getPlaceholderType());
-            }
             if (isFieldValidForType(FIELD_DATA_SOURCE, type)) {
                 ComponentName componentName = mComplicationData.getDataSource();
                 if (componentName == null) {
@@ -500,6 +490,16 @@
             long end = mComplicationData.mFields.getLong(FIELD_TIMELINE_END_TIME, -1);
             oos.writeLong(end);
 
+            if (isFieldValidForType(FIELD_PLACEHOLDER_FIELDS, type)) {
+                ComplicationData placeholder = mComplicationData.getPlaceholder();
+                if (placeholder == null) {
+                    oos.writeBoolean(false);
+                } else {
+                    oos.writeBoolean(true);
+                    new SerializedForm(placeholder).writeObject(oos);
+                }
+            }
+
             // This has to be last, since it's recursive.
             List<ComplicationData> timeline = mComplicationData.getTimelineEntries();
             int timelineLength = (timeline != null) ? timeline.size() : 0;
@@ -572,12 +572,6 @@
             if (isFieldValidForType(FIELD_END_TIME, type)) {
                 fields.putLong(FIELD_END_TIME, ois.readLong());
             }
-            if (isFieldValidForType(FIELD_PLACEHOLDER_TYPE, type)) {
-                int placeholderType = ois.readInt();
-                if (placeholderType != 0) {
-                    fields.putInt(FIELD_PLACEHOLDER_TYPE, placeholderType);
-                }
-            }
             if (isFieldValidForType(FIELD_DATA_SOURCE, type)) {
                 String componentName = ois.readUTF();
                 if (componentName.isEmpty()) {
@@ -598,6 +592,18 @@
             if (end != -1) {
                 fields.putLong(FIELD_TIMELINE_END_TIME, end);
             }
+
+            if (isFieldValidForType(FIELD_PLACEHOLDER_FIELDS, type)) {
+                if (ois.readBoolean()) {
+                    SerializedForm serializedPlaceholder = new SerializedForm();
+                    serializedPlaceholder.readObject(ois);
+                    fields.putInt(FIELD_PLACEHOLDER_TYPE,
+                            serializedPlaceholder.mComplicationData.mType);
+                    fields.putBundle(FIELD_PLACEHOLDER_FIELDS,
+                            serializedPlaceholder.mComplicationData.mFields);
+                }
+            }
+
             int timelineLength = ois.readInt();
             if (timelineLength != 0) {
                 Parcelable[] parcels = new Parcelable[timelineLength];
@@ -731,11 +737,12 @@
         }
         ArrayList<ComplicationData> entries = new ArrayList<>();
         for (Parcelable parcelable : bundles) {
-            // Pass is the type of the outer complication data to the timeline entries by default.
-            // The array should only contain elements of the same type. The only exception is the
-            // NO_DATA type, which is allowed, but the code in the constructor is going to coerce
-            // the type to NO_DATA if necessary.
-            entries.add(new ComplicationData(mType, (Bundle) parcelable));
+            Bundle bundle = (Bundle) parcelable;
+            // Use the serialized FIELD_TIMELINE_ENTRY_TYPE or the outer type if it's not there.
+            // Usually the timeline entry type will be the same as the outer type, unless an entry
+            // contains NoDataComplicationData.
+            int type = bundle.getInt(FIELD_TIMELINE_ENTRY_TYPE, mType);
+            entries.add(new ComplicationData(type, (Bundle) parcelable));
         }
         return entries;
     }
@@ -747,7 +754,13 @@
         } else {
             mFields.putParcelableArray(
                     FIELD_TIMELINE_ENTRIES,
-                    timelineEntries.stream().map(e -> e.mFields).toArray(Parcelable[]::new));
+                    timelineEntries.stream().map(
+                            e -> {
+                                // This supports timeline entry of NoDataComplicationData.
+                                e.mFields.putInt(FIELD_TIMELINE_ENTRY_TYPE, e.mType);
+                                return e.mFields;
+                            }
+                    ).toArray(Parcelable[]::new));
         }
     }
 
@@ -1215,28 +1228,18 @@
     }
 
     /**
-     * Returns true if the ComplicationData contains a placeholder type. I.e. if
-     * {@link #getPlaceholderType} can succeed.
+     * Returns the placeholder ComplicationData if there is one or `null`.
      */
-    public boolean hasPlaceholderType() {
-        try {
-            return isFieldValidForType(FIELD_PLACEHOLDER_TYPE, mType)
-                    && mFields.containsKey(FIELD_PLACEHOLDER_TYPE);
-        } catch (BadParcelableException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Returns the type this complication is a placeholder for.
-     *
-     * <p>Valid only if the type of this complication data is {@link #TYPE_NO_DATA}.
-     * Otherwise returns zero.
-     */
-    @ComplicationType
-    public int getPlaceholderType() {
+    @Nullable
+    public ComplicationData getPlaceholder() {
+        checkFieldValidForType(FIELD_PLACEHOLDER_FIELDS, mType);
         checkFieldValidForType(FIELD_PLACEHOLDER_TYPE, mType);
-        return mFields.getInt(FIELD_PLACEHOLDER_TYPE);
+        if (!mFields.containsKey(FIELD_PLACEHOLDER_FIELDS)
+                || !mFields.containsKey(FIELD_PLACEHOLDER_TYPE)) {
+            return null;
+        }
+        return new ComplicationData(mFields.getInt(FIELD_PLACEHOLDER_TYPE),
+                mFields.getBundle(FIELD_PLACEHOLDER_FIELDS));
     }
 
     /**
@@ -1699,13 +1702,21 @@
         }
 
         /**
-         * Sets the type this complication is a placeholder for.
+         * Sets the placeholder.
          *
          * <p>Returns this Builder to allow chaining.
          */
+        @SuppressLint("SyntheticAccessor")
         @NonNull
-        public Builder setPlaceholderType(@ComplicationType int placeholderType) {
-            putIntField(FIELD_PLACEHOLDER_TYPE, placeholderType);
+        public Builder setPlaceholder(@Nullable ComplicationData placeholder) {
+            if (placeholder == null) {
+                mFields.remove(FIELD_PLACEHOLDER_FIELDS);
+                mFields.remove(FIELD_PLACEHOLDER_TYPE);
+            } else {
+                ComplicationData.checkFieldValidForType(FIELD_PLACEHOLDER_FIELDS, mType);
+                mFields.putBundle(FIELD_PLACEHOLDER_FIELDS, placeholder.mFields);
+                putIntField(FIELD_PLACEHOLDER_TYPE, placeholder.mType);
+            }
             return this;
         }
 
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
index 8520303..5141d8b 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
@@ -86,11 +86,6 @@
     internal open fun fillWireComplicationDataBuilder(builder: WireComplicationDataBuilder) {
     }
 
-    internal fun asPlaceholderWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(NoDataComplicationData.TYPE.toWireComplicationType()).apply {
-            fillWireComplicationDataBuilder(this)
-        }.build()
-
     /**
      * Returns `true` if any of the fields of this ComplicationData are placeholders. I.e. if any
      * fields are equal to: [ComplicationText.PLACEHOLDER], [SmallImage.PLACEHOLDER],
@@ -135,7 +130,7 @@
     TYPE,
     placeholder?.tapAction,
     cachedWireComplicationData,
-    dataSource = placeholder?.dataSource
+    dataSource = null
 ) {
 
     /** Constructs a NoDataComplicationData without a [placeholder]. */
@@ -170,12 +165,12 @@
         }
         return createWireComplicationDataBuilder().apply {
             if (placeholder == null) {
-                setPlaceholderType(TYPE.toWireComplicationType())
+                setPlaceholder(null)
             } else {
-                setPlaceholderType(placeholder.type.toWireComplicationType())
-                placeholder.fillWireComplicationDataBuilder(this)
+                val builder = placeholder.createWireComplicationDataBuilder()
+                placeholder.fillWireComplicationDataBuilder(builder)
+                setPlaceholder(builder.build())
             }
-            setDataSource(dataSource)
         }.build().also { cachedWireComplicationData = it }
     }
 
@@ -1611,6 +1606,84 @@
     }
 }
 
+internal fun WireComplicationData.toPlaceholderComplicationData(): ComplicationData? = when (type) {
+    NoDataComplicationData.TYPE.toWireComplicationType() -> null
+
+    ShortTextComplicationData.TYPE.toWireComplicationType() -> {
+        ShortTextComplicationData.Builder(
+            shortText!!.toApiComplicationTextPlaceholderAware(),
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY
+        ).apply {
+            setTapAction(tapAction)
+            setValidTimeRange(parseTimeRange())
+            setMonochromaticImage(parseIconPlaceholderAware())
+            setTitle(shortTitle?.toApiComplicationTextPlaceholderAware())
+            setDataSource(dataSource)
+        }.build()
+    }
+
+    LongTextComplicationData.TYPE.toWireComplicationType() -> {
+        LongTextComplicationData.Builder(
+            longText!!.toApiComplicationTextPlaceholderAware(),
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY
+        ).apply {
+            setTapAction(tapAction)
+            setValidTimeRange(parseTimeRange())
+            setMonochromaticImage(parseIconPlaceholderAware())
+            setSmallImage(parseSmallImagePlaceholderAware())
+            setTitle(longTitle?.toApiComplicationTextPlaceholderAware())
+            setDataSource(dataSource)
+        }.build()
+    }
+
+    RangedValueComplicationData.TYPE.toWireComplicationType() ->
+        RangedValueComplicationData.Builder(
+            value = rangedValue,
+            min = rangedMinValue,
+            max = rangedMaxValue,
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY
+        ).apply {
+            setTapAction(tapAction)
+            setValidTimeRange(parseTimeRange())
+            setMonochromaticImage(parseIconPlaceholderAware())
+            setTitle(shortTitle?.toApiComplicationTextPlaceholderAware())
+            setText(shortText?.toApiComplicationTextPlaceholderAware())
+            setDataSource(dataSource)
+        }.build()
+
+    MonochromaticImageComplicationData.TYPE.toWireComplicationType() ->
+        MonochromaticImageComplicationData(
+            parseIconPlaceholderAware()!!,
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY,
+            tapAction,
+            parseTimeRange(),
+            this,
+            dataSource
+        )
+
+    SmallImageComplicationData.TYPE.toWireComplicationType() ->
+        SmallImageComplicationData(
+            parseSmallImagePlaceholderAware()!!,
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY,
+            tapAction,
+            parseTimeRange(),
+            this,
+            dataSource
+        )
+
+    PhotoImageComplicationData.TYPE.toWireComplicationType() ->
+        PhotoImageComplicationData(
+            parseLargeImagePlaceholderAware()!!,
+            contentDescription?.toApiComplicationText() ?: ComplicationText.EMPTY,
+            tapAction,
+            parseTimeRange(),
+            this,
+            dataSource
+        )
+
+    else -> null
+}
+
 /**
  * @hide
  */
@@ -1619,95 +1692,9 @@
     val wireComplicationData = this
     return when (type) {
         NoDataComplicationData.TYPE.toWireComplicationType() -> {
-            if (hasPlaceholderType()) {
-                val placeholder = when (placeholderType) {
-                    NoDataComplicationData.TYPE.toWireComplicationType() -> null
-
-                    ShortTextComplicationData.TYPE.toWireComplicationType() -> {
-                        ShortTextComplicationData.Builder(
-                            shortText!!.toApiComplicationTextPlaceholderAware(),
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY
-                        ).apply {
-                            setMonochromaticImage(parseIconPlaceholderAware())
-                            setTitle(shortTitle?.toApiComplicationTextPlaceholderAware())
-                            setDataSource(dataSource)
-                        }.build()
-                    }
-
-                    LongTextComplicationData.TYPE.toWireComplicationType() -> {
-                        LongTextComplicationData.Builder(
-                            longText!!.toApiComplicationTextPlaceholderAware(),
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY
-                        ).apply {
-                            setMonochromaticImage(parseIconPlaceholderAware())
-                            setSmallImage(parseSmallImagePlaceholderAware())
-                            setTitle(longTitle?.toApiComplicationTextPlaceholderAware())
-                            setDataSource(dataSource)
-                        }.build()
-                    }
-
-                    RangedValueComplicationData.TYPE.toWireComplicationType() ->
-                        RangedValueComplicationData.Builder(
-                            value = rangedValue,
-                            min = rangedMinValue,
-                            max = rangedMaxValue,
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY
-                        ).apply {
-                            setMonochromaticImage(parseIconPlaceholderAware())
-                            setTitle(shortTitle?.toApiComplicationTextPlaceholderAware())
-                            setText(shortText?.toApiComplicationTextPlaceholderAware())
-                            setDataSource(dataSource)
-                        }.build()
-
-                    MonochromaticImageComplicationData.TYPE.toWireComplicationType() ->
-                        MonochromaticImageComplicationData(
-                            parseIconPlaceholderAware()!!,
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY,
-                            tapAction,
-                            parseTimeRange(),
-                            wireComplicationData,
-                            dataSource
-                        )
-
-                    SmallImageComplicationData.TYPE.toWireComplicationType() ->
-                        SmallImageComplicationData(
-                            parseSmallImagePlaceholderAware()!!,
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY,
-                            tapAction,
-                            parseTimeRange(),
-                            wireComplicationData,
-                            dataSource
-                        )
-
-                    PhotoImageComplicationData.TYPE.toWireComplicationType() ->
-                        PhotoImageComplicationData(
-                            parseLargeImagePlaceholderAware()!!,
-                            contentDescription?.toApiComplicationText()
-                                ?: ComplicationText.EMPTY,
-                            tapAction,
-                            parseTimeRange(),
-                            wireComplicationData,
-                            dataSource
-                        )
-
-                    else -> throw IllegalStateException(
-                        "Unrecognized placeholderType $placeholderType"
-                    )
-                }
-
-                if (placeholder != null) {
-                    NoDataComplicationData(placeholder)
-                } else {
-                    NoDataComplicationData()
-                }
-            } else {
-                NoDataComplicationData()
-            }
+            placeholder?.toPlaceholderComplicationData() ?.let {
+                NoDataComplicationData(it)
+            } ?: NoDataComplicationData()
         }
 
         EmptyComplicationData.TYPE.toWireComplicationType() -> EmptyComplicationData()
diff --git a/wear/watchface/watchface-complications-data/src/test/java/android/support/wearable/complications/ComplicationDataTest.kt b/wear/watchface/watchface-complications-data/src/test/java/android/support/wearable/complications/ComplicationDataTest.kt
index e583843..2b79589 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/android/support/wearable/complications/ComplicationDataTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/android/support/wearable/complications/ComplicationDataTest.kt
@@ -1095,16 +1095,19 @@
 
     @Test
     public fun timelineEntryCollectionWithPlaceholder() {
+        val placeholderString =
+            androidx.wear.watchface.complications.data.ComplicationText.PLACEHOLDER_STRING
         val data =
             ComplicationData.Builder(ComplicationData.TYPE_LONG_TEXT)
-                .setLongText(ComplicationText.plainText(
-                    androidx.wear.watchface.complications.data.ComplicationText.PLACEHOLDER_STRING))
+                .setLongText(ComplicationText.plainText(placeholderString))
                 .build()
         val timelineEntry =
             ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(ComplicationData.TYPE_LONG_TEXT)
-                .setLongText(ComplicationText.plainText(
-                    androidx.wear.watchface.complications.data.ComplicationText.PLACEHOLDER_STRING))
+                .setPlaceholder(
+                    ComplicationData.Builder(ComplicationData.TYPE_LONG_TEXT)
+                        .setLongText(ComplicationText.plainText(placeholderString))
+                            .build()
+                )
                 .build()
         timelineEntry.timelineStartEpochSecond = 100
         timelineEntry.timelineEndEpochSecond = 1000
@@ -1112,7 +1115,7 @@
 
         val entry = data.timelineEntries!!.first()
         Truth.assertThat(entry.type).isEqualTo(ComplicationData.TYPE_NO_DATA)
-        Truth.assertThat(entry.placeholderType).isEqualTo(ComplicationData.TYPE_LONG_TEXT)
+        Truth.assertThat(entry.placeholder!!.type).isEqualTo(ComplicationData.TYPE_LONG_TEXT)
     }
 
     private companion object {
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
index 19a5e93..f1945a4 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
@@ -45,7 +45,7 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_NO_DATA)
+                    .setPlaceholder(null)
                     .build()
             )
         testRoundTripConversions(data)
@@ -470,12 +470,17 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_SHORT_TEXT)
-                    .setShortText(ComplicationText.PLACEHOLDER.toWireComplicationText())
-                    .setShortTitle(ComplicationText.PLACEHOLDER.toWireComplicationText())
-                    .setIcon(createPlaceholderIcon())
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_SHORT_TEXT)
+                            .setShortText(ComplicationText.PLACEHOLDER.toWireComplicationText())
+                            .setShortTitle(ComplicationText.PLACEHOLDER.toWireComplicationText())
+                            .setIcon(createPlaceholderIcon())
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -533,10 +538,15 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_LONG_TEXT)
-                    .setLongText(WireComplicationText.plainText("text"))
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_LONG_TEXT)
+                            .setLongText(WireComplicationText.plainText("text"))
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -592,13 +602,18 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_RANGED_VALUE)
-                    .setRangedValue(RangedValueComplicationData.PLACEHOLDER)
-                    .setRangedMinValue(0f)
-                    .setRangedMaxValue(100f)
-                    .setShortText(ComplicationText.PLACEHOLDER.toWireComplicationText())
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_RANGED_VALUE)
+                            .setRangedValue(RangedValueComplicationData.PLACEHOLDER)
+                            .setRangedMinValue(0f)
+                            .setRangedMaxValue(100f)
+                            .setShortText(ComplicationText.PLACEHOLDER.toWireComplicationText())
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -656,10 +671,15 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_ICON)
-                    .setIcon(createPlaceholderIcon())
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_ICON)
+                            .setIcon(createPlaceholderIcon())
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -713,11 +733,16 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_SMALL_IMAGE)
-                    .setSmallImage(createPlaceholderIcon())
-                    .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_ICON)
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_SMALL_IMAGE)
+                            .setSmallImage(createPlaceholderIcon())
+                            .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_ICON)
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -771,10 +796,15 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_LARGE_IMAGE)
-                    .setLargeImage(createPlaceholderIcon())
-                    .setContentDescription(WireComplicationText.plainText("content description"))
-                    .setDataSource(dataSourceA)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_LARGE_IMAGE)
+                            .setLargeImage(createPlaceholderIcon())
+                            .setContentDescription(
+                                WireComplicationText.plainText("content description")
+                            )
+                            .setDataSource(dataSourceA)
+                            .build()
+                    )
                     .build()
             )
         testRoundTripConversions(data)
@@ -842,7 +872,7 @@
     public fun noDataComplicationData() {
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_NO_DATA).build(),
+                .setPlaceholder(null).build(),
             ComplicationType.NO_DATA
         )
     }
@@ -953,11 +983,16 @@
         val icon = Icon.createWithContentUri("someuri")
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_SHORT_TEXT)
-                .setContentDescription(WireComplicationText.plainText("content description"))
-                .setShortText(WireComplicationText.plainText("text"))
-                .setShortTitle(WireComplicationText.plainText("title"))
-                .setIcon(icon)
+                .setPlaceholder(
+                    WireComplicationDataBuilder(WireComplicationData.TYPE_SHORT_TEXT)
+                        .setContentDescription(
+                            WireComplicationText.plainText("content description")
+                        )
+                        .setShortText(WireComplicationText.plainText("text"))
+                        .setShortTitle(WireComplicationText.plainText("title"))
+                        .setIcon(icon)
+                        .build()
+                )
                 .build(),
             ComplicationType.NO_DATA
         )
@@ -968,11 +1003,16 @@
         val icon = Icon.createWithContentUri("someuri")
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_LONG_TEXT)
-                .setContentDescription(WireComplicationText.plainText("content description"))
-                .setLongText(WireComplicationText.plainText("text"))
-                .setLongTitle(WireComplicationText.plainText("title"))
-                .setIcon(icon)
+                .setPlaceholder(
+                    WireComplicationDataBuilder(WireComplicationData.TYPE_LONG_TEXT)
+                        .setContentDescription(
+                            WireComplicationText.plainText("content description")
+                        )
+                        .setLongText(WireComplicationText.plainText("text"))
+                        .setLongTitle(WireComplicationText.plainText("title"))
+                        .setIcon(icon)
+                        .build()
+                )
                 .build(),
             ComplicationType.NO_DATA
         )
@@ -983,13 +1023,18 @@
         val icon = Icon.createWithContentUri("someuri")
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_RANGED_VALUE)
-                .setContentDescription(WireComplicationText.plainText("content description"))
-                .setRangedValue(75f)
-                .setRangedMinValue(0f)
-                .setRangedMaxValue(100f)
-                .setShortTitle(WireComplicationText.plainText("battery"))
-                .setIcon(icon)
+                .setPlaceholder(
+                    WireComplicationDataBuilder(WireComplicationData.TYPE_RANGED_VALUE)
+                        .setContentDescription(
+                            WireComplicationText.plainText("content description")
+                        )
+                        .setRangedValue(75f)
+                        .setRangedMinValue(0f)
+                        .setRangedMaxValue(100f)
+                        .setShortTitle(WireComplicationText.plainText("battery"))
+                        .setIcon(icon)
+                        .build()
+                )
                 .build(),
             ComplicationType.NO_DATA
         )
@@ -1000,10 +1045,15 @@
         val icon = Icon.createWithContentUri("someuri")
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_SMALL_IMAGE)
-                .setSmallImage(icon)
-                .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_PHOTO)
-                .setContentDescription(WireComplicationText.plainText("content description"))
+                .setPlaceholder(
+                    WireComplicationDataBuilder(WireComplicationData.TYPE_SMALL_IMAGE)
+                        .setSmallImage(icon)
+                        .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_PHOTO)
+                        .setContentDescription(
+                            WireComplicationText.plainText("content description")
+                        )
+                        .build()
+                )
                 .build(),
             ComplicationType.NO_DATA
         )
@@ -1014,9 +1064,14 @@
         val icon = Icon.createWithContentUri("someuri")
         assertRoundtrip(
             WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                .setPlaceholderType(WireComplicationData.TYPE_ICON)
-                .setIcon(icon)
-                .setContentDescription(WireComplicationText.plainText("content description"))
+                .setPlaceholder(
+                    WireComplicationDataBuilder(WireComplicationData.TYPE_ICON)
+                        .setIcon(icon)
+                        .setContentDescription(
+                            WireComplicationText.plainText("content description")
+                        )
+                        .build()
+                )
                 .build(),
             ComplicationType.NO_DATA
         )
@@ -1105,14 +1160,14 @@
     }
 
     @Test
-    public fun NoDataComplicationData() {
+    public fun noDataComplicationData() {
         assertThat(
             NoDataComplicationData(
                 ShortTextComplicationData.Builder(
                     ComplicationText.PLACEHOLDER,
                     ComplicationText.EMPTY
                 ).setTapAction(mPendingIntent).build()
-            ).asWireComplicationData().tapAction
+            ).asWireComplicationData().placeholder?.tapAction
         ).isEqualTo(mPendingIntent)
     }
 }
@@ -1325,8 +1380,11 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_SHORT_TEXT)
-                    .setShortText(WireComplicationText.plainText("text"))
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_SHORT_TEXT)
+                            .setShortText(WireComplicationText.plainText("text"))
+                            .build()
+                    )
                     .build()
             )
     }
@@ -1340,8 +1398,11 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_LONG_TEXT)
-                    .setLongText(WireComplicationText.plainText("text"))
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_LONG_TEXT)
+                            .setLongText(WireComplicationText.plainText("text"))
+                            .build()
+                    )
                     .build()
             )
     }
@@ -1359,10 +1420,13 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_RANGED_VALUE)
-                    .setRangedValue(95f)
-                    .setRangedMinValue(0f)
-                    .setRangedMaxValue(100f)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_RANGED_VALUE)
+                            .setRangedValue(95f)
+                            .setRangedMinValue(0f)
+                            .setRangedMaxValue(100f)
+                            .build()
+                    )
                     .build()
             )
     }
@@ -1377,8 +1441,11 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_ICON)
-                    .setIcon(icon)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_ICON)
+                            .setIcon(icon)
+                            .build()
+                    )
                     .build()
             )
     }
@@ -1393,9 +1460,12 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_SMALL_IMAGE)
-                    .setSmallImage(icon)
-                    .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_PHOTO)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_SMALL_IMAGE)
+                            .setSmallImage(icon)
+                            .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_PHOTO)
+                            .build()
+                    )
                     .build()
             )
     }
@@ -1409,8 +1479,11 @@
         ParcelableSubject.assertThat(data.asWireComplicationData())
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA)
-                    .setPlaceholderType(WireComplicationData.TYPE_LARGE_IMAGE)
-                    .setLargeImage(icon)
+                    .setPlaceholder(
+                        WireComplicationDataBuilder(WireComplicationData.TYPE_LARGE_IMAGE)
+                            .setLargeImage(icon)
+                            .build()
+                    )
                     .build()
             )
     }
diff --git a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
index 8ede3a8..2f790f8 100644
--- a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
+++ b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
@@ -170,6 +170,7 @@
     boolean mIsPlaceholderTitle;
     @VisibleForTesting
     boolean mIsPlaceholderText;
+    boolean mIsPlaceholder;
 
     // Drawables for rendering rounded images
     private RoundedDrawable mRoundedBackgroundDrawable = null;
@@ -284,9 +285,12 @@
         mIsPlaceholderRangedValue = false;
         mIsPlaceholderTitle = false;
         mIsPlaceholderText = false;
+        mIsPlaceholder = false;
 
         if (data.getType() == ComplicationData.TYPE_NO_DATA) {
-            if (data.hasPlaceholderType()) {
+            ComplicationData placeholder = data.getPlaceholder();
+            if (placeholder != null) {
+                data = placeholder;
                 mIsPlaceholderIcon = data.hasIcon() && ImageKt.isPlaceholder(data.getIcon());
                 mIsPlaceholderSmallImage =
                         data.hasSmallImage() && ImageKt.isPlaceholder(data.getSmallImage());
@@ -295,7 +299,7 @@
                 mIsPlaceholderRangedValue = data.hasRangedValue()
                         && data.getRangedValue()
                         == RangedValueComplicationData.PLACEHOLDER;
-                if (data.getPlaceholderType() == ComplicationData.TYPE_LONG_TEXT) {
+                if (data.getType() == ComplicationData.TYPE_LONG_TEXT) {
                     mIsPlaceholderTitle =
                             data.hasLongTitle() && data.getLongTitle().isPlaceholder();
                     mIsPlaceholderText =
@@ -308,6 +312,7 @@
                 }
                 mComplicationData = data;
                 mHasNoData = false;
+                mIsPlaceholder = true;
             } else {
                 if (!mHasNoData) {
                     // Render TYPE_NO_DATA as a short text complication with a predefined string
@@ -547,8 +552,8 @@
             float height;
             // Avoid drawing two placeholder text fields of the same length.
             if (!mSubTextBounds.isEmpty()
-                    && (mComplicationData.getPlaceholderType() == ComplicationData.TYPE_SHORT_TEXT
-                    || mComplicationData.getPlaceholderType() == ComplicationData.TYPE_LONG_TEXT)) {
+                    && (mComplicationData.getType() == ComplicationData.TYPE_SHORT_TEXT
+                    || mComplicationData.getType() == ComplicationData.TYPE_LONG_TEXT)) {
                 width = mMainTextBounds.width() * 0.4f;
                 height = mMainTextBounds.height() * 0.9f;
             } else {
@@ -659,7 +664,7 @@
             if (paintSet.isInBurnInProtectionMode() && mBurnInProtectionIcon != null) {
                 icon = mBurnInProtectionIcon;
             }
-            icon.setColorFilter(mComplicationData.hasPlaceholderType() ? PLACEHOLDER_COLOR_FILTER :
+            icon.setColorFilter(mIsPlaceholder ? PLACEHOLDER_COLOR_FILTER :
                     paintSet.mIconColorFilter);
             drawIconOnCanvas(canvas, mIconBounds, icon);
         } else if (isPlaceholder) {
@@ -768,9 +773,6 @@
         mBackgroundBoundsF.set(0, 0, mBounds.width(), mBounds.height());
         LayoutHelper currentLayoutHelper;
         int type = mComplicationData.getType();
-        if (type == ComplicationData.TYPE_NO_DATA && mComplicationData.hasPlaceholderType()) {
-            type = mComplicationData.getPlaceholderType();
-        }
         switch (type) {
             case ComplicationData.TYPE_ICON:
                 currentLayoutHelper = new IconLayoutHelper();
diff --git a/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
index d3dd469..f3b4ae2 100644
--- a/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
+++ b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
@@ -608,8 +608,10 @@
     public void placeholderLongTextIsDrawnAsPlaceholder() {
         mComplicationRenderer.setComplicationData(
                 new ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                        .setPlaceholderType(ComplicationData.TYPE_LONG_TEXT)
-                        .setLongText(PLACEHOLDER_COMPLICATION_TEXT)
+                        .setPlaceholder(new ComplicationData.Builder(
+                                ComplicationData.TYPE_LONG_TEXT)
+                                .setLongText(PLACEHOLDER_COMPLICATION_TEXT)
+                                .build())
                         .build(),
                 true);
 
@@ -623,8 +625,10 @@
     public void placeholderShortTextIsDrawnAsPlaceholder() {
         mComplicationRenderer.setComplicationData(
                 new ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                        .setPlaceholderType(ComplicationData.TYPE_SHORT_TEXT)
-                        .setShortText(PLACEHOLDER_COMPLICATION_TEXT)
+                        .setPlaceholder(new ComplicationData.Builder(
+                                ComplicationData.TYPE_SHORT_TEXT)
+                                .setShortText(PLACEHOLDER_COMPLICATION_TEXT)
+                                .build())
                         .build(),
                 true);
 
@@ -638,9 +642,11 @@
     public void placeholderLongTitleIsDrawnAsPlaceholder() {
         mComplicationRenderer.setComplicationData(
                 new ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                        .setPlaceholderType(ComplicationData.TYPE_LONG_TEXT)
-                        .setLongText(ComplicationText.plainText("Hi"))
-                        .setLongTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                        .setPlaceholder(new ComplicationData.Builder(
+                                ComplicationData.TYPE_LONG_TEXT)
+                                .setLongText(ComplicationText.plainText("Hi"))
+                                .setLongTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                                .build())
                         .build(),
                 true);
 
@@ -654,9 +660,11 @@
     public void placeholderShortTitleIsDrawnAsPlaceholder() {
         mComplicationRenderer.setComplicationData(
                 new ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                        .setPlaceholderType(ComplicationData.TYPE_SHORT_TEXT)
-                        .setShortText(ComplicationText.plainText("Hi"))
-                        .setShortTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                        .setPlaceholder(new ComplicationData.Builder(
+                                ComplicationData.TYPE_SHORT_TEXT)
+                                .setShortText(ComplicationText.plainText("Hi"))
+                                .setShortTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                                .build())
                         .build(),
                 true);
 
@@ -670,11 +678,13 @@
     public void iconIsTintedWithPlaceholderTintForPlaceholderComplication() {
         mComplicationRenderer.setComplicationData(
                 new ComplicationData.Builder(ComplicationData.TYPE_NO_DATA)
-                        .setPlaceholderType(ComplicationData.TYPE_SHORT_TEXT)
-                        .setShortText(ComplicationText.plainText("Hi"))
-                        .setIcon(Icon.createWithBitmap(
-                                Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565)))
-                        .setShortTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                        .setPlaceholder(new ComplicationData.Builder(
+                                ComplicationData.TYPE_SHORT_TEXT)
+                                .setShortText(ComplicationText.plainText("Hi"))
+                                .setIcon(Icon.createWithBitmap(
+                                        Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565)))
+                                .setShortTitle(PLACEHOLDER_COMPLICATION_TEXT)
+                                .build())
                         .build(),
                 false);
 
diff --git a/wear/watchface/watchface/src/main/AndroidManifest.xml b/wear/watchface/watchface/src/main/AndroidManifest.xml
index 52231e3..546fd68 100644
--- a/wear/watchface/watchface/src/main/AndroidManifest.xml
+++ b/wear/watchface/watchface/src/main/AndroidManifest.xml
@@ -35,6 +35,8 @@
         android:exported="true"
         android:permission="com.google.android.wearable.permission.BIND_WATCH_FACE_CONTROL">
       <meta-data android:name="androidx.wear.watchface.api_version" android:value="5" />
+      <meta-data android:name="androidx.wear.watchface.xml_version"
+          android:value="@integer/watch_face_xml_version" />
       <intent-filter>
         <action android:name="com.google.android.wearable.action.WATCH_FACE_CONTROL"/>
       </intent-filter>
diff --git a/wear/watchface/watchface/src/main/res/values/config.xml b/wear/watchface/watchface/src/main/res/values/config.xml
index 2325b7c2..a0e0eec 100644
--- a/wear/watchface/watchface/src/main/res/values/config.xml
+++ b/wear/watchface/watchface/src/main/res/values/config.xml
@@ -17,4 +17,5 @@
 
 <resources>
     <bool name="watch_face_instance_service_enabled">false</bool>
+    <integer name="watch_face_xml_version">0</integer>
 </resources>