Merge "SwiftKey multiline for when ImeAction is unspecified" into androidx-main
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt b/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
index 1173c37..273ff17 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
@@ -477,7 +477,15 @@
             setOf(
                 ":compose:integration-tests:macrobenchmark",
                 ":compose:integration-tests:macrobenchmark-target"
-            ), // link compose's macrobenchmark and its target
+            ),
+            setOf(
+                ":emoji2:integration-tests:init-disabled-macrobenchmark",
+                ":emoji2:integration-tests:init-disabled-macrobenchmark-target",
+            ),
+            setOf(
+                ":emoji2:integration-tests:init-enabled-macrobenchmark",
+                ":emoji2:integration-tests:init-enabled-macrobenchmark-target",
+            ),
         )
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/build.gradle b/camera/camera-camera2-pipe-integration/build.gradle
index 2c57aeb..e14d471 100644
--- a/camera/camera-camera2-pipe-integration/build.gradle
+++ b/camera/camera-camera2-pipe-integration/build.gradle
@@ -38,6 +38,7 @@
 )
 
 dependencies {
+    implementation("androidx.core:core:1.1.0")
     implementation("androidx.concurrent:concurrent-listenablefuture-callback:1.0.0-beta01")
     bundleInside(project(path: ":camera:camera-camera2-pipe", configuration: "exportRelease"))
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt
new file mode 100644
index 0000000..d038a85
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/MeteringRepeating.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.impl
+
+import android.graphics.ImageFormat
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraDevice
+import android.os.Build
+import android.util.Size
+import android.view.Surface
+import androidx.camera.camera2.pipe.core.Log.error
+import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.UseCase
+import androidx.camera.core.impl.CaptureConfig
+import androidx.camera.core.impl.Config
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.ImageFormatConstants
+import androidx.camera.core.impl.ImageInputConfig
+import androidx.camera.core.impl.ImmediateSurface
+import androidx.camera.core.impl.MutableOptionsBundle
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.UseCaseConfig
+import androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER
+import androidx.camera.core.impl.UseCaseConfigFactory
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.core.util.Consumer
+
+private val DEFAULT_PREVIEW_SIZE = Size(0, 0)
+
+/**
+ * A [UseCase] used to issue repeating requests when only [androidx.camera.core.ImageCapture] is
+ * enabled, since taking a picture may require a repeating surface to perform pre-capture checks,
+ * mainly around 3A.
+ */
+class MeteringRepeating(
+    private val cameraProperties: CameraProperties,
+    config: MeteringRepeatingConfig,
+) : UseCase(config) {
+
+    private val meteringSurfaceSize = cameraProperties.getMinimumPreviewSize()
+    private var deferrableSurface: DeferrableSurface? = null
+
+    override fun getDefaultConfig(applyDefaultConfig: Boolean, factory: UseCaseConfigFactory) =
+        Builder(cameraProperties).useCaseConfig
+
+    override fun getUseCaseConfigBuilder(config: Config) = Builder(cameraProperties)
+
+    override fun onSuggestedResolutionUpdated(suggestedResolution: Size): Size {
+        updateSessionConfig(createPipeline().build())
+        notifyActive()
+        return meteringSurfaceSize
+    }
+
+    override fun onDetached() {
+        deferrableSurface?.close()
+        deferrableSurface = null
+    }
+
+    private fun createPipeline(): SessionConfig.Builder {
+        val surfaceTexture = SurfaceTexture(0).apply {
+            setDefaultBufferSize(meteringSurfaceSize.width, meteringSurfaceSize.height)
+        }
+        val surface = Surface(surfaceTexture)
+
+        deferrableSurface?.close()
+        deferrableSurface = ImmediateSurface(surface)
+        deferrableSurface!!.terminationFuture
+            .addListener(
+                {
+                    surface.release()
+                    surfaceTexture.release()
+                },
+                CameraXExecutors.directExecutor()
+            )
+
+        return SessionConfig.Builder
+            .createFrom(MeteringRepeatingConfig())
+            .apply {
+                setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
+                addSurface(deferrableSurface!!)
+                addErrorListener { _, _ ->
+                    updateSessionConfig(createPipeline().build())
+                    notifyReset()
+                }
+            }
+    }
+
+    private fun CameraProperties.getMinimumPreviewSize(): Size {
+        val map = metadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
+        if (map == null) {
+            error { "Can not retrieve SCALER_STREAM_CONFIGURATION_MAP." }
+            return DEFAULT_PREVIEW_SIZE
+        }
+
+        val outputSizes = if (Build.VERSION.SDK_INT < 23) {
+            // ImageFormat.PRIVATE is only public after Android level 23. Therefore, use
+            // SurfaceTexture.class to get the supported output sizes before Android level 23.
+            map.getOutputSizes(SurfaceTexture::class.java)
+        } else {
+            map.getOutputSizes(ImageFormat.PRIVATE)
+        }
+
+        if (outputSizes == null) {
+            error { "Can not get output size list." }
+            return DEFAULT_PREVIEW_SIZE
+        }
+
+        check(outputSizes.isNotEmpty()) { "Output sizes empty" }
+        return outputSizes.minWithOrNull { size1, size2 -> size1.area().compareTo(size2.area()) }!!
+    }
+
+    class MeteringRepeatingConfig : UseCaseConfig<MeteringRepeating>, ImageInputConfig {
+        private val config = MutableOptionsBundle.create().apply {
+            insertOption(
+                OPTION_SESSION_CONFIG_UNPACKER,
+                CameraUseCaseAdapter.DefaultSessionOptionsUnpacker
+            )
+        }
+
+        override fun getConfig() = config
+
+        override fun getInputFormat() = ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+    }
+
+    class Builder(private val cameraProperties: CameraProperties) :
+        UseCaseConfig.Builder<MeteringRepeating, MeteringRepeatingConfig, Builder> {
+
+        override fun getMutableConfig() = MutableOptionsBundle.create()
+
+        override fun getUseCaseConfig() = MeteringRepeatingConfig()
+
+        override fun setTargetClass(targetClass: Class<MeteringRepeating>) = this
+
+        override fun setTargetName(targetName: String) = this
+
+        override fun setUseCaseEventCallback(eventCallback: EventCallback) = this
+
+        override fun setDefaultSessionConfig(sessionConfig: SessionConfig) = this
+
+        override fun setDefaultCaptureConfig(captureConfig: CaptureConfig) = this
+
+        override fun setSessionOptionUnpacker(optionUnpacker: SessionConfig.OptionUnpacker) = this
+
+        override fun setCaptureOptionUnpacker(optionUnpacker: CaptureConfig.OptionUnpacker) = this
+
+        override fun setSurfaceOccupancyPriority(priority: Int) = this
+
+        override fun setCameraSelector(cameraSelector: CameraSelector) = this
+
+        override fun setAttachedUseCasesUpdateListener(
+            attachedUseCasesUpdateListener: Consumer<MutableCollection<UseCase>>
+        ): Builder = this
+
+        override fun build(): MeteringRepeating {
+            return MeteringRepeating(cameraProperties, useCaseConfig)
+        }
+    }
+}
diff --git a/camera/camera-view/api/current.txt b/camera/camera-view/api/current.txt
index 645b302..160857f 100644
--- a/camera/camera-view/api/current.txt
+++ b/camera/camera-view/api/current.txt
@@ -33,40 +33,6 @@
     field public static final int IMAGE_CAPTURE = 1; // 0x1
   }
 
-  @Deprecated public final class CameraView extends android.widget.FrameLayout {
-    ctor @Deprecated public CameraView(android.content.Context);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?, int);
-    ctor @Deprecated @RequiresApi(21) public CameraView(android.content.Context, android.util.AttributeSet?, int, int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
-    method @Deprecated public void enableTorch(boolean);
-    method @Deprecated public Integer? getCameraLensFacing();
-    method @Deprecated public androidx.camera.view.CameraView.CaptureMode getCaptureMode();
-    method @Deprecated public int getFlash();
-    method @Deprecated public float getMaxZoomRatio();
-    method @Deprecated public float getMinZoomRatio();
-    method @Deprecated public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
-    method @Deprecated public androidx.camera.view.PreviewView.ScaleType getScaleType();
-    method @Deprecated public float getZoomRatio();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public boolean hasCameraWithLensFacing(int);
-    method @Deprecated public boolean isPinchToZoomEnabled();
-    method @Deprecated public boolean isTorchOn();
-    method @Deprecated public boolean isZoomSupported();
-    method @Deprecated public void setCameraLensFacing(Integer?);
-    method @Deprecated public void setCaptureMode(androidx.camera.view.CameraView.CaptureMode);
-    method @Deprecated public void setFlash(int);
-    method @Deprecated public void setPinchToZoomEnabled(boolean);
-    method @Deprecated public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
-    method @Deprecated public void setZoomRatio(float);
-    method @Deprecated public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
-    method @Deprecated public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
-    method @Deprecated public void toggleCamera();
-  }
-
-  @Deprecated public enum CameraView.CaptureMode {
-    enum_constant @Deprecated public static final androidx.camera.view.CameraView.CaptureMode IMAGE;
-  }
-
   public final class LifecycleCameraController extends androidx.camera.view.CameraController {
     ctor public LifecycleCameraController(android.content.Context);
     method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
diff --git a/camera/camera-view/api/public_plus_experimental_current.txt b/camera/camera-view/api/public_plus_experimental_current.txt
index 6dbb420..4190144 100644
--- a/camera/camera-view/api/public_plus_experimental_current.txt
+++ b/camera/camera-view/api/public_plus_experimental_current.txt
@@ -38,47 +38,6 @@
     field @androidx.camera.view.video.ExperimentalVideo public static final int VIDEO_CAPTURE = 4; // 0x4
   }
 
-  @Deprecated public final class CameraView extends android.widget.FrameLayout {
-    ctor @Deprecated public CameraView(android.content.Context);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?, int);
-    ctor @Deprecated @RequiresApi(21) public CameraView(android.content.Context, android.util.AttributeSet?, int, int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
-    method @Deprecated public void enableTorch(boolean);
-    method @Deprecated public Integer? getCameraLensFacing();
-    method @Deprecated public androidx.camera.view.CameraView.CaptureMode getCaptureMode();
-    method @Deprecated @androidx.camera.core.ImageCapture.FlashMode public int getFlash();
-    method @Deprecated public float getMaxZoomRatio();
-    method @Deprecated public float getMinZoomRatio();
-    method @Deprecated public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
-    method @Deprecated public androidx.camera.view.PreviewView.ScaleType getScaleType();
-    method @Deprecated public float getZoomRatio();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public boolean hasCameraWithLensFacing(@androidx.camera.core.CameraSelector.LensFacing int);
-    method @Deprecated public boolean isPinchToZoomEnabled();
-    method @Deprecated @androidx.camera.view.video.ExperimentalVideo public boolean isRecording();
-    method @Deprecated public boolean isTorchOn();
-    method @Deprecated public boolean isZoomSupported();
-    method @Deprecated public void setCameraLensFacing(Integer?);
-    method @Deprecated public void setCaptureMode(androidx.camera.view.CameraView.CaptureMode);
-    method @Deprecated public void setFlash(@androidx.camera.core.ImageCapture.FlashMode int);
-    method @Deprecated public void setPinchToZoomEnabled(boolean);
-    method @Deprecated public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
-    method @Deprecated public void setZoomRatio(float);
-    method @Deprecated @androidx.camera.view.video.ExperimentalVideo public void startRecording(java.io.File, java.util.concurrent.Executor, androidx.camera.view.video.OnVideoSavedCallback);
-    method @Deprecated @androidx.camera.view.video.ExperimentalVideo public void startRecording(android.os.ParcelFileDescriptor, java.util.concurrent.Executor, androidx.camera.view.video.OnVideoSavedCallback);
-    method @Deprecated @androidx.camera.view.video.ExperimentalVideo public void startRecording(androidx.camera.view.video.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.view.video.OnVideoSavedCallback);
-    method @Deprecated @androidx.camera.view.video.ExperimentalVideo public void stopRecording();
-    method @Deprecated public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
-    method @Deprecated public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
-    method @Deprecated public void toggleCamera();
-  }
-
-  @Deprecated public enum CameraView.CaptureMode {
-    enum_constant @Deprecated public static final androidx.camera.view.CameraView.CaptureMode IMAGE;
-    enum_constant @Deprecated @androidx.camera.view.video.ExperimentalVideo public static final androidx.camera.view.CameraView.CaptureMode MIXED;
-    enum_constant @Deprecated @androidx.camera.view.video.ExperimentalVideo public static final androidx.camera.view.CameraView.CaptureMode VIDEO;
-  }
-
   public final class LifecycleCameraController extends androidx.camera.view.CameraController {
     ctor public LifecycleCameraController(android.content.Context);
     method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
diff --git a/camera/camera-view/api/restricted_current.txt b/camera/camera-view/api/restricted_current.txt
index d0ba609..56cdeaa 100644
--- a/camera/camera-view/api/restricted_current.txt
+++ b/camera/camera-view/api/restricted_current.txt
@@ -33,40 +33,6 @@
     field public static final int IMAGE_CAPTURE = 1; // 0x1
   }
 
-  @Deprecated public final class CameraView extends android.widget.FrameLayout {
-    ctor @Deprecated public CameraView(android.content.Context);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?);
-    ctor @Deprecated public CameraView(android.content.Context, android.util.AttributeSet?, int);
-    ctor @Deprecated @RequiresApi(21) public CameraView(android.content.Context, android.util.AttributeSet?, int, int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
-    method @Deprecated public void enableTorch(boolean);
-    method @Deprecated public Integer? getCameraLensFacing();
-    method @Deprecated public androidx.camera.view.CameraView.CaptureMode getCaptureMode();
-    method @Deprecated @androidx.camera.core.ImageCapture.FlashMode public int getFlash();
-    method @Deprecated public float getMaxZoomRatio();
-    method @Deprecated public float getMinZoomRatio();
-    method @Deprecated public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
-    method @Deprecated public androidx.camera.view.PreviewView.ScaleType getScaleType();
-    method @Deprecated public float getZoomRatio();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.CAMERA) public boolean hasCameraWithLensFacing(@androidx.camera.core.CameraSelector.LensFacing int);
-    method @Deprecated public boolean isPinchToZoomEnabled();
-    method @Deprecated public boolean isTorchOn();
-    method @Deprecated public boolean isZoomSupported();
-    method @Deprecated public void setCameraLensFacing(Integer?);
-    method @Deprecated public void setCaptureMode(androidx.camera.view.CameraView.CaptureMode);
-    method @Deprecated public void setFlash(@androidx.camera.core.ImageCapture.FlashMode int);
-    method @Deprecated public void setPinchToZoomEnabled(boolean);
-    method @Deprecated public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
-    method @Deprecated public void setZoomRatio(float);
-    method @Deprecated public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
-    method @Deprecated public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
-    method @Deprecated public void toggleCamera();
-  }
-
-  @Deprecated public enum CameraView.CaptureMode {
-    enum_constant @Deprecated public static final androidx.camera.view.CameraView.CaptureMode IMAGE;
-  }
-
   public final class LifecycleCameraController extends androidx.camera.view.CameraController {
     ctor public LifecycleCameraController(android.content.Context);
     method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
diff --git a/camera/camera-view/build.gradle b/camera/camera-view/build.gradle
index 06c00c8..2b2420f 100644
--- a/camera/camera-view/build.gradle
+++ b/camera/camera-view/build.gradle
@@ -36,7 +36,7 @@
     implementation("androidx.camera:camera-lifecycle:${VIEW_ATOMIC_GROUP_PINNED_VER}")
     implementation("androidx.annotation:annotation-experimental:1.1.0-rc01")
     implementation(GUAVA_LISTENABLE_FUTURE)
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.3.2")
     implementation("androidx.concurrent:concurrent-futures:1.0.0")
     implementation(AUTO_VALUE_ANNOTATIONS)
     implementation("androidx.appcompat:appcompat:1.1.0")
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java
deleted file mode 100644
index b6106fc..0000000
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraView.java
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * Copyright (C) 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.camera.view;
-
-import android.Manifest.permission;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.annotation.RequiresPermission;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.camera.core.Camera;
-import androidx.camera.core.CameraSelector;
-import androidx.camera.core.FocusMeteringAction;
-import androidx.camera.core.FocusMeteringResult;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.ImageCapture.OnImageCapturedCallback;
-import androidx.camera.core.ImageCapture.OnImageSavedCallback;
-import androidx.camera.core.ImageProxy;
-import androidx.camera.core.Logger;
-import androidx.camera.core.MeteringPoint;
-import androidx.camera.core.MeteringPointFactory;
-import androidx.camera.core.VideoCapture;
-import androidx.camera.core.impl.LensFacingConverter;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.core.impl.utils.futures.FutureCallback;
-import androidx.camera.core.impl.utils.futures.Futures;
-import androidx.camera.view.video.ExperimentalVideo;
-import androidx.camera.view.video.OnVideoSavedCallback;
-import androidx.camera.view.video.OutputFileOptions;
-import androidx.camera.view.video.OutputFileResults;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LiveData;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.io.File;
-import java.util.concurrent.Executor;
-
-/**
- * A {@link View} that displays a preview of the camera with methods {@link
- * #takePicture(Executor, OnImageCapturedCallback)},
- * {@link #takePicture(ImageCapture.OutputFileOptions, Executor, OnImageSavedCallback)},
- * {@link #startRecording(File, Executor, OnVideoSavedCallback callback)}
- * and {@link #stopRecording()}.
- *
- * <p>Because the Camera is a limited resource and consumes a high amount of power, CameraView must
- * be opened/closed. CameraView will handle opening/closing automatically through use of a {@link
- * LifecycleOwner}. Use {@link #bindToLifecycle(LifecycleOwner)} to start the camera.
- *
- * @deprecated Use {@link LifecycleCameraController}. See
- * <a href="https://medium.com/androiddevelopers/camerax-learn-how-to-use-cameracontroller
- * -e3ed10fffecf">migration guide</a>.
- */
-@Deprecated
-public final class CameraView extends FrameLayout {
-    static final String TAG = CameraView.class.getSimpleName();
-
-    static final int INDEFINITE_VIDEO_DURATION = -1;
-    static final int INDEFINITE_VIDEO_SIZE = -1;
-
-    private static final String EXTRA_SUPER = "super";
-    private static final String EXTRA_ZOOM_RATIO = "zoom_ratio";
-    private static final String EXTRA_PINCH_TO_ZOOM_ENABLED = "pinch_to_zoom_enabled";
-    private static final String EXTRA_FLASH = "flash";
-    private static final String EXTRA_MAX_VIDEO_DURATION = "max_video_duration";
-    private static final String EXTRA_MAX_VIDEO_SIZE = "max_video_size";
-    private static final String EXTRA_SCALE_TYPE = "scale_type";
-    private static final String EXTRA_CAMERA_DIRECTION = "camera_direction";
-    private static final String EXTRA_CAPTURE_MODE = "captureMode";
-
-    private static final int LENS_FACING_NONE = 0;
-    private static final int LENS_FACING_FRONT = 1;
-    private static final int LENS_FACING_BACK = 2;
-    private static final int FLASH_MODE_AUTO = 1;
-    private static final int FLASH_MODE_ON = 2;
-    private static final int FLASH_MODE_OFF = 4;
-    // For tap-to-focus
-    private long mDownEventTimestamp;
-    // For pinch-to-zoom
-    private PinchToZoomGestureDetector mPinchToZoomGestureDetector;
-    private boolean mIsPinchToZoomEnabled = true;
-    CameraXModule mCameraModule;
-    private final DisplayManager.DisplayListener mDisplayListener =
-            new DisplayListener() {
-                @Override
-                public void onDisplayAdded(int displayId) {
-                }
-
-                @Override
-                public void onDisplayRemoved(int displayId) {
-                }
-
-                @Override
-                public void onDisplayChanged(int displayId) {
-                    mCameraModule.invalidateView();
-                }
-            };
-    private PreviewView mPreviewView;
-    // For accessibility event
-    private MotionEvent mUpEvent;
-
-    public CameraView(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(context, attrs);
-    }
-
-    @RequiresApi(21)
-    public CameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        init(context, attrs);
-    }
-
-    /**
-     * Binds control of the camera used by this view to the given lifecycle.
-     *
-     * <p>This links opening/closing the camera to the given lifecycle. The camera will not operate
-     * unless this method is called with a valid {@link LifecycleOwner} that is not in the {@link
-     * androidx.lifecycle.Lifecycle.State#DESTROYED} state. Call this method only once camera
-     * permissions have been obtained.
-     *
-     * <p>Once the provided lifecycle has transitioned to a {@link
-     * androidx.lifecycle.Lifecycle.State#DESTROYED} state, CameraView must be bound to a new
-     * lifecycle through this method in order to operate the camera.
-     *
-     * @param lifecycleOwner The lifecycle that will control this view's camera
-     * @throws IllegalArgumentException if provided lifecycle is in a {@link
-     *                                  androidx.lifecycle.Lifecycle.State#DESTROYED} state.
-     * @throws IllegalStateException    if camera permissions are not granted.
-     */
-    @RequiresPermission(permission.CAMERA)
-    public void bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner) {
-        mCameraModule.bindToLifecycle(lifecycleOwner);
-    }
-
-    private void init(Context context, @Nullable AttributeSet attrs) {
-        addView(mPreviewView = new PreviewView(getContext()), 0 /* view position */);
-        mCameraModule = new CameraXModule(this);
-
-        if (attrs != null) {
-            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView);
-            setScaleType(
-                    PreviewView.ScaleType.fromId(
-                            a.getInteger(R.styleable.CameraView_scaleType,
-                                    getScaleType().getId())));
-            setPinchToZoomEnabled(
-                    a.getBoolean(
-                            R.styleable.CameraView_pinchToZoomEnabled, isPinchToZoomEnabled()));
-            setCaptureMode(
-                    CaptureMode.fromId(
-                            a.getInteger(R.styleable.CameraView_captureMode,
-                                    getCaptureMode().getId())));
-
-            int lensFacing = a.getInt(R.styleable.CameraView_lensFacing, LENS_FACING_BACK);
-            switch (lensFacing) {
-                case LENS_FACING_NONE:
-                    setCameraLensFacing(null);
-                    break;
-                case LENS_FACING_FRONT:
-                    setCameraLensFacing(CameraSelector.LENS_FACING_FRONT);
-                    break;
-                case LENS_FACING_BACK:
-                    setCameraLensFacing(CameraSelector.LENS_FACING_BACK);
-                    break;
-                default:
-                    // Unhandled event.
-            }
-
-            int flashMode = a.getInt(R.styleable.CameraView_flash, 0);
-            switch (flashMode) {
-                case FLASH_MODE_AUTO:
-                    setFlash(ImageCapture.FLASH_MODE_AUTO);
-                    break;
-                case FLASH_MODE_ON:
-                    setFlash(ImageCapture.FLASH_MODE_ON);
-                    break;
-                case FLASH_MODE_OFF:
-                    setFlash(ImageCapture.FLASH_MODE_OFF);
-                    break;
-                default:
-                    // Unhandled event.
-            }
-
-            a.recycle();
-        }
-
-        if (getBackground() == null) {
-            setBackgroundColor(0xFF111111);
-        }
-
-        mPinchToZoomGestureDetector = new PinchToZoomGestureDetector(context);
-    }
-
-    @Override
-    @NonNull
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-    }
-
-    @Override
-    @NonNull
-    protected Parcelable onSaveInstanceState() {
-        // TODO(b/113884082): Decide what belongs here or what should be invalidated on
-        // configuration
-        // change
-        Bundle state = new Bundle();
-        state.putParcelable(EXTRA_SUPER, super.onSaveInstanceState());
-        state.putInt(EXTRA_SCALE_TYPE, getScaleType().getId());
-        state.putFloat(EXTRA_ZOOM_RATIO, getZoomRatio());
-        state.putBoolean(EXTRA_PINCH_TO_ZOOM_ENABLED, isPinchToZoomEnabled());
-        state.putString(EXTRA_FLASH, FlashModeConverter.nameOf(getFlash()));
-        state.putLong(EXTRA_MAX_VIDEO_DURATION, getMaxVideoDuration());
-        state.putLong(EXTRA_MAX_VIDEO_SIZE, getMaxVideoSize());
-        if (getCameraLensFacing() != null) {
-            state.putString(EXTRA_CAMERA_DIRECTION,
-                    LensFacingConverter.nameOf(getCameraLensFacing()));
-        }
-        state.putInt(EXTRA_CAPTURE_MODE, getCaptureMode().getId());
-        return state;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(@Nullable Parcelable savedState) {
-        // TODO(b/113884082): Decide what belongs here or what should be invalidated on
-        // configuration
-        // change
-        if (savedState instanceof Bundle) {
-            Bundle state = (Bundle) savedState;
-            super.onRestoreInstanceState(state.getParcelable(EXTRA_SUPER));
-            setScaleType(PreviewView.ScaleType.fromId(state.getInt(EXTRA_SCALE_TYPE)));
-            setZoomRatio(state.getFloat(EXTRA_ZOOM_RATIO));
-            setPinchToZoomEnabled(state.getBoolean(EXTRA_PINCH_TO_ZOOM_ENABLED));
-            setFlash(FlashModeConverter.valueOf(state.getString(EXTRA_FLASH)));
-            setMaxVideoDuration(state.getLong(EXTRA_MAX_VIDEO_DURATION));
-            setMaxVideoSize(state.getLong(EXTRA_MAX_VIDEO_SIZE));
-            String lensFacingString = state.getString(EXTRA_CAMERA_DIRECTION);
-            setCameraLensFacing(
-                    TextUtils.isEmpty(lensFacingString)
-                            ? null
-                            : LensFacingConverter.valueOf(lensFacingString));
-            setCaptureMode(CaptureMode.fromId(state.getInt(EXTRA_CAPTURE_MODE)));
-        } else {
-            super.onRestoreInstanceState(savedState);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        DisplayManager dpyMgr =
-                (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
-        dpyMgr.registerDisplayListener(mDisplayListener, new Handler(Looper.getMainLooper()));
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        DisplayManager dpyMgr =
-                (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
-        dpyMgr.unregisterDisplayListener(mDisplayListener);
-    }
-
-    /**
-     * Gets the {@link LiveData} of the underlying {@link PreviewView}'s
-     * {@link PreviewView.StreamState}.
-     *
-     * @return A {@link LiveData} containing the {@link PreviewView.StreamState}. Apps can either
-     * get current value by {@link LiveData#getValue()} or register a observer by
-     * {@link LiveData#observe}.
-     * @see PreviewView#getPreviewStreamState()
-     */
-    @NonNull
-    public LiveData<PreviewView.StreamState> getPreviewStreamState() {
-        return mPreviewView.getPreviewStreamState();
-    }
-
-    @NonNull
-    PreviewView getPreviewView() {
-        return mPreviewView;
-    }
-
-    // TODO(b/124269166): Rethink how we can handle permissions here.
-    @SuppressLint("MissingPermission")
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Since bindToLifecycle will depend on the measured dimension, only call it when measured
-        // dimension is not 0x0
-        if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
-            mCameraModule.bindToLifecycleAfterViewMeasured();
-        }
-
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    // TODO(b/124269166): Rethink how we can handle permissions here.
-    @SuppressLint("MissingPermission")
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        // In case that the CameraView size is always set as 0x0, we still need to trigger to force
-        // binding to lifecycle
-        mCameraModule.bindToLifecycleAfterViewMeasured();
-
-        mCameraModule.invalidateView();
-        super.onLayout(changed, left, top, right, bottom);
-    }
-
-    /**
-     * @return One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90}, {@link
-     * Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
-     */
-    int getDisplaySurfaceRotation() {
-        Display display = getDisplay();
-
-        // Null when the View is detached. If we were in the middle of a background operation,
-        // better to not NPE. When the background operation finishes, it'll realize that the camera
-        // was closed.
-        if (display == null) {
-            return 0;
-        }
-
-        return display.getRotation();
-    }
-
-    /**
-     * Returns the scale type used to scale the preview.
-     *
-     * @return The current {@link PreviewView.ScaleType}.
-     */
-    @NonNull
-    public PreviewView.ScaleType getScaleType() {
-        return mPreviewView.getScaleType();
-    }
-
-    /**
-     * Sets the view finder scale type.
-     *
-     * <p>This controls how the view finder should be scaled and positioned within the view.
-     *
-     * @param scaleType The desired {@link PreviewView.ScaleType}.
-     */
-    public void setScaleType(@NonNull PreviewView.ScaleType scaleType) {
-        mPreviewView.setScaleType(scaleType);
-    }
-
-    /**
-     * Returns the scale type used to scale the preview.
-     *
-     * @return The current {@link CaptureMode}.
-     */
-    @NonNull
-    public CaptureMode getCaptureMode() {
-        return mCameraModule.getCaptureMode();
-    }
-
-    /**
-     * Sets the CameraView capture mode
-     *
-     * <p>This controls only image or video capture function is enabled or both are enabled.
-     *
-     * @param captureMode The desired {@link CaptureMode}.
-     */
-    public void setCaptureMode(@NonNull CaptureMode captureMode) {
-        mCameraModule.setCaptureMode(captureMode);
-    }
-
-    /**
-     * Returns the maximum duration of videos, or {@link #INDEFINITE_VIDEO_DURATION} if there is no
-     * timeout.
-     *
-     * @hide Not currently implemented.
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public long getMaxVideoDuration() {
-        return mCameraModule.getMaxVideoDuration();
-    }
-
-    /**
-     * Sets the maximum video duration before
-     * {@link OnVideoSavedCallback#onVideoSaved(OutputFileResults)} is called
-     * automatically.
-     * Use {@link #INDEFINITE_VIDEO_DURATION} to disable the timeout.
-     */
-    private void setMaxVideoDuration(long duration) {
-        mCameraModule.setMaxVideoDuration(duration);
-    }
-
-    /**
-     * Returns the maximum size of videos in bytes, or {@link #INDEFINITE_VIDEO_SIZE} if there is no
-     * timeout.
-     */
-    private long getMaxVideoSize() {
-        return mCameraModule.getMaxVideoSize();
-    }
-
-    /**
-     * Sets the maximum video size in bytes before
-     * {@link OnVideoSavedCallback#onVideoSaved(OutputFileResults)}
-     * is called automatically. Use {@link #INDEFINITE_VIDEO_SIZE} to disable the size restriction.
-     */
-    private void setMaxVideoSize(long size) {
-        mCameraModule.setMaxVideoSize(size);
-    }
-
-    /**
-     * Takes a picture, and calls {@link OnImageCapturedCallback#onCaptureSuccess(ImageProxy)}
-     * once when done.
-     *
-     * @param executor The executor in which the callback methods will be run.
-     * @param callback Callback which will receive success or failure callbacks.
-     */
-    public void takePicture(@NonNull Executor executor, @NonNull OnImageCapturedCallback callback) {
-        mCameraModule.takePicture(executor, callback);
-    }
-
-    /**
-     * Takes a picture and calls
-     * {@link OnImageSavedCallback#onImageSaved(ImageCapture.OutputFileResults)} when done.
-     *
-     * <p> The value of {@link ImageCapture.Metadata#isReversedHorizontal()} in the
-     * {@link ImageCapture.OutputFileOptions} will be overwritten based on camera direction. For
-     * front camera, it will be set to true; for back camera, it will be set to false.
-     *
-     * @param outputFileOptions Options to store the newly captured image.
-     * @param executor          The executor in which the callback methods will be run.
-     * @param callback          Callback which will receive success or failure.
-     */
-    public void takePicture(@NonNull ImageCapture.OutputFileOptions outputFileOptions,
-            @NonNull Executor executor,
-            @NonNull OnImageSavedCallback callback) {
-        mCameraModule.takePicture(outputFileOptions, executor, callback);
-    }
-
-    /**
-     * Takes a video and calls the OnVideoSavedCallback when done.
-     *
-     * @param file     The destination.
-     * @param executor The executor in which the callback methods will be run.
-     * @param callback Callback which will receive success or failure.
-     */
-    @ExperimentalVideo
-    public void startRecording(@NonNull File file, @NonNull Executor executor,
-            @NonNull OnVideoSavedCallback callback) {
-        OutputFileOptions options = OutputFileOptions.builder(file).build();
-        startRecording(options, executor, callback);
-    }
-
-    /**
-     * Takes a video and calls the OnVideoSavedCallback when done.
-     *
-     * @param fd       The destination {@link ParcelFileDescriptor}.
-     * @param executor The executor in which the callback methods will be run.
-     * @param callback Callback which will receive success or failure.
-     */
-    @ExperimentalVideo
-    public void startRecording(@NonNull ParcelFileDescriptor fd, @NonNull Executor executor,
-            @NonNull OnVideoSavedCallback callback) {
-        OutputFileOptions options = OutputFileOptions.builder(fd).build();
-        startRecording(options, executor, callback);
-    }
-
-    /**
-     * Takes a video and calls the OnVideoSavedCallback when done.
-     *
-     * @param outputFileOptions Options to store the newly captured video.
-     * @param executor          The executor in which the callback methods will be run.
-     * @param callback          Callback which will receive success or failure.
-     */
-    @ExperimentalVideo
-    public void startRecording(@NonNull OutputFileOptions outputFileOptions,
-            @NonNull Executor executor,
-            @NonNull OnVideoSavedCallback callback) {
-        VideoCapture.OnVideoSavedCallback callbackWrapper =
-                new VideoCapture.OnVideoSavedCallback() {
-                    @Override
-                    public void onVideoSaved(
-                            @NonNull VideoCapture.OutputFileResults outputFileResults) {
-                        callback.onVideoSaved(
-                                OutputFileResults.create(outputFileResults.getSavedUri()));
-                    }
-
-                    @Override
-                    public void onError(int videoCaptureError, @NonNull String message,
-                            @Nullable Throwable cause) {
-                        callback.onError(videoCaptureError, message, cause);
-                    }
-                };
-
-        mCameraModule.startRecording(outputFileOptions.toVideoCaptureOutputFileOptions(), executor,
-                callbackWrapper);
-    }
-
-    /** Stops an in progress video. */
-    @ExperimentalVideo
-    public void stopRecording() {
-        mCameraModule.stopRecording();
-    }
-
-    /** @return True if currently recording. */
-    @ExperimentalVideo
-    public boolean isRecording() {
-        return mCameraModule.isRecording();
-    }
-
-    /**
-     * Queries whether the current device has a camera with the specified direction.
-     *
-     * @return True if the device supports the direction.
-     * @throws IllegalStateException if the CAMERA permission is not currently granted.
-     */
-    @RequiresPermission(permission.CAMERA)
-    public boolean hasCameraWithLensFacing(@CameraSelector.LensFacing int lensFacing) {
-        return mCameraModule.hasCameraWithLensFacing(lensFacing);
-    }
-
-    /**
-     * Toggles between the primary front facing camera and the primary back facing camera.
-     *
-     * <p>This will have no effect if not already bound to a lifecycle via {@link
-     * #bindToLifecycle(LifecycleOwner)}.
-     */
-    public void toggleCamera() {
-        mCameraModule.toggleCamera();
-    }
-
-    /**
-     * Sets the desired camera by specifying desired lensFacing.
-     *
-     * <p>This will choose the primary camera with the specified camera lensFacing.
-     *
-     * <p>If called before {@link #bindToLifecycle(LifecycleOwner)}, this will set the camera to be
-     * used when first bound to the lifecycle. If the specified lensFacing is not supported by the
-     * device, as determined by {@link #hasCameraWithLensFacing(int)}, the first supported
-     * lensFacing will be chosen when {@link #bindToLifecycle(LifecycleOwner)} is called.
-     *
-     * <p>If called with {@code null} AFTER binding to the lifecycle, the behavior would be
-     * equivalent to unbind the use cases without the lifecycle having to be destroyed.
-     *
-     * @param lensFacing The desired camera lensFacing.
-     */
-    public void setCameraLensFacing(@Nullable Integer lensFacing) {
-        mCameraModule.setCameraLensFacing(lensFacing);
-    }
-
-    /** Returns the currently selected lensFacing. */
-    @Nullable
-    public Integer getCameraLensFacing() {
-        return mCameraModule.getLensFacing();
-    }
-
-    /** Gets the active flash strategy. */
-    @ImageCapture.FlashMode
-    public int getFlash() {
-        return mCameraModule.getFlash();
-    }
-
-    /** Sets the active flash strategy. */
-    public void setFlash(@ImageCapture.FlashMode int flashMode) {
-        mCameraModule.setFlash(flashMode);
-    }
-
-    private long delta() {
-        return System.currentTimeMillis() - mDownEventTimestamp;
-    }
-
-    @Override
-    public boolean onTouchEvent(@NonNull MotionEvent event) {
-        // Disable pinch-to-zoom and tap-to-focus while the camera module is paused.
-        if (mCameraModule.isPaused()) {
-            return false;
-        }
-        // Only forward the event to the pinch-to-zoom gesture detector when pinch-to-zoom is
-        // enabled.
-        if (isPinchToZoomEnabled()) {
-            mPinchToZoomGestureDetector.onTouchEvent(event);
-        }
-        if (event.getPointerCount() == 2 && isPinchToZoomEnabled() && isZoomSupported()) {
-            return true;
-        }
-
-        // Camera focus
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mDownEventTimestamp = System.currentTimeMillis();
-                break;
-            case MotionEvent.ACTION_UP:
-                if (delta() < ViewConfiguration.getLongPressTimeout()
-                        && mCameraModule.isBoundToLifecycle()) {
-                    mUpEvent = event;
-                    performClick();
-                }
-                break;
-            default:
-                // Unhandled event.
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Focus the position of the touch event, or focus the center of the preview for
-     * accessibility events
-     */
-    @Override
-    public boolean performClick() {
-        super.performClick();
-
-        final float x = (mUpEvent != null) ? mUpEvent.getX() : getX() + getWidth() / 2f;
-        final float y = (mUpEvent != null) ? mUpEvent.getY() : getY() + getHeight() / 2f;
-        mUpEvent = null;
-
-        Camera camera = mCameraModule.getCamera();
-        if (camera != null) {
-            MeteringPointFactory pointFactory = mPreviewView.getMeteringPointFactory();
-            float afPointWidth = 1.0f / 6.0f;  // 1/6 total area
-            float aePointWidth = afPointWidth * 1.5f;
-            MeteringPoint afPoint = pointFactory.createPoint(x, y, afPointWidth);
-            MeteringPoint aePoint = pointFactory.createPoint(x, y, aePointWidth);
-
-            ListenableFuture<FocusMeteringResult> future =
-                    camera.getCameraControl().startFocusAndMetering(
-                            new FocusMeteringAction.Builder(afPoint,
-                                    FocusMeteringAction.FLAG_AF).addPoint(aePoint,
-                                    FocusMeteringAction.FLAG_AE).build());
-            Futures.addCallback(future, new FutureCallback<FocusMeteringResult>() {
-                @Override
-                public void onSuccess(@Nullable FocusMeteringResult result) {
-                }
-
-                @Override
-                public void onFailure(Throwable t) {
-                    // Throw the unexpected error.
-                    throw new RuntimeException(t);
-                }
-            }, CameraXExecutors.directExecutor());
-
-        } else {
-            Logger.d(TAG, "cannot access camera");
-        }
-
-        return true;
-    }
-
-    float rangeLimit(float val, float max, float min) {
-        return Math.min(Math.max(val, min), max);
-    }
-
-    /**
-     * Returns whether the view allows pinch-to-zoom.
-     *
-     * @return True if pinch to zoom is enabled.
-     */
-    public boolean isPinchToZoomEnabled() {
-        return mIsPinchToZoomEnabled;
-    }
-
-    /**
-     * Sets whether the view should allow pinch-to-zoom.
-     *
-     * <p>When enabled, the user can pinch the camera to zoom in/out. This only has an effect if the
-     * bound camera supports zoom.
-     *
-     * @param enabled True to enable pinch-to-zoom.
-     */
-    public void setPinchToZoomEnabled(boolean enabled) {
-        mIsPinchToZoomEnabled = enabled;
-    }
-
-    /**
-     * Returns the current zoom ratio.
-     *
-     * @return The current zoom ratio.
-     */
-    public float getZoomRatio() {
-        return mCameraModule.getZoomRatio();
-    }
-
-    /**
-     * Sets the current zoom ratio.
-     *
-     * <p>Valid zoom values range from {@link #getMinZoomRatio()} to {@link #getMaxZoomRatio()}.
-     *
-     * @param zoomRatio The requested zoom ratio.
-     */
-    public void setZoomRatio(float zoomRatio) {
-        mCameraModule.setZoomRatio(zoomRatio);
-    }
-
-    /**
-     * Returns the minimum zoom ratio.
-     *
-     * <p>For most cameras this should return a zoom ratio of 1. A zoom ratio of 1 corresponds to a
-     * non-zoomed image.
-     *
-     * @return The minimum zoom ratio.
-     */
-    public float getMinZoomRatio() {
-        return mCameraModule.getMinZoomRatio();
-    }
-
-    /**
-     * Returns the maximum zoom ratio.
-     *
-     * <p>The zoom ratio corresponds to the ratio between both the widths and heights of a
-     * non-zoomed image and a maximally zoomed image for the selected camera.
-     *
-     * @return The maximum zoom ratio.
-     */
-    public float getMaxZoomRatio() {
-        return mCameraModule.getMaxZoomRatio();
-    }
-
-    /**
-     * Returns whether the bound camera supports zooming.
-     *
-     * @return True if the camera supports zooming.
-     */
-    public boolean isZoomSupported() {
-        return mCameraModule.isZoomSupported();
-    }
-
-    /**
-     * Turns on/off torch.
-     *
-     * @param torch True to turn on torch, false to turn off torch.
-     */
-    public void enableTorch(boolean torch) {
-        mCameraModule.enableTorch(torch);
-    }
-
-    /**
-     * Returns current torch status.
-     *
-     * @return true if torch is on , otherwise false
-     */
-    public boolean isTorchOn() {
-        return mCameraModule.isTorchOn();
-    }
-
-    /**
-     * The capture mode used by CameraView.
-     *
-     * <p>This enum can be used to determine which capture mode will be enabled for {@link
-     * CameraView}.
-     */
-    public enum CaptureMode {
-        /** A mode where image capture is enabled. */
-        IMAGE(0),
-        /** A mode where video capture is enabled. */
-        @ExperimentalVideo
-        VIDEO(1),
-        /**
-         * A mode where both image capture and video capture are simultaneously enabled. Note that
-         * this mode may not be available on every device.
-         */
-        @ExperimentalVideo
-        MIXED(2);
-
-        private final int mId;
-
-        int getId() {
-            return mId;
-        }
-
-        CaptureMode(int id) {
-            mId = id;
-        }
-
-        static CaptureMode fromId(int id) {
-            for (CaptureMode f : values()) {
-                if (f.mId == id) {
-                    return f;
-                }
-            }
-            throw new IllegalArgumentException();
-        }
-    }
-
-    static class S extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        private ScaleGestureDetector.OnScaleGestureListener mListener;
-
-        void setRealGestureDetector(ScaleGestureDetector.OnScaleGestureListener l) {
-            mListener = l;
-        }
-
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            return mListener.onScale(detector);
-        }
-    }
-
-    private class PinchToZoomGestureDetector extends ScaleGestureDetector
-            implements ScaleGestureDetector.OnScaleGestureListener {
-        PinchToZoomGestureDetector(Context context) {
-            this(context, new S());
-        }
-
-        PinchToZoomGestureDetector(Context context, S s) {
-            super(context, s);
-            s.setRealGestureDetector(this);
-        }
-
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            float scale = detector.getScaleFactor();
-
-            // Speeding up the zoom by 2X.
-            if (scale > 1f) {
-                scale = 1.0f + (scale - 1.0f) * 2;
-            } else {
-                scale = 1.0f - (1.0f - scale) * 2;
-            }
-
-            float newRatio = getZoomRatio() * scale;
-            newRatio = rangeLimit(newRatio, getMaxZoomRatio(), getMinZoomRatio());
-            setZoomRatio(newRatio);
-            return true;
-        }
-
-        @Override
-        public boolean onScaleBegin(ScaleGestureDetector detector) {
-            return true;
-        }
-
-        @Override
-        public void onScaleEnd(ScaleGestureDetector detector) {
-        }
-    }
-}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
deleted file mode 100644
index c1ad936..0000000
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright (C) 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.camera.view;
-
-import static androidx.camera.core.ImageCapture.FLASH_MODE_OFF;
-
-import android.Manifest.permission;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.util.Rational;
-import android.util.Size;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
-import androidx.annotation.RequiresPermission;
-import androidx.camera.core.AspectRatio;
-import androidx.camera.core.Camera;
-import androidx.camera.core.CameraInfoUnavailableException;
-import androidx.camera.core.CameraSelector;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.ImageCapture.OnImageCapturedCallback;
-import androidx.camera.core.ImageCapture.OnImageSavedCallback;
-import androidx.camera.core.Logger;
-import androidx.camera.core.Preview;
-import androidx.camera.core.TorchState;
-import androidx.camera.core.UseCase;
-import androidx.camera.core.VideoCapture;
-import androidx.camera.core.VideoCapture.OnVideoSavedCallback;
-import androidx.camera.core.impl.LensFacingConverter;
-import androidx.camera.core.impl.utils.CameraOrientationUtil;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.core.impl.utils.futures.FutureCallback;
-import androidx.camera.core.impl.utils.futures.Futures;
-import androidx.camera.lifecycle.ProcessCameraProvider;
-import androidx.camera.view.video.ExperimentalVideo;
-import androidx.core.util.Preconditions;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.OnLifecycleEvent;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * CameraX use case operation built on @{link androidx.camera.core}.
- *
- * @deprecated Use {@link LifecycleCameraController}. See
- * <a href="https://medium.com/androiddevelopers/camerax-learn-how-to-use-cameracontroller
- * -e3ed10fffecf">migration guide</a>.
- */
-@Deprecated
-final class CameraXModule {
-    public static final String TAG = "CameraXModule";
-
-    private static final float UNITY_ZOOM_SCALE = 1f;
-    private static final float ZOOM_NOT_SUPPORTED = UNITY_ZOOM_SCALE;
-    private static final Rational ASPECT_RATIO_16_9 = new Rational(16, 9);
-    private static final Rational ASPECT_RATIO_4_3 = new Rational(4, 3);
-    private static final Rational ASPECT_RATIO_9_16 = new Rational(9, 16);
-    private static final Rational ASPECT_RATIO_3_4 = new Rational(3, 4);
-
-    private final Preview.Builder mPreviewBuilder;
-    private final VideoCapture.Builder mVideoCaptureBuilder;
-    private final ImageCapture.Builder mImageCaptureBuilder;
-    private final CameraView mCameraView;
-    final AtomicBoolean mVideoIsRecording = new AtomicBoolean(false);
-    private CameraView.CaptureMode mCaptureMode = CameraView.CaptureMode.IMAGE;
-    private long mMaxVideoDuration = CameraView.INDEFINITE_VIDEO_DURATION;
-    private long mMaxVideoSize = CameraView.INDEFINITE_VIDEO_SIZE;
-    @ImageCapture.FlashMode
-    private int mFlash = FLASH_MODE_OFF;
-    @Nullable
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    Camera mCamera;
-    @Nullable
-    private ImageCapture mImageCapture;
-    @Nullable
-    private VideoCapture mVideoCapture;
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @Nullable
-    Preview mPreview;
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @Nullable
-    LifecycleOwner mCurrentLifecycle;
-    private final LifecycleObserver mCurrentLifecycleObserver =
-            new LifecycleObserver() {
-                @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-                public void onDestroy(LifecycleOwner owner) {
-                    if (owner == mCurrentLifecycle) {
-                        clearCurrentLifecycle();
-                    }
-                }
-            };
-    @Nullable
-    private LifecycleOwner mNewLifecycle;
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @Nullable
-    Integer mCameraLensFacing = CameraSelector.LENS_FACING_BACK;
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @Nullable
-    ProcessCameraProvider mCameraProvider;
-
-    CameraXModule(CameraView view) {
-        mCameraView = view;
-
-        Futures.addCallback(ProcessCameraProvider.getInstance(view.getContext()),
-                new FutureCallback<ProcessCameraProvider>() {
-                    // TODO(b/124269166): Rethink how we can handle permissions here.
-                    @SuppressLint("MissingPermission")
-                    @Override
-                    public void onSuccess(@Nullable ProcessCameraProvider provider) {
-                        Preconditions.checkNotNull(provider);
-                        mCameraProvider = provider;
-                        if (mCurrentLifecycle != null) {
-                            bindToLifecycle(mCurrentLifecycle);
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Throwable t) {
-                        throw new RuntimeException("CameraX failed to initialize.", t);
-                    }
-                }, CameraXExecutors.mainThreadExecutor());
-
-        mPreviewBuilder = new Preview.Builder().setTargetName("Preview");
-
-        mImageCaptureBuilder = new ImageCapture.Builder().setTargetName("ImageCapture");
-
-        mVideoCaptureBuilder = new VideoCapture.Builder().setTargetName("VideoCapture");
-    }
-
-    @RequiresPermission(permission.CAMERA)
-    void bindToLifecycle(LifecycleOwner lifecycleOwner) {
-        mNewLifecycle = lifecycleOwner;
-
-        if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
-            bindToLifecycleAfterViewMeasured();
-        }
-    }
-
-    @OptIn(markerClass = ExperimentalVideo.class)
-    @RequiresPermission(permission.CAMERA)
-    void bindToLifecycleAfterViewMeasured() {
-        if (mNewLifecycle == null) {
-            return;
-        }
-
-        clearCurrentLifecycle();
-        if (mNewLifecycle.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
-            // Lifecycle is already in a destroyed state. Since it may have been a valid
-            // lifecycle when bound, but became destroyed while waiting for layout, treat this as
-            // a no-op now that we have cleared the previous lifecycle.
-            mNewLifecycle = null;
-            return;
-        }
-        mCurrentLifecycle = mNewLifecycle;
-        mNewLifecycle = null;
-
-        if (mCameraProvider == null) {
-            // try again once the camera provider is no longer null
-            return;
-        }
-
-        Set<Integer> available = getAvailableCameraLensFacing();
-
-        if (available.isEmpty()) {
-            Logger.w(TAG, "Unable to bindToLifeCycle since no cameras available");
-            mCameraLensFacing = null;
-        }
-
-        // Ensure the current camera exists, or default to another camera
-        if (mCameraLensFacing != null && !available.contains(mCameraLensFacing)) {
-            Logger.w(TAG, "Camera does not exist with direction " + mCameraLensFacing);
-
-            // Default to the first available camera direction
-            mCameraLensFacing = available.iterator().next();
-
-            Logger.w(TAG, "Defaulting to primary camera with direction " + mCameraLensFacing);
-        }
-
-        // Do not attempt to create use cases for a null cameraLensFacing. This could occur if
-        // the user explicitly sets the LensFacing to null, or if we determined there
-        // were no available cameras, which should be logged in the logic above.
-        if (mCameraLensFacing == null) {
-            return;
-        }
-
-        // Set the preferred aspect ratio as 4:3 if it is IMAGE only mode. Set the preferred aspect
-        // ratio as 16:9 if it is VIDEO or MIXED mode. Then, it will be WYSIWYG when the view finder
-        // is in CENTER_INSIDE mode.
-
-        boolean isDisplayPortrait = getDisplayRotationDegrees() == 0
-                || getDisplayRotationDegrees() == 180;
-
-        Rational targetAspectRatio;
-        if (getCaptureMode() == CameraView.CaptureMode.IMAGE) {
-            targetAspectRatio = isDisplayPortrait ? ASPECT_RATIO_3_4 : ASPECT_RATIO_4_3;
-        } else {
-            mImageCaptureBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-            mVideoCaptureBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-            targetAspectRatio = isDisplayPortrait ? ASPECT_RATIO_9_16 : ASPECT_RATIO_16_9;
-        }
-
-        mImageCaptureBuilder.setTargetRotation(getDisplaySurfaceRotation());
-        mImageCapture = mImageCaptureBuilder.build();
-
-        mVideoCaptureBuilder.setTargetRotation(getDisplaySurfaceRotation());
-        mVideoCapture = mVideoCaptureBuilder.build();
-
-        // Adjusts the preview resolution according to the view size and the target aspect ratio.
-        int height = (int) (getMeasuredWidth() / targetAspectRatio.floatValue());
-        mPreviewBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
-
-        mPreview = mPreviewBuilder.build();
-        mPreview.setSurfaceProvider(mCameraView.getPreviewView().getSurfaceProvider());
-
-        CameraSelector cameraSelector =
-                new CameraSelector.Builder().requireLensFacing(mCameraLensFacing).build();
-        if (getCaptureMode() == CameraView.CaptureMode.IMAGE) {
-            mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
-                    mImageCapture,
-                    mPreview);
-        } else if (getCaptureMode() == CameraView.CaptureMode.VIDEO) {
-            mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
-                    mVideoCapture,
-                    mPreview);
-        } else {
-            mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
-                    mImageCapture,
-                    mVideoCapture, mPreview);
-        }
-
-        setZoomRatio(UNITY_ZOOM_SCALE);
-        mCurrentLifecycle.getLifecycle().addObserver(mCurrentLifecycleObserver);
-        // Enable flash setting in ImageCapture after use cases are created and binded.
-        setFlash(getFlash());
-    }
-
-    public void open() {
-        throw new UnsupportedOperationException(
-                "Explicit open/close of camera not yet supported. Use bindtoLifecycle() instead.");
-    }
-
-    public void close() {
-        throw new UnsupportedOperationException(
-                "Explicit open/close of camera not yet supported. Use bindtoLifecycle() instead.");
-    }
-
-    @OptIn(markerClass = ExperimentalVideo.class)
-    public void takePicture(Executor executor, OnImageCapturedCallback callback) {
-        if (mImageCapture == null) {
-            return;
-        }
-
-        if (getCaptureMode() == CameraView.CaptureMode.VIDEO) {
-            throw new IllegalStateException("Can not take picture under VIDEO capture mode.");
-        }
-
-        if (callback == null) {
-            throw new IllegalArgumentException("OnImageCapturedCallback should not be empty");
-        }
-
-        mImageCapture.takePicture(executor, callback);
-    }
-
-    @OptIn(markerClass = ExperimentalVideo.class)
-    public void takePicture(@NonNull ImageCapture.OutputFileOptions outputFileOptions,
-            @NonNull Executor executor, OnImageSavedCallback callback) {
-        if (mImageCapture == null) {
-            return;
-        }
-
-        if (getCaptureMode() == CameraView.CaptureMode.VIDEO) {
-            throw new IllegalStateException("Can not take picture under VIDEO capture mode.");
-        }
-
-        if (callback == null) {
-            throw new IllegalArgumentException("OnImageSavedCallback should not be empty");
-        }
-
-        outputFileOptions.getMetadata().setReversedHorizontal(mCameraLensFacing != null
-                && mCameraLensFacing == CameraSelector.LENS_FACING_FRONT);
-        mImageCapture.takePicture(outputFileOptions, executor, callback);
-    }
-
-    public void startRecording(VideoCapture.OutputFileOptions outputFileOptions,
-            Executor executor, final OnVideoSavedCallback callback) {
-        if (mVideoCapture == null) {
-            return;
-        }
-
-        if (getCaptureMode() == CameraView.CaptureMode.IMAGE) {
-            throw new IllegalStateException("Can not record video under IMAGE capture mode.");
-        }
-
-        if (callback == null) {
-            throw new IllegalArgumentException("OnVideoSavedCallback should not be empty");
-        }
-
-        mVideoIsRecording.set(true);
-        mVideoCapture.startRecording(
-                outputFileOptions,
-                executor,
-                new VideoCapture.OnVideoSavedCallback() {
-                    @Override
-                    public void onVideoSaved(
-                            @NonNull VideoCapture.OutputFileResults outputFileResults) {
-                        mVideoIsRecording.set(false);
-                        callback.onVideoSaved(outputFileResults);
-                    }
-
-                    @Override
-                    public void onError(
-                            @VideoCapture.VideoCaptureError int videoCaptureError,
-                            @NonNull String message,
-                            @Nullable Throwable cause) {
-                        mVideoIsRecording.set(false);
-                        Logger.e(TAG, message, cause);
-                        callback.onError(videoCaptureError, message, cause);
-                    }
-                });
-    }
-
-    public void stopRecording() {
-        if (mVideoCapture == null) {
-            return;
-        }
-
-        mVideoCapture.stopRecording();
-    }
-
-    public boolean isRecording() {
-        return mVideoIsRecording.get();
-    }
-
-    // TODO(b/124269166): Rethink how we can handle permissions here.
-    @SuppressLint("MissingPermission")
-    public void setCameraLensFacing(@Nullable Integer lensFacing) {
-        // Setting same lens facing is a no-op, so check for that first
-        if (!Objects.equals(mCameraLensFacing, lensFacing)) {
-            // If we're not bound to a lifecycle, just update the camera that will be opened when we
-            // attach to a lifecycle.
-            mCameraLensFacing = lensFacing;
-
-            if (mCurrentLifecycle != null) {
-                // Re-bind to lifecycle with new camera
-                bindToLifecycle(mCurrentLifecycle);
-            }
-        }
-    }
-
-    @RequiresPermission(permission.CAMERA)
-    public boolean hasCameraWithLensFacing(@CameraSelector.LensFacing int lensFacing) {
-        if (mCameraProvider == null) {
-            return false;
-        }
-        try {
-            return mCameraProvider.hasCamera(
-                    new CameraSelector.Builder().requireLensFacing(lensFacing).build());
-        } catch (CameraInfoUnavailableException e) {
-            return false;
-        }
-    }
-
-    @Nullable
-    public Integer getLensFacing() {
-        return mCameraLensFacing;
-    }
-
-    public void toggleCamera() {
-        // TODO(b/124269166): Rethink how we can handle permissions here.
-        @SuppressLint("MissingPermission")
-        Set<Integer> availableCameraLensFacing = getAvailableCameraLensFacing();
-
-        if (availableCameraLensFacing.isEmpty()) {
-            return;
-        }
-
-        if (mCameraLensFacing == null) {
-            setCameraLensFacing(availableCameraLensFacing.iterator().next());
-            return;
-        }
-
-        if (mCameraLensFacing == CameraSelector.LENS_FACING_BACK
-                && availableCameraLensFacing.contains(CameraSelector.LENS_FACING_FRONT)) {
-            setCameraLensFacing(CameraSelector.LENS_FACING_FRONT);
-            return;
-        }
-
-        if (mCameraLensFacing == CameraSelector.LENS_FACING_FRONT
-                && availableCameraLensFacing.contains(CameraSelector.LENS_FACING_BACK)) {
-            setCameraLensFacing(CameraSelector.LENS_FACING_BACK);
-            return;
-        }
-    }
-
-    public float getZoomRatio() {
-        if (mCamera != null) {
-            return mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio();
-        } else {
-            return UNITY_ZOOM_SCALE;
-        }
-    }
-
-    public void setZoomRatio(float zoomRatio) {
-        if (mCamera != null) {
-            ListenableFuture<Void> future = mCamera.getCameraControl().setZoomRatio(
-                    zoomRatio);
-            Futures.addCallback(future, new FutureCallback<Void>() {
-                @Override
-                public void onSuccess(@Nullable Void result) {
-                }
-
-                @Override
-                public void onFailure(Throwable t) {
-                    // Throw the unexpected error.
-                    throw new RuntimeException(t);
-                }
-            }, CameraXExecutors.directExecutor());
-        } else {
-            Logger.e(TAG, "Failed to set zoom ratio");
-        }
-    }
-
-    public float getMinZoomRatio() {
-        if (mCamera != null) {
-            return mCamera.getCameraInfo().getZoomState().getValue().getMinZoomRatio();
-        } else {
-            return UNITY_ZOOM_SCALE;
-        }
-    }
-
-    public float getMaxZoomRatio() {
-        if (mCamera != null) {
-            return mCamera.getCameraInfo().getZoomState().getValue().getMaxZoomRatio();
-        } else {
-            return ZOOM_NOT_SUPPORTED;
-        }
-    }
-
-    public boolean isZoomSupported() {
-        return getMaxZoomRatio() != ZOOM_NOT_SUPPORTED;
-    }
-
-    // TODO(b/124269166): Rethink how we can handle permissions here.
-    @SuppressLint("MissingPermission")
-    private void rebindToLifecycle() {
-        if (mCurrentLifecycle != null) {
-            bindToLifecycle(mCurrentLifecycle);
-        }
-    }
-
-    boolean isBoundToLifecycle() {
-        return mCamera != null;
-    }
-
-    int getRelativeCameraOrientation(boolean compensateForMirroring) {
-        int rotationDegrees = 0;
-        if (mCamera != null) {
-            rotationDegrees =
-                    mCamera.getCameraInfo().getSensorRotationDegrees(getDisplaySurfaceRotation());
-            if (compensateForMirroring) {
-                rotationDegrees = (360 - rotationDegrees) % 360;
-            }
-        }
-
-        return rotationDegrees;
-    }
-
-    public void invalidateView() {
-        updateViewInfo();
-    }
-
-    void clearCurrentLifecycle() {
-        if (mCurrentLifecycle != null && mCameraProvider != null) {
-            // Remove previous use cases
-            List<UseCase> toUnbind = new ArrayList<>();
-            if (mImageCapture != null && mCameraProvider.isBound(mImageCapture)) {
-                toUnbind.add(mImageCapture);
-            }
-            if (mVideoCapture != null && mCameraProvider.isBound(mVideoCapture)) {
-                toUnbind.add(mVideoCapture);
-            }
-            if (mPreview != null && mCameraProvider.isBound(mPreview)) {
-                toUnbind.add(mPreview);
-            }
-
-            if (!toUnbind.isEmpty()) {
-                mCameraProvider.unbind(toUnbind.toArray((new UseCase[0])));
-            }
-
-            // Remove surface provider once unbound.
-            if (mPreview != null) {
-                mPreview.setSurfaceProvider(null);
-            }
-        }
-        mCamera = null;
-        mCurrentLifecycle = null;
-    }
-
-    // Update view related information used in use cases
-    private void updateViewInfo() {
-        if (mImageCapture != null) {
-            mImageCapture.setCropAspectRatio(new Rational(getWidth(), getHeight()));
-            mImageCapture.setTargetRotation(getDisplaySurfaceRotation());
-        }
-
-        if (mVideoCapture != null) {
-            mVideoCapture.setTargetRotation(getDisplaySurfaceRotation());
-        }
-    }
-
-    @RequiresPermission(permission.CAMERA)
-    private Set<Integer> getAvailableCameraLensFacing() {
-        // Start with all camera directions
-        Set<Integer> available = new LinkedHashSet<>(Arrays.asList(LensFacingConverter.values()));
-
-        // If we're bound to a lifecycle, remove unavailable cameras
-        if (mCurrentLifecycle != null) {
-            if (!hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK)) {
-                available.remove(CameraSelector.LENS_FACING_BACK);
-            }
-
-            if (!hasCameraWithLensFacing(CameraSelector.LENS_FACING_FRONT)) {
-                available.remove(CameraSelector.LENS_FACING_FRONT);
-            }
-        }
-
-        return available;
-    }
-
-    @ImageCapture.FlashMode
-    public int getFlash() {
-        return mFlash;
-    }
-
-    public void setFlash(@ImageCapture.FlashMode int flash) {
-        this.mFlash = flash;
-
-        if (mImageCapture == null) {
-            // Do nothing if there is no imageCapture
-            return;
-        }
-
-        mImageCapture.setFlashMode(flash);
-    }
-
-    public void enableTorch(boolean torch) {
-        if (mCamera == null) {
-            return;
-        }
-        ListenableFuture<Void> future = mCamera.getCameraControl().enableTorch(torch);
-        Futures.addCallback(future, new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(@Nullable Void result) {
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                // Throw the unexpected error.
-                throw new RuntimeException(t);
-            }
-        }, CameraXExecutors.directExecutor());
-    }
-
-    public boolean isTorchOn() {
-        if (mCamera == null) {
-            return false;
-        }
-        return mCamera.getCameraInfo().getTorchState().getValue() == TorchState.ON;
-    }
-
-    public Context getContext() {
-        return mCameraView.getContext();
-    }
-
-    public int getWidth() {
-        return mCameraView.getWidth();
-    }
-
-    public int getHeight() {
-        return mCameraView.getHeight();
-    }
-
-    public int getDisplayRotationDegrees() {
-        return CameraOrientationUtil.surfaceRotationToDegrees(getDisplaySurfaceRotation());
-    }
-
-    protected int getDisplaySurfaceRotation() {
-        return mCameraView.getDisplaySurfaceRotation();
-    }
-
-    private int getMeasuredWidth() {
-        return mCameraView.getMeasuredWidth();
-    }
-
-    private int getMeasuredHeight() {
-        return mCameraView.getMeasuredHeight();
-    }
-
-    @Nullable
-    public Camera getCamera() {
-        return mCamera;
-    }
-
-    @NonNull
-    public CameraView.CaptureMode getCaptureMode() {
-        return mCaptureMode;
-    }
-
-    public void setCaptureMode(@NonNull CameraView.CaptureMode captureMode) {
-        this.mCaptureMode = captureMode;
-        rebindToLifecycle();
-    }
-
-    public long getMaxVideoDuration() {
-        return mMaxVideoDuration;
-    }
-
-    public void setMaxVideoDuration(long duration) {
-        mMaxVideoDuration = duration;
-    }
-
-    public long getMaxVideoSize() {
-        return mMaxVideoSize;
-    }
-
-    public void setMaxVideoSize(long size) {
-        mMaxVideoSize = size;
-    }
-
-    public boolean isPaused() {
-        return false;
-    }
-}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index 9459be0..89775f6 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -69,6 +69,7 @@
 import androidx.camera.view.transform.CoordinateTransform;
 import androidx.camera.view.transform.OutputTransform;
 import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
@@ -156,6 +157,7 @@
     @SuppressWarnings("WeakerAccess")
     final Preview.SurfaceProvider mSurfaceProvider = new Preview.SurfaceProvider() {
 
+        @SuppressLint("NewApi")
         @OptIn(markerClass = ExperimentalUseCaseGroup.class)
         @Override
         @AnyThread
@@ -230,10 +232,8 @@
         Threads.checkMainThread();
         final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs,
                 R.styleable.PreviewView, defStyleAttr, defStyleRes);
-        if (Build.VERSION.SDK_INT >= 29) {
-            saveAttributeDataForStyleable(context, R.styleable.PreviewView, attrs, attributes,
-                    defStyleAttr, defStyleRes);
-        }
+        ViewCompat.saveAttributeDataForStyleable(this, context, R.styleable.PreviewView, attrs,
+                attributes, defStyleAttr, defStyleRes);
 
         try {
             final int scaleTypeId = attributes.getInteger(
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
index 4110046..0d9a473 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
@@ -16,7 +16,6 @@
 
 package androidx.camera.view;
 
-import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.util.Size;
 import android.view.PixelCopy;
@@ -28,6 +27,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.UiThread;
 import androidx.camera.core.Logger;
 import androidx.camera.core.SurfaceRequest;
@@ -114,7 +114,7 @@
      * would introduced in API level 24. PreviewView doesn't currently use a SurfaceView on API
      * levels below 24.
      */
-    @TargetApi(24)
+    @RequiresApi(24)
     @Nullable
     @Override
     Bitmap getPreviewBitmap() {
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraViewFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraViewFragmentTest.kt
deleted file mode 100644
index 65a5116..0000000
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraViewFragmentTest.kt
+++ /dev/null
@@ -1,151 +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.camera.integration.view
-
-import androidx.camera.testing.CameraUtil
-import androidx.camera.testing.CoreAppTestUtil
-import androidx.camera.view.PreviewView
-import androidx.core.os.bundleOf
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.testing.FragmentScenario
-import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.asFlow
-import androidx.lifecycle.testing.TestLifecycleOwner
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.runBlocking
-import org.junit.Assume
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TestRule
-import org.junit.runner.RunWith
-
-@LargeTest
-@RunWith(AndroidJUnit4::class)
-class CameraViewFragmentTest {
-
-    @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
-
-    @get:Rule
-    val permissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(
-            android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-            android.Manifest.permission.RECORD_AUDIO
-        )
-
-    @Before
-    fun setup() {
-        Assume.assumeTrue(CameraUtil.deviceHasCamera())
-        CoreAppTestUtil.assumeCompatibleDevice()
-        // Clear the device UI and check if there is no dialog or lock screen on the top of the
-        // window before start the test.
-        CoreAppTestUtil.prepareDeviceUI(InstrumentationRegistry.getInstrumentation())
-    }
-
-    @Test
-    fun cameraView_canStream_defaultLifecycle() = runBlocking {
-        with(launchFragmentInContainer<CameraViewFragment>()) { assertStreaming() }
-    }
-
-    @Test
-    fun cameraView_canStream_withActivityLifecycle() = runBlocking {
-        with(
-            launchFragmentInContainer<CameraViewFragment>(
-                fragmentArgs = bundleOf(
-                    CameraViewFragment.ARG_LIFECYCLE_TYPE to
-                        CameraViewFragment.LIFECYCLE_TYPE_ACTIVITY
-                )
-            )
-        ) { assertStreaming() }
-    }
-
-    @Test
-    fun cameraView_canStream_withFragmentLifecycle() = runBlocking {
-        with(
-            launchFragmentInContainer<CameraViewFragment>(
-                fragmentArgs = bundleOf(
-                    CameraViewFragment.ARG_LIFECYCLE_TYPE to
-                        CameraViewFragment.LIFECYCLE_TYPE_FRAGMENT
-                )
-            )
-        ) { assertStreaming() }
-    }
-
-    @Test
-    fun cameraView_canStream_withFragmentViewLifecycle() = runBlocking {
-        with(
-            launchFragmentInContainer<CameraViewFragment>(
-                fragmentArgs = bundleOf(
-                    CameraViewFragment.ARG_LIFECYCLE_TYPE to
-                        CameraViewFragment.LIFECYCLE_TYPE_FRAGMENT_VIEW
-                )
-            )
-        ) { assertStreaming() }
-    }
-
-    @Test
-    fun cameraView_ignoresLifecycleInDestroyedState() {
-        // Since launchFragmentInContainer waits for onResume() to complete, CameraView should
-        // have measured its view and bound to the lifecycle by this time. This would crash with
-        // an IllegalArgumentException prior to applying fix for b/157949175
-        launchFragmentInContainer(
-            fragmentArgs = bundleOf(
-                CameraViewFragment.ARG_LIFECYCLE_TYPE to CameraViewFragment.LIFECYCLE_TYPE_DEBUG
-            ),
-            instantiate = {
-                CameraViewFragment().apply {
-                    setDebugLifecycleOwner(TestLifecycleOwner(Lifecycle.State.DESTROYED))
-                }
-            }
-        )
-    }
-}
-
-@Suppress("DEPRECATION")
-private suspend inline fun FragmentScenario<CameraViewFragment>.assertStreaming() {
-    val streamState = withFragment {
-        (view?.findViewById<androidx.camera.view.CameraView>(R.id.camera)?.previewStreamState)!!
-    }.asFlow().first {
-        it == PreviewView.StreamState.STREAMING
-    }
-
-    assertThat(streamState).isEqualTo(PreviewView.StreamState.STREAMING)
-}
-
-// Adapted from ActivityScenario.withActivity extension function
-private inline fun <reified F : Fragment, T : Any> FragmentScenario<F>.withFragment(
-    crossinline block: F.() -> T
-): T {
-    lateinit var value: T
-    var err: Throwable? = null
-    onFragment { fragment ->
-        try {
-            value = block(fragment)
-        } catch (t: Throwable) {
-            err = t
-        }
-    }
-    err?.let { throw it }
-    return value
-}
\ No newline at end of file
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraViewFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraViewFragment.java
deleted file mode 100644
index 6a5e574..0000000
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraViewFragment.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 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.camera.integration.view;
-
-import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.CompoundButton;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
-import androidx.camera.core.CameraSelector;
-import androidx.camera.view.CameraView;
-import androidx.camera.view.CameraView.CaptureMode;
-import androidx.camera.view.PreviewView;
-import androidx.camera.view.video.ExperimentalVideo;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.LifecycleOwner;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.Locale;
-import java.util.Objects;
-
-/** The main camera fragment. */
-public class CameraViewFragment extends Fragment {
-    private static final String TAG = "CameraViewFragment";
-
-    // Possible values for this intent key are the name values of LensFacing encoded as
-    // strings (case-insensitive): "back", "front".
-    private static final String INTENT_EXTRA_CAMERA_DIRECTION = "camera_direction";
-
-    // Possible values for this intent key are the name values of CameraView.CaptureMode encoded as
-    // strings (case-insensitive): "image", "video", "mixed"
-    private static final String INTENT_EXTRA_CAPTURE_MODE = "captureMode";
-
-    // The time-out to wait for the ready of CameraProver in the CameraXModule of CameraView.
-    private static final int CAMERA_PROVIDER_READY_TIMEOUT = 2000;
-
-    // Argument key which determines the lifecycle used to control the camera of CameraView.
-    // Possible values for this argument key are LIFECYCLE_TYPE_ACTIVITY, LIFECYCLE_TYPE_FRAGMENT,
-    // LIFECYCLE_TYPE_FRAGMENT_VIEW, LIFECYCLE_TYPE_CUSTOM. If using LIFECYCLE_TYPE_DEBUG, then
-    // a lifecycle must be provided via setDebugLifecycleOwner().
-    static final String ARG_LIFECYCLE_TYPE = "lifecycle_type";
-
-    // Fragment's Activity lifecycle
-    static final String LIFECYCLE_TYPE_ACTIVITY = "activity";
-    // Fragment lifecycle (this). This is the default lifecycle used by this fragment
-    static final String LIFECYCLE_TYPE_FRAGMENT = "fragment";
-    // Fragment's View lifecycle (getViewLifecycleOwner())
-    static final String LIFECYCLE_TYPE_FRAGMENT_VIEW = "fragment_view";
-    // Lifecycle provided by setDebugLifecycleOwner
-    static final String LIFECYCLE_TYPE_DEBUG = "debug";
-
-
-    private View mCameraHolder;
-    CameraView mCameraView;
-    private View mCaptureView;
-    private CompoundButton mModeButton;
-    @Nullable
-    private CompoundButton mToggleCameraButton;
-    private CompoundButton mToggleCropButton;
-    @Nullable
-    private LifecycleOwner mDebugLifecycleOwner;
-
-    /**
-     * Sets the debug lifecycle used by this fragment IF the fragment has argument
-     * {@link #ARG_LIFECYCLE_TYPE} set to {@link #LIFECYCLE_TYPE_DEBUG}.
-     *
-     * <p>This lifecycle must be set before the fragment lifecycle reaches
-     * {@link #onViewStateRestored(Bundle)}, or it will be ignored.
-     *
-     * <p>This value set here is not retained across fragment recreation, so it is only safe to
-     * use for debugging/testing purposes.
-     */
-    public void setDebugLifecycleOwner(@NonNull LifecycleOwner owner) {
-        mDebugLifecycleOwner = owner;
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        mCameraHolder = view.findViewById(R.id.layout_camera);
-        mCameraView = view.findViewById(R.id.camera);
-        mToggleCameraButton = view.findViewById(R.id.toggle);
-        mToggleCropButton = view.findViewById(R.id.toggle_crop);
-        mCaptureView = mCameraHolder.findViewById(R.id.capture);
-        if (mCameraHolder == null) {
-            throw new IllegalStateException("No View found with id R.id.layout_camera");
-        }
-        if (mCameraView == null) {
-            throw new IllegalStateException("No CameraView found with id R.id.camera");
-        }
-        if (mCaptureView == null) {
-            throw new IllegalStateException("No CameraView found with id R.id.capture");
-        }
-
-        mModeButton = mCameraHolder.findViewById(R.id.mode);
-
-        if (mModeButton == null) {
-            throw new IllegalStateException("No View found with id R.id.mode");
-        }
-
-        // Log the location of some views, so their locations can be used to perform some automated
-        // clicks in tests.
-        logCenterCoordinates(mCameraView, "camera_view");
-        logCenterCoordinates(mCaptureView, "capture");
-        logCenterCoordinates(mToggleCameraButton, "toggle_camera");
-        logCenterCoordinates(mToggleCropButton, "toggle_crop");
-        logCenterCoordinates(mModeButton, "mode");
-
-        // Get extra option for setting initial camera direction
-        Bundle bundle = getActivity().getIntent().getExtras();
-        if (bundle != null) {
-            final String cameraDirectionString = bundle.getString(INTENT_EXTRA_CAMERA_DIRECTION);
-            final boolean isCameraDirectionValid =
-                    cameraDirectionString != null && (cameraDirectionString.equalsIgnoreCase("BACK")
-                            || cameraDirectionString.equalsIgnoreCase("FRONT"));
-            if (isCameraDirectionValid) {
-                @CameraSelector.LensFacing int lensFacing = cameraDirectionString.equalsIgnoreCase(
-                        "BACK")
-                        ? CameraSelector.LENS_FACING_BACK : CameraSelector.LENS_FACING_FRONT;
-                mCameraView.setCameraLensFacing(lensFacing);
-            }
-
-            String captureModeString = bundle.getString(INTENT_EXTRA_CAPTURE_MODE);
-            if (captureModeString != null) {
-                CaptureMode captureMode = CaptureMode.valueOf(captureModeString.toUpperCase());
-                mCameraView.setCaptureMode(captureMode);
-            }
-        }
-    }
-
-    @Override
-    @OptIn(markerClass = ExperimentalVideo.class)
-    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
-        super.onViewStateRestored(savedInstanceState);
-
-        if (ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.CAMERA)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new IllegalStateException("App has not been granted CAMERA permission");
-        }
-
-        // Set the lifecycle that will be used to control the camera
-        Bundle args = getArguments();
-        String lifecycleType = args == null ? LIFECYCLE_TYPE_FRAGMENT :
-                args.getString(ARG_LIFECYCLE_TYPE, LIFECYCLE_TYPE_FRAGMENT);
-        Log.d(TAG, "Attempting bindToLifecycle with lifecycle type: " + lifecycleType);
-        switch (lifecycleType) {
-            case LIFECYCLE_TYPE_ACTIVITY:
-                mCameraView.bindToLifecycle(requireActivity());
-                break;
-            case LIFECYCLE_TYPE_FRAGMENT:
-                mCameraView.bindToLifecycle(CameraViewFragment.this);
-                break;
-            case LIFECYCLE_TYPE_FRAGMENT_VIEW:
-                mCameraView.bindToLifecycle(Objects.requireNonNull(getViewLifecycleOwner()));
-                break;
-            case LIFECYCLE_TYPE_DEBUG:
-                if (mDebugLifecycleOwner == null) {
-                    throw new IllegalStateException("Lifecycle type set to DEBUG, but no debug "
-                            + "lifecycle exists. setDebugLifecycleOwner() must be called before "
-                            + "onViewStateRestored()");
-                }
-                mCameraView.bindToLifecycle(mDebugLifecycleOwner);
-                break;
-            default:
-                throw new IllegalArgumentException(String.format(Locale.US, "Invalid lifecycle "
-                                + "type: %s. Valid options are %s, %s, %s, and %s.", lifecycleType,
-                        LIFECYCLE_TYPE_ACTIVITY, LIFECYCLE_TYPE_FRAGMENT,
-                        LIFECYCLE_TYPE_FRAGMENT_VIEW, LIFECYCLE_TYPE_DEBUG));
-        }
-
-        mCameraView.setPinchToZoomEnabled(true);
-        mCaptureView.setOnTouchListener(new CaptureViewOnTouchListener(mCameraView));
-
-        // Set clickable, Let the cameraView can be interacted by Voice Access
-        mCameraView.setClickable(true);
-
-        // CameraView.hasCameraWithLensFacing need to wait for the ready of CameraProvider. Check
-        // the b/183916771 for the workaround.
-        Handler handler = new Handler(Looper.getMainLooper());
-        handler.postDelayed(() -> {
-            if (mToggleCameraButton != null) {
-                if (mToggleCameraButton != null) {
-                    mToggleCameraButton.setVisibility(
-                            (mCameraView.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK)
-                                    && mCameraView.hasCameraWithLensFacing(
-                                    CameraSelector.LENS_FACING_FRONT))
-                                    ? View.VISIBLE
-                                    : View.INVISIBLE);
-                    mToggleCameraButton.setChecked(
-                            mCameraView.getCameraLensFacing() == CameraSelector.LENS_FACING_FRONT);
-                }
-            }
-        }, CAMERA_PROVIDER_READY_TIMEOUT);
-
-        // Set listeners here, or else restoring state will trigger them.
-        if (mToggleCameraButton != null) {
-            mToggleCameraButton.setOnCheckedChangeListener(
-                    new CompoundButton.OnCheckedChangeListener() {
-                        @Override
-                        public void onCheckedChanged(CompoundButton b, boolean checked) {
-                            mCameraView.setCameraLensFacing(
-                                    checked ? CameraSelector.LENS_FACING_FRONT
-                                            : CameraSelector.LENS_FACING_BACK);
-                        }
-                    });
-        }
-
-        mToggleCropButton.setChecked(
-                mCameraView.getScaleType() == PreviewView.ScaleType.FILL_CENTER);
-        mToggleCropButton.setOnCheckedChangeListener((b, checked) -> {
-            if (checked) {
-                mCameraView.setScaleType(PreviewView.ScaleType.FILL_CENTER);
-            } else {
-                mCameraView.setScaleType(PreviewView.ScaleType.FIT_CENTER);
-            }
-        });
-
-        if (mModeButton != null) {
-            updateModeButtonIcon();
-
-            mModeButton.setOnClickListener(
-                    new View.OnClickListener() {
-                        @Override
-                        public void onClick(View view) {
-                            if (mCameraView.isRecording()) {
-                                Toast.makeText(
-                                        CameraViewFragment.this.getContext(),
-                                        "Can not switch mode during video recording.",
-                                        Toast.LENGTH_SHORT)
-                                        .show();
-                                return;
-                            }
-
-                            if (mCameraView.getCaptureMode() == CaptureMode.MIXED) {
-                                mCameraView.setCaptureMode(CaptureMode.IMAGE);
-                            } else if (mCameraView.getCaptureMode() == CaptureMode.IMAGE) {
-                                mCameraView.setCaptureMode(CaptureMode.VIDEO);
-                            } else {
-                                mCameraView.setCaptureMode(CaptureMode.MIXED);
-                            }
-
-                            CameraViewFragment.this.updateModeButtonIcon();
-                        }
-                    });
-        }
-    }
-
-    @OptIn(markerClass = ExperimentalVideo.class)
-    void updateModeButtonIcon() {
-        if (mCameraView.getCaptureMode() == CaptureMode.MIXED) {
-            mModeButton.setButtonDrawable(R.drawable.ic_photo_camera);
-        } else if (mCameraView.getCaptureMode() == CaptureMode.IMAGE) {
-            mModeButton.setButtonDrawable(R.drawable.ic_camera);
-        } else {
-            mModeButton.setButtonDrawable(R.drawable.ic_videocam);
-        }
-    }
-
-    @Override
-    @NonNull
-    public View onCreateView(
-            @NonNull LayoutInflater inflater,
-            @Nullable ViewGroup container,
-            @Nullable Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.fragment_main, container, false);
-    }
-
-    private void logCenterCoordinates(View view, String name) {
-        view.getViewTreeObserver()
-                .addOnGlobalLayoutListener(
-                        new ViewTreeObserver.OnGlobalLayoutListener() {
-                            @Override
-                            public void onGlobalLayout() {
-                                Activity activity = getActivity();
-                                if (activity == null) {
-                                    // The fragment has been detached from the parent Activity.
-                                    return;
-                                }
-                                Rect rect = new Rect();
-                                view.getGlobalVisibleRect(rect);
-                                Log.d(
-                                        TAG,
-                                        "View "
-                                                + name
-                                                + " Center "
-                                                + rect.centerX()
-                                                + " "
-                                                + rect.centerY());
-                                File externalDir = activity.getExternalFilesDir(null);
-                                File logFile =
-                                        new File(externalDir, name + "_button_coordinates.txt");
-                                try (PrintStream stream = new PrintStream(logFile)) {
-                                    stream.print(rect.centerX() + " " + rect.centerY());
-                                } catch (IOException e) {
-                                    Log.e(TAG, "Could not save to " + logFile, e);
-                                }
-                            }
-                        });
-    }
-}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CaptureViewOnTouchListener.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CaptureViewOnTouchListener.java
deleted file mode 100644
index 0f08848..0000000
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CaptureViewOnTouchListener.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 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.camera.integration.view;
-
-import android.content.ContentValues;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.ImageCapture.OnImageSavedCallback;
-import androidx.camera.core.ImageCaptureException;
-import androidx.camera.view.CameraView;
-import androidx.camera.view.CameraView.CaptureMode;
-import androidx.camera.view.video.ExperimentalVideo;
-import androidx.camera.view.video.OnVideoSavedCallback;
-import androidx.camera.view.video.OutputFileResults;
-import androidx.core.content.ContextCompat;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-/**
- * A {@link View.OnTouchListener} which converts a view's touches into camera actions.
- *
- * <p>The listener converts touches on a {@link View}, such as a button, into appropriate photo
- * taking or video recording actions through a {@link CameraView}. A click is interpreted as a
- * take-photo signal, while a long-press is interpreted as a record-video signal.
- */
-class CaptureViewOnTouchListener implements View.OnTouchListener {
-    private static final String TAG = "ViewOnTouchListener";
-
-    private static final String FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS";
-    private static final String PHOTO_EXTENSION = ".jpg";
-    private static final String VIDEO_EXTENSION = ".mp4";
-
-    private static final int TAP = 1;
-    private static final int HOLD = 2;
-    private static final int RELEASE = 3;
-
-    private final long mLongPress = ViewConfiguration.getLongPressTimeout();
-    private final CameraView mCameraView;
-
-    // TODO: Use a Handler for a background thread, rather than running on the current (main)
-    // thread.
-    private final Handler mHandler =
-            new Handler() {
-                @Override
-                public void handleMessage(Message msg) {
-                    switch (msg.what) {
-                        case TAP:
-                            onTap();
-                            break;
-                        case HOLD:
-                            onHold();
-                            if (mCameraView.getMaxVideoDuration() > 0) {
-                                sendEmptyMessageDelayed(RELEASE, mCameraView.getMaxVideoDuration());
-                            }
-                            break;
-                        case RELEASE:
-                            onRelease();
-                            break;
-                        default:
-                            // No op
-                    }
-                }
-            };
-
-    private long mDownEventTimestamp;
-    private Rect mViewBoundsRect;
-
-    /** Creates a new listener which links to the given {@link CameraView}. */
-    CaptureViewOnTouchListener(CameraView cameraView) {
-        mCameraView = cameraView;
-    }
-
-    /** Called when the user taps. */
-    @OptIn(markerClass = ExperimentalVideo.class)
-    private void onTap() {
-        if (mCameraView.getCaptureMode() == CaptureMode.IMAGE
-                || mCameraView.getCaptureMode() == CaptureMode.MIXED) {
-
-            File saveFile = createNewFile(PHOTO_EXTENSION);
-            ImageCapture.OutputFileOptions outputFileOptions;
-            ContentValues contentValues = new ContentValues();
-            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, saveFile.getName());
-            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
-                        Environment.DIRECTORY_PICTURES);
-            } else {
-                contentValues.put(MediaStore.MediaColumns.DATA, saveFile.getAbsolutePath());
-            }
-            outputFileOptions = new ImageCapture.OutputFileOptions.Builder(
-                    mCameraView.getContext().getContentResolver(),
-                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                    contentValues).build();
-
-            mCameraView.takePicture(outputFileOptions,
-                    ContextCompat.getMainExecutor(mCameraView.getContext()),
-                    new OnImageSavedCallback() {
-                        @Override
-                        public void onImageSaved(
-                                @NonNull ImageCapture.OutputFileResults outputFileResults) {
-                            report("Picture saved to " + saveFile.getAbsolutePath());
-                            // Print out metadata about the picture
-                            // TODO: Print out metadata to log once metadata is implemented
-                        }
-
-                        @Override
-                        public void onError(@NonNull ImageCaptureException exception) {
-                            report("Failure: " + exception.getMessage(), exception.getCause());
-                        }
-                    });
-        }
-    }
-
-    /** Called when the user holds (long presses). */
-    @OptIn(markerClass = ExperimentalVideo.class)
-    private void onHold() {
-        if (mCameraView.getCaptureMode() == CaptureMode.VIDEO
-                || mCameraView.getCaptureMode() == CaptureMode.MIXED) {
-
-            final File saveFile = createNewFile(VIDEO_EXTENSION);
-            mCameraView.startRecording(saveFile,
-                    ContextCompat.getMainExecutor(mCameraView.getContext()),
-                    new OnVideoSavedCallback() {
-                        @Override
-                        public void onVideoSaved(
-                                @NonNull OutputFileResults outputFileResults) {
-                            report("Video saved to " + outputFileResults.getSavedUri());
-                        }
-
-                        @Override
-                        public void onError(int videoCaptureError, @NonNull String message,
-                                @Nullable Throwable cause) {
-                            report("Failure: " + message, cause);
-                        }
-                    });
-        }
-    }
-
-    /** Called when the user releases. */
-    @OptIn(markerClass = ExperimentalVideo.class)
-    private void onRelease() {
-        if (mCameraView.getCaptureMode() == CaptureMode.VIDEO
-                || mCameraView.getCaptureMode() == CaptureMode.MIXED) {
-            mCameraView.stopRecording();
-        }
-    }
-
-    @Override
-    public boolean onTouch(View view, MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mDownEventTimestamp = System.currentTimeMillis();
-                mViewBoundsRect =
-                        new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-                mHandler.sendEmptyMessageDelayed(HOLD, mLongPress);
-                view.setPressed(true);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                // If the user moves their finger off the button, trigger RELEASE
-                if (mViewBoundsRect.contains(
-                        view.getLeft() + (int) event.getX(), view.getTop() + (int) event.getY())) {
-                    break;
-                }
-                // Fall-through
-            case MotionEvent.ACTION_CANCEL:
-                clearHandler();
-                if (deltaSinceDownEvent() > mLongPress
-                        && (mCameraView.getMaxVideoDuration() <= 0
-                        || deltaSinceDownEvent() < mCameraView.getMaxVideoDuration())) {
-                    mHandler.sendEmptyMessage(RELEASE);
-                }
-                view.setPressed(false);
-                break;
-            case MotionEvent.ACTION_UP:
-                clearHandler();
-                if (deltaSinceDownEvent() < mLongPress) {
-                    mHandler.sendEmptyMessage(TAP);
-                } else if ((mCameraView.getMaxVideoDuration() <= 0
-                        || deltaSinceDownEvent() < mCameraView.getMaxVideoDuration())) {
-                    mHandler.sendEmptyMessage(RELEASE);
-                }
-                view.setPressed(false);
-                break;
-            default:
-                // No op
-        }
-        return true;
-    }
-
-    private long deltaSinceDownEvent() {
-        return System.currentTimeMillis() - mDownEventTimestamp;
-    }
-
-    private void clearHandler() {
-        mHandler.removeMessages(TAP);
-        mHandler.removeMessages(HOLD);
-        mHandler.removeMessages(RELEASE);
-    }
-
-    private File createNewFile(String extension) {
-        File dirFile =
-                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
-        if (dirFile != null && !dirFile.exists()) {
-            dirFile.mkdirs();
-        }
-        // Use Locale.US to ensure we get ASCII digits
-        return new File(dirFile,
-                new SimpleDateFormat(FILENAME, Locale.US).format(System.currentTimeMillis())
-                        + extension);
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    void report(@NonNull String msg) {
-        report(msg, null);
-    }
-
-    @SuppressWarnings("WeakerAccess")
-    void report(@NonNull String msg, @Nullable Throwable cause) {
-        Log.d(TAG, msg, cause);
-        Toast.makeText(mCameraView.getContext(), msg, Toast.LENGTH_SHORT).show();
-    }
-}
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
index 504277c..411ec1f 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/MainActivity.java
@@ -54,7 +54,7 @@
     private static final int REQUEST_CODE_PERMISSIONS = 10;
 
     private boolean mCheckedPermissions = false;
-    private Mode mMode = Mode.CAMERA_VIEW;
+    private Mode mMode = Mode.CAMERA_CONTROLLER;
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -114,9 +114,6 @@
     @Override
     public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         switch (item.getItemId()) {
-            case R.id.camera_view:
-                mMode = Mode.CAMERA_VIEW;
-                break;
             case R.id.preview_view:
                 mMode = Mode.PREVIEW_VIEW;
                 break;
@@ -143,9 +140,6 @@
 
     private void startFragment() {
         switch (mMode) {
-            case CAMERA_VIEW:
-                startFragment(R.string.camera_view, new CameraViewFragment());
-                break;
             case PREVIEW_VIEW:
                 startFragment(R.string.preview_view, new PreviewViewFragment());
                 break;
@@ -175,6 +169,6 @@
     }
 
     private enum Mode {
-        CAMERA_VIEW, PREVIEW_VIEW, CAMERA_CONTROLLER, TRANSFORM
+        PREVIEW_VIEW, CAMERA_CONTROLLER, TRANSFORM
     }
 }
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/fullscreen_selector.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/fullscreen_selector.xml
deleted file mode 100644
index ff39715..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/fullscreen_selector.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<selector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:drawable="@drawable/ic_fullscreen_exit" android:state_checked="true" android:state_enabled="true" />
-    <item android:drawable="@drawable/ic_fullscreen" android:state_checked="false" android:state_enabled="true" />
-</selector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_camera.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_camera.xml
deleted file mode 100644
index a35682e..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_camera.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0">
-    <path
-
-        android:fillColor="?android:attr/colorControlNormal"
-        android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z" />
-</vector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen.xml
deleted file mode 100644
index 467ce90..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0">
-    <path
-        android:fillColor="?android:attr/colorControlNormal"
-        android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z" />
-</vector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen_exit.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen_exit.xml
deleted file mode 100644
index 8ee9dfc..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_fullscreen_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0">
-    <path
-        android:fillColor="?android:attr/colorControlNormal"
-        android:pathData="M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z" />
-</vector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_photo_camera.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_photo_camera.xml
deleted file mode 100644
index 625e155..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_photo_camera.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:tint="?attr/colorControlNormal"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
-</vector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_videocam.xml b/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_videocam.xml
deleted file mode 100644
index f009891..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/drawable/ic_videocam.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:tint="?attr/colorControlNormal"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M18,10.48V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l4,3.98v-11L18,10.48zM16,9.69V18H4V6h12V9.69zM11.67,11l-2.5,3.72L7.5,12L5,16h10L11.67,11z" />
-</vector>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/fragment_main.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/fragment_main.xml
deleted file mode 100644
index 7938a58..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/layout-land/fragment_main.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:id="@+id/layout_camera"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="horizontal">
-
-        <androidx.camera.view.CameraView
-            android:id="@+id/camera"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_vertical"
-            android:layout_weight="1" />
-
-        <LinearLayout
-            android:layout_width="125dp"
-            android:layout_height="match_parent"
-            android:layout_marginBottom="10dp"
-            android:layout_marginTop="10dp"
-            android:gravity="center"
-            android:orientation="vertical">
-
-            <CheckBox
-                android:id="@+id/toggle_crop"
-                android:layout_width="wrap_content"
-                android:layout_height="50dp"
-                android:button="@drawable/fullscreen_selector" />
-
-            <CheckBox
-                android:id="@+id/mode"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:button="@drawable/ic_photo_camera" />
-
-            <Button
-                android:id="@+id/capture"
-                style="?android:buttonBarButtonStyle"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginBottom="10dp"
-                android:layout_marginTop="10dp"
-                android:layout_weight="1"
-                android:text="@string/btn_capture" />
-
-            <CheckBox
-                android:id="@+id/toggle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-</FrameLayout>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout/fragment_main.xml b/camera/integration-tests/viewtestapp/src/main/res/layout/fragment_main.xml
deleted file mode 100644
index 72f8ecb..0000000
--- a/camera/integration-tests/viewtestapp/src/main/res/layout/fragment_main.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:id="@+id/layout_camera"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-
-        <androidx.camera.view.CameraView
-            android:id="@+id/camera"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_gravity="center_horizontal"
-            android:layout_weight="1" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="58dp"
-            android:layout_marginLeft="10dp"
-            android:layout_marginRight="10dp"
-            android:gravity="center">
-
-            <CheckBox
-                android:id="@+id/toggle"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-
-            <Button
-                android:id="@+id/capture"
-                style="?android:buttonBarButtonStyle"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_marginLeft="50dp"
-                android:layout_marginRight="50dp"
-                android:layout_weight="1"
-                android:text="@string/btn_capture" />
-
-            <CheckBox
-                android:id="@+id/mode"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="15dp"
-                android:button="@drawable/ic_photo_camera" />
-
-            <CheckBox
-                android:id="@+id/toggle_crop"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:button="@drawable/fullscreen_selector" />
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-</FrameLayout>
diff --git a/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml b/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
index 8babd1e..4868f69 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/menu/actionbar_menu.xml
@@ -17,10 +17,6 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
     <item
-        android:id="@+id/camera_view"
-        android:title="@string/camera_view"
-        app:showAsAction="never" />
-    <item
         android:id="@+id/preview_view"
         android:title="@string/preview_view"
         app:showAsAction="never" />
diff --git a/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml b/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
index 0eb3bd9..e257662 100644
--- a/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
+++ b/camera/integration-tests/viewtestapp/src/main/res/values/donottranslate-strings.xml
@@ -41,7 +41,6 @@
     <string name="btn_switch">Switch</string>
     <string name="btn_confirm">Confirm</string>
     <string name="btn_cancel">Cancel</string>
-    <string name="camera_view">Camera View</string>
     <string name="preview_view">Preview View</string>
     <string name="camera_controller">Camera Controller</string>
     <string name="transform">Transform</string>
diff --git a/compose/animation/animation-core/api/public_plus_experimental_1.0.0-beta07.txt b/compose/animation/animation-core/api/public_plus_experimental_1.0.0-beta07.txt
index 67580ac..459b61a 100644
--- a/compose/animation/animation-core/api/public_plus_experimental_1.0.0-beta07.txt
+++ b/compose/animation/animation-core/api/public_plus_experimental_1.0.0-beta07.txt
@@ -272,6 +272,9 @@
     method public static androidx.compose.animation.core.Easing getLinearOutSlowInEasing();
   }
 
+  @kotlin.RequiresOptIn(message="This is an experimental animation API for Transition. It may change in the future.") public @interface ExperimentalTransitionApi {
+  }
+
   public interface FiniteAnimationSpec<T> extends androidx.compose.animation.core.AnimationSpec<T> {
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
   }
@@ -404,8 +407,10 @@
     ctor public MutableTransitionState(S? initialState);
     method public S! getCurrentState();
     method public S! getTargetState();
+    method @androidx.compose.animation.core.ExperimentalTransitionApi public boolean isIdle();
     method public void setTargetState(S! p);
     property public final S! currentState;
+    property @androidx.compose.animation.core.ExperimentalTransitionApi public final boolean isIdle;
     property public final S! targetState;
   }
 
@@ -518,6 +523,7 @@
     method @androidx.compose.runtime.Composable public static inline <S> androidx.compose.runtime.State<androidx.compose.ui.geometry.Rect> animateRect(androidx.compose.animation.core.Transition<S>, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.geometry.Rect>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,androidx.compose.ui.geometry.Rect> targetValueByState);
     method @androidx.compose.runtime.Composable public static inline <S> androidx.compose.runtime.State<androidx.compose.ui.geometry.Size> animateSize(androidx.compose.animation.core.Transition<S>, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.geometry.Size>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,androidx.compose.ui.geometry.Size> targetValueByState);
     method @androidx.compose.runtime.Composable public static inline <S, T, V extends androidx.compose.animation.core.AnimationVector> androidx.compose.runtime.State<T> animateValue(androidx.compose.animation.core.Transition<S>, androidx.compose.animation.core.TwoWayConverter<T,V> typeConverter, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<T>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,? extends T> targetValueByState);
+    method @androidx.compose.animation.core.ExperimentalTransitionApi @androidx.compose.runtime.Composable public static inline <S, T> androidx.compose.animation.core.Transition<T> createChildTransition(androidx.compose.animation.core.Transition<S>, optional String label, kotlin.jvm.functions.Function1<? super S,? extends T> transformToChildState);
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.Transition<T> updateTransition(T? targetState, optional String? label);
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.Transition<T> updateTransition(androidx.compose.animation.core.MutableTransitionState<T> transitionState, optional String? label);
   }
diff --git a/compose/animation/animation-core/api/public_plus_experimental_current.txt b/compose/animation/animation-core/api/public_plus_experimental_current.txt
index 67580ac..459b61a 100644
--- a/compose/animation/animation-core/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation-core/api/public_plus_experimental_current.txt
@@ -272,6 +272,9 @@
     method public static androidx.compose.animation.core.Easing getLinearOutSlowInEasing();
   }
 
+  @kotlin.RequiresOptIn(message="This is an experimental animation API for Transition. It may change in the future.") public @interface ExperimentalTransitionApi {
+  }
+
   public interface FiniteAnimationSpec<T> extends androidx.compose.animation.core.AnimationSpec<T> {
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedFiniteAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
   }
@@ -404,8 +407,10 @@
     ctor public MutableTransitionState(S? initialState);
     method public S! getCurrentState();
     method public S! getTargetState();
+    method @androidx.compose.animation.core.ExperimentalTransitionApi public boolean isIdle();
     method public void setTargetState(S! p);
     property public final S! currentState;
+    property @androidx.compose.animation.core.ExperimentalTransitionApi public final boolean isIdle;
     property public final S! targetState;
   }
 
@@ -518,6 +523,7 @@
     method @androidx.compose.runtime.Composable public static inline <S> androidx.compose.runtime.State<androidx.compose.ui.geometry.Rect> animateRect(androidx.compose.animation.core.Transition<S>, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.geometry.Rect>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,androidx.compose.ui.geometry.Rect> targetValueByState);
     method @androidx.compose.runtime.Composable public static inline <S> androidx.compose.runtime.State<androidx.compose.ui.geometry.Size> animateSize(androidx.compose.animation.core.Transition<S>, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.geometry.Size>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,androidx.compose.ui.geometry.Size> targetValueByState);
     method @androidx.compose.runtime.Composable public static inline <S, T, V extends androidx.compose.animation.core.AnimationVector> androidx.compose.runtime.State<T> animateValue(androidx.compose.animation.core.Transition<S>, androidx.compose.animation.core.TwoWayConverter<T,V> typeConverter, optional kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.Transition.Segment<S>,? extends androidx.compose.animation.core.FiniteAnimationSpec<T>> transitionSpec, optional String label, kotlin.jvm.functions.Function1<? super S,? extends T> targetValueByState);
+    method @androidx.compose.animation.core.ExperimentalTransitionApi @androidx.compose.runtime.Composable public static inline <S, T> androidx.compose.animation.core.Transition<T> createChildTransition(androidx.compose.animation.core.Transition<S>, optional String label, kotlin.jvm.functions.Function1<? super S,? extends T> transformToChildState);
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.Transition<T> updateTransition(T? targetState, optional String? label);
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.Transition<T> updateTransition(androidx.compose.animation.core.MutableTransitionState<T> transitionState, optional String? label);
   }
diff --git a/compose/animation/animation-core/api/restricted_1.0.0-beta07.txt b/compose/animation/animation-core/api/restricted_1.0.0-beta07.txt
index 3062208..4d76908 100644
--- a/compose/animation/animation-core/api/restricted_1.0.0-beta07.txt
+++ b/compose/animation/animation-core/api/restricted_1.0.0-beta07.txt
@@ -484,13 +484,17 @@
   }
 
   public final class Transition<S> {
+    ctor @kotlin.PublishedApi internal Transition(androidx.compose.animation.core.MutableTransitionState<S> transitionState, optional String? label);
     method @kotlin.PublishedApi internal boolean addAnimation(androidx.compose.animation.core.Transition<S>.TransitionAnimationState<?,?> animation);
+    method @kotlin.PublishedApi internal boolean addTransition(androidx.compose.animation.core.Transition<?> transition);
     method public S! getCurrentState();
     method public String? getLabel();
     method public androidx.compose.animation.core.Transition.Segment<S> getSegment();
     method public S! getTargetState();
     method public boolean isRunning();
     method @kotlin.PublishedApi internal void removeAnimation(androidx.compose.animation.core.Transition<S>.TransitionAnimationState<?,?> animation);
+    method @kotlin.PublishedApi internal boolean removeTransition(androidx.compose.animation.core.Transition<?> transition);
+    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal void updateTarget(S? targetState);
     property public final S! currentState;
     property public final boolean isRunning;
     property public final String? label;
diff --git a/compose/animation/animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
index 3062208..4d76908 100644
--- a/compose/animation/animation-core/api/restricted_current.txt
+++ b/compose/animation/animation-core/api/restricted_current.txt
@@ -484,13 +484,17 @@
   }
 
   public final class Transition<S> {
+    ctor @kotlin.PublishedApi internal Transition(androidx.compose.animation.core.MutableTransitionState<S> transitionState, optional String? label);
     method @kotlin.PublishedApi internal boolean addAnimation(androidx.compose.animation.core.Transition<S>.TransitionAnimationState<?,?> animation);
+    method @kotlin.PublishedApi internal boolean addTransition(androidx.compose.animation.core.Transition<?> transition);
     method public S! getCurrentState();
     method public String? getLabel();
     method public androidx.compose.animation.core.Transition.Segment<S> getSegment();
     method public S! getTargetState();
     method public boolean isRunning();
     method @kotlin.PublishedApi internal void removeAnimation(androidx.compose.animation.core.Transition<S>.TransitionAnimationState<?,?> animation);
+    method @kotlin.PublishedApi internal boolean removeTransition(androidx.compose.animation.core.Transition<?> transition);
+    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal void updateTarget(S? targetState);
     property public final S! currentState;
     property public final boolean isRunning;
     property public final String? label;
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSamples.kt
index 7d19409..7172064 100644
--- a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSamples.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSamples.kt
@@ -18,11 +18,13 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.ExperimentalTransitionApi
 import androidx.compose.animation.core.MutableTransitionState
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.Transition
 import androidx.compose.animation.core.animateDp
 import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.createChildTransition
 import androidx.compose.animation.core.keyframes
 import androidx.compose.animation.core.snap
 import androidx.compose.animation.core.spring
@@ -34,9 +36,12 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.Button
 import androidx.compose.material.Card
 import androidx.compose.material.Icon
@@ -51,6 +56,8 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.scale
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.pointer.pointerInput
@@ -324,3 +331,118 @@
         }
     }
 }
+
+@Composable
+@Suppress("UNUSED_PARAMETER")
+@Sampled
+fun CreateChildTransitionSample() {
+    // enum class DialerState { DialerMinimized, NumberPad }
+    @OptIn(ExperimentalTransitionApi::class)
+    @Composable
+    fun DialerButton(visibilityTransition: Transition<Boolean>, modifier: Modifier) {
+        val scale by visibilityTransition.animateFloat { visible ->
+            if (visible) 1f else 2f
+        }
+        Box(modifier.scale(scale).background(Color.Black)) {
+            // Content goes here
+        }
+    }
+
+    @Composable
+    fun NumberPad(visibilityTransition: Transition<Boolean>) {
+        // Create animations using the provided Transition for visibility change here...
+    }
+
+    @OptIn(ExperimentalTransitionApi::class)
+    @Composable
+    fun childTransitionSample() {
+        var dialerState by remember { mutableStateOf(DialerState.NumberPad) }
+        Box(Modifier.fillMaxSize()) {
+            val parentTransition = updateTransition(dialerState)
+
+            // Animate to different corner radius based on target state
+            val cornerRadius by parentTransition.animateDp {
+                if (it == DialerState.NumberPad) 0.dp else 20.dp
+            }
+
+            Box(
+                Modifier.align(Alignment.BottomCenter).widthIn(50.dp).heightIn(50.dp)
+                    .clip(RoundedCornerShape(cornerRadius))
+            ) {
+                NumberPad(
+                    // Creates a child transition that derives its target state from the parent
+                    // transition, and the mapping from parent state to child state.
+                    // This will allow:
+                    // 1) Parent transition to account for additional animations in the child
+                    // Transitions before it considers itself finished. This is useful when you
+                    // have a subsequent action after all animations triggered by a state change
+                    // have finished.
+                    // 2) Separation of concerns. This allows the child composable (i.e.
+                    // NumberPad) to only care about its own visibility, rather than knowing about
+                    // DialerState.
+                    visibilityTransition = parentTransition.createChildTransition {
+                        // This is the lambda that defines how the parent target state maps to
+                        // child target state.
+                        it == DialerState.NumberPad
+                    }
+                    // Note: If it's not important for the animations within the child composable to
+                    // be observable, it's perfectly valid to not hoist the animations through
+                    // a Transition object and instead use animate*AsState.
+                )
+                DialerButton(
+                    visibilityTransition = parentTransition.createChildTransition {
+                        it == DialerState.DialerMinimized
+                    },
+                    modifier = Modifier.matchParentSize()
+                )
+            }
+        }
+    }
+}
+
+enum class DialerState {
+    DialerMinimized,
+    NumberPad
+}
+
+@OptIn(ExperimentalTransitionApi::class)
+@Composable
+fun TransitionStateIsIdleSample() {
+    @Composable
+    fun SelectableItem(selectedState: MutableTransitionState<Boolean>) {
+        val transition = updateTransition(selectedState)
+        val cornerRadius by transition.animateDp { selected -> if (selected) 10.dp else 0.dp }
+        val backgroundColor by transition.animateColor { selected ->
+            if (selected) Color.Red else Color.White
+        }
+        Box(Modifier.background(backgroundColor, RoundedCornerShape(cornerRadius))) {
+            // Item content goes here
+        }
+    }
+
+    @OptIn(ExperimentalTransitionApi::class)
+    @Composable
+    fun ItemsSample(selectedId: Int) {
+        Column {
+            repeat(3) { id ->
+                Box {
+                    // Initialize the selected state as false to produce a transition going from
+                    // false to true if `selected` parameter is true when entering composition.
+                    val selectedState = remember { MutableTransitionState(false) }
+                    // Mutate target state as needed.
+                    selectedState.targetState = id == selectedId
+                    // Now we pass the `MutableTransitionState` to the `Selectable` item and
+                    // observe state change.
+                    SelectableItem(selectedState)
+                    if (selectedState.isIdle && selectedState.targetState) {
+                        // If isIdle == true, it means the transition has arrived at its target state
+                        // and there is no pending animation.
+                        // Now we can do something after the selection transition is
+                        // finished:
+                        Text("Nice choice")
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
index 157183c9..8135f03 100644
--- a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
+++ b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
@@ -20,16 +20,17 @@
 import androidx.compose.animation.animateColor
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.State
-import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
 import junit.framework.TestCase.assertTrue
 import kotlinx.coroutines.delay
 import org.junit.Rule
@@ -48,6 +49,7 @@
         To
     }
 
+    @OptIn(InternalAnimationApi::class)
     @Test
     fun transitionTest() {
         val target = mutableStateOf(AnimStates.From)
@@ -239,6 +241,7 @@
         assertTrue(playTime > 200 * MillisToNanos)
     }
 
+    @OptIn(InternalAnimationApi::class)
     @Test
     fun addNewAnimationInFlightTest() {
         val target = mutableStateOf(AnimStates.From)
@@ -339,4 +342,108 @@
         assertTrue(targetRecreated)
         assertTrue(playTime >= 800 * MillisToNanos)
     }
+
+    @OptIn(ExperimentalTransitionApi::class)
+    @Test
+    fun testMutableTransitionStateIsIdle() {
+        val mutableTransitionState = MutableTransitionState(false)
+        var transition: Transition<Boolean>? = null
+        rule.setContent {
+            transition = updateTransition(mutableTransitionState).apply {
+                animateFloat {
+                    if (it) 1f else 0f
+                }
+            }
+        }
+        rule.mainClock.autoAdvance = false
+        rule.runOnIdle {
+            assertTrue(mutableTransitionState.isIdle)
+            mutableTransitionState.targetState = true
+            assertFalse(mutableTransitionState.isIdle)
+        }
+
+        while (transition?.currentState != true) {
+            // Animation has not finished or even started from Transition's perspective
+            assertFalse(mutableTransitionState.isIdle)
+            rule.mainClock.advanceTimeByFrame()
+        }
+        assertTrue(mutableTransitionState.isIdle)
+
+        // Now that transition false -> true finished, go back to false
+        rule.runOnIdle {
+            assertTrue(mutableTransitionState.isIdle)
+            mutableTransitionState.targetState = false
+            assertFalse(mutableTransitionState.isIdle)
+        }
+
+        while (transition?.currentState == true) {
+            // Animation has not finished or even started from Transition's perspective
+            assertFalse(mutableTransitionState.isIdle)
+            rule.mainClock.advanceTimeByFrame()
+        }
+        assertTrue(mutableTransitionState.isIdle)
+    }
+
+    @OptIn(ExperimentalTransitionApi::class, InternalAnimationApi::class)
+    @Test
+    fun testCreateChildTransition() {
+        val intState = mutableStateOf(1)
+        val parentTransitionFloat = mutableStateOf(1f)
+        val childTransitionFloat = mutableStateOf(1f)
+        rule.setContent {
+            val transition = updateTransition(intState.value)
+            parentTransitionFloat.value = transition.animateFloat({ tween(100) }) {
+                when (it) {
+                    0 -> 0f
+                    1 -> 1f
+                    else -> 2f
+                }
+            }.value
+            val booleanTransition = transition.createChildTransition {
+                it == 1
+            }
+            childTransitionFloat.value = booleanTransition.animateFloat({ tween(500) }) {
+                if (it) 1f else 0f
+            }.value
+            LaunchedEffect(intState.value) {
+                while (true) {
+                    if (transition.targetState == transition.currentState) {
+                        break
+                    }
+                    withFrameNanos { it }
+                    if (intState.value == 0) {
+                        // 1 -> 0
+                        if (
+                            transition.playTimeNanos > 0 && transition.playTimeNanos <= 500_000_000L
+                        ) {
+                            assertTrue(transition.isRunning)
+                            assertTrue(booleanTransition.isRunning)
+                        }
+                    } else if (intState.value == 2) {
+                        // 0 -> 2
+                        assertFalse(booleanTransition.isRunning)
+                        if (transition.playTimeNanos > 120_000_000L) {
+                            assertFalse(transition.isRunning)
+                        } else if (transition.playTimeNanos > 0) {
+                            assertTrue(transition.isRunning)
+                        }
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertEquals(1f, parentTransitionFloat.value)
+            assertEquals(1f, childTransitionFloat.value)
+            intState.value = 0
+        }
+        rule.runOnIdle {
+            assertEquals(0f, parentTransitionFloat.value)
+            assertEquals(0f, childTransitionFloat.value)
+            intState.value = 2
+        }
+        rule.runOnIdle {
+            assertEquals(2f, parentTransitionFloat.value)
+            assertEquals(0f, childTransitionFloat.value)
+        }
+    }
 }
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ExperimentalTransitionApi.kt
similarity index 68%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ExperimentalTransitionApi.kt
index 2aa2c9c..9972083 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ExperimentalTransitionApi.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.compose.animation.core
 
+@RequiresOptIn(
+    message = "This is an experimental animation API for Transition. It may change in the future."
+)
+annotation class ExperimentalTransitionApi
\ No newline at end of file
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
index 1251a0c..d0cce40 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
@@ -22,7 +22,6 @@
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.State
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.runtime.getValue
@@ -66,7 +65,14 @@
     label: String? = null
 ): Transition<T> {
     val transition = remember { Transition(targetState, label = label) }
-    transition.updateTarget(targetState)
+    transition.animateTo(targetState)
+    DisposableEffect(transition) {
+        onDispose {
+            // Clean up on the way out, to ensure the observers are not stuck in an in-between
+            // state.
+            transition.onTransitionEnd()
+        }
+    }
     return transition
 }
 
@@ -101,6 +107,19 @@
      * animate from the current values to the new target.
      */
     var targetState: S by mutableStateOf(initialState)
+
+    /**
+     * [isIdle] returns whether the transition has finished running. This will return false once
+     * the [targetState] has been set to a different value than [currentState].
+     *
+     * @sample androidx.compose.animation.core.samples.TransitionStateIsIdleSample
+     */
+    @get:ExperimentalTransitionApi
+    val isIdle: Boolean
+        get() = (currentState == targetState) && !isRunning
+
+    // Updated from Transition
+    internal var isRunning: Boolean by mutableStateOf(false)
 }
 
 /**
@@ -130,7 +149,14 @@
     val transition = remember(transitionState) {
         Transition(transitionState = transitionState, label)
     }
-    transition.updateTarget(transitionState.targetState)
+    transition.animateTo(transitionState.targetState)
+    DisposableEffect(transition) {
+        onDispose {
+            // Clean up on the way out, to ensure the observers are not stuck in an in-between
+            // state.
+            transition.onTransitionEnd()
+        }
+    }
     return transition
 }
 
@@ -153,7 +179,7 @@
  * @see androidx.compose.animation.animateColor
  */
 // TODO: Support creating Transition outside of composition and support imperative use of Transition
-class Transition<S> internal constructor(
+class Transition<S> @PublishedApi internal constructor(
     private val transitionState: MutableTransitionState<S>,
     val label: String? = null
 ) {
@@ -196,15 +222,20 @@
     /**
      * Play time in nano-seconds. [playTimeNanos] is always non-negative. It starts from 0L at the
      * beginning of the transition and increment until all child animations have finished.
+     * @suppress
      */
-    internal var playTimeNanos by mutableStateOf(0L)
+    @InternalAnimationApi
+    var playTimeNanos by mutableStateOf(0L)
+    private var startTimeNanos by mutableStateOf(AnimationConstants.UnspecifiedTime)
 
     // This gets calculated every time child is updated/added
     internal var updateChildrenNeeded: Boolean by mutableStateOf(true)
-    private var startTimeNanos = AnimationConstants.UnspecifiedTime
 
     private val _animations = mutableVectorOf<TransitionAnimationState<*, *>>()
 
+    // TODO: Support this in animation tooling
+    private val _transitions = mutableVectorOf<Transition<*>>()
+
     /** @suppress **/
     @InternalAnimationApi
     val animations: List<TransitionAnimationState<*, *>> = _animations.asMutableList()
@@ -219,12 +250,9 @@
     var totalDurationNanos: Long by mutableStateOf(0L)
         private set
 
-    // Target state that is currently being animated to
-    private var currentTargetState: S = currentState
-
     internal fun onFrame(frameTimeNanos: Long) {
         if (startTimeNanos == AnimationConstants.UnspecifiedTime) {
-            startTimeNanos = frameTimeNanos
+            onTransitionStart(frameTimeNanos)
         }
         updateChildrenNeeded = false
 
@@ -241,11 +269,31 @@
                 allFinished = false
             }
         }
-        if (allFinished) {
-            startTimeNanos = AnimationConstants.UnspecifiedTime
-            currentState = targetState
-            playTimeNanos = 0
+        _transitions.forEach {
+            if (it.targetState != it.currentState) {
+                it.onFrame(playTimeNanos)
+            }
+            if (it.targetState != it.currentState) {
+                allFinished = false
+            }
         }
+        if (allFinished) {
+            onTransitionEnd()
+        }
+    }
+
+    // onTransitionStart and onTransitionEnd are symmetric. Both are called from onFrame
+    internal fun onTransitionStart(frameTimeNanos: Long) {
+        startTimeNanos = frameTimeNanos
+        transitionState.isRunning = true
+    }
+
+    // onTransitionStart and onTransitionEnd are symmetric. Both are called from onFrame
+    internal fun onTransitionEnd() {
+        startTimeNanos = AnimationConstants.UnspecifiedTime
+        currentState = targetState
+        playTimeNanos = 0
+        transitionState.isRunning = false
     }
 
     /**
@@ -256,6 +304,7 @@
     fun seek(initialState: S, targetState: S, playTimeNanos: Long) {
         // Reset running state
         startTimeNanos = AnimationConstants.UnspecifiedTime
+        transitionState.isRunning = false
         if (!isSeeking || this.currentState != initialState || this.targetState != targetState) {
             // Reset all child animations
             this.currentState = initialState
@@ -274,6 +323,12 @@
     }
 
     @PublishedApi
+    internal fun addTransition(transition: Transition<*>) = _transitions.add(transition)
+
+    @PublishedApi
+    internal fun removeTransition(transition: Transition<*>) = _transitions.remove(transition)
+
+    @PublishedApi
     internal fun addAnimation(
         @Suppress("HiddenTypeParameter")
         animation: TransitionAnimationState<*, *>
@@ -290,6 +345,7 @@
     // This target state should only be used to modify "mutableState"s, as it could potentially
     // roll back. The
     @Suppress("ComposableNaming")
+    @PublishedApi
     @Composable
     internal fun updateTarget(targetState: S) {
         if (!isSeeking) {
@@ -300,11 +356,25 @@
                 segment = Segment(this.targetState, targetState)
                 currentState = this.targetState
                 this.targetState = targetState
-            }
-            SideEffect {
-                animateTo(targetState)
-            }
+                if (!isRunning) {
+                    updateChildrenNeeded = true
+                }
 
+                // If target state is changed, reset all the animations to be re-created in the
+                // next frame w/ their new target value. Child animations target values are updated in
+                // the side effect that may not have happened when this function in invoked.
+                _animations.forEach { it.resetAnimation() }
+            }
+        }
+    }
+
+    // This should only be called if PlayTime comes from clock directly, instead of from a parent
+    // Transition.
+    @Suppress("ComposableNaming")
+    @Composable
+    internal fun animateTo(targetState: S) {
+        if (!isSeeking) {
+            updateTarget(targetState)
             // target != currentState adds LaunchedEffect into the tree in the same frame as
             // target change.
             if (targetState != currentState || isRunning || updateChildrenNeeded) {
@@ -319,22 +389,6 @@
         }
     }
 
-    internal fun animateTo(targetState: S) {
-        if (targetState != currentTargetState) {
-            if (isRunning) {
-                startTimeNanos += playTimeNanos
-                playTimeNanos = 0
-            } else {
-                updateChildrenNeeded = true
-            }
-            currentTargetState = targetState
-            // If target state is changed, reset all the animations to be re-created in the
-            // next frame w/ their new target value. Child animations target values are updated in
-            // the side effect that may not have happened when this function in invoked.
-            _animations.forEach { it.resetAnimation() }
-        }
-    }
-
     private fun onChildAnimationUpdated() {
         updateChildrenNeeded = true
         if (isSeeking) {
@@ -363,14 +417,9 @@
     ) : State<T> {
 
         // Changed during composition, may rollback
-        @Suppress("ShowingMemberInHiddenClass")
-        @PublishedApi
-        internal var targetValue: T by mutableStateOf(initialValue)
-            internal set
+        private var targetValue: T by mutableStateOf(initialValue)
+        private var animationSpec: FiniteAnimationSpec<T> by mutableStateOf(spring())
 
-        @Suppress("ShowingMemberInHiddenClass")
-        @PublishedApi
-        internal var animationSpec: FiniteAnimationSpec<T> by mutableStateOf(spring())
         private var animation: TargetBasedAnimation<T, V> by mutableStateOf(
             TargetBasedAnimation(
                 animationSpec, typeConverter, initialValue, targetValue,
@@ -379,11 +428,12 @@
         )
         internal var isFinished: Boolean by mutableStateOf(true)
         private var offsetTimeNanos by mutableStateOf(0L)
+        private var needsReset by mutableStateOf(false)
 
         // Changed during animation, no concerns of rolling back
         override var value by mutableStateOf(initialValue)
             internal set
-        internal var velocityVector: V = initialVelocityVector
+        private var velocityVector: V = initialVelocityVector
         internal val durationNanos
             get() = animation.durationNanos
 
@@ -404,9 +454,28 @@
             velocityVector = animation.getVelocityVectorFromNanos(playTimeNanos)
         }
 
-        private fun updateAnimation(initialValue: T = value) {
+        private val interruptionSpec: FiniteAnimationSpec<T>
+
+        init {
+            val visibilityThreshold: T? = visibilityThresholdMap.get(typeConverter)?.let {
+                val vector = typeConverter.convertToVector(initialValue)
+                for (id in 0 until vector.size) {
+                    vector[id] = it
+                }
+                typeConverter.convertFromVector(vector)
+            }
+            interruptionSpec = spring(visibilityThreshold = visibilityThreshold)
+        }
+
+        private fun updateAnimation(initialValue: T = value, isInterrupted: Boolean = false) {
+            val spec = if (isInterrupted) {
+                // When interrupted, use the default spring, unless the spec is also a spring.
+                if (animationSpec is SpringSpec<*>) animationSpec else interruptionSpec
+            } else {
+                animationSpec
+            }
             animation = TargetBasedAnimation(
-                animationSpec,
+                spec,
                 typeConverter,
                 initialValue,
                 targetValue,
@@ -416,29 +485,34 @@
         }
 
         internal fun resetAnimation() {
-            offsetTimeNanos = 0
-            isFinished = false
-            updateAnimation()
+            needsReset = true
         }
 
         @PublishedApi
         @Suppress("ShowingMemberInHiddenClass")
         // This gets called *during* composition
-        internal fun updateTargetValue(targetValue: T) {
-            if (this.targetValue != targetValue) {
+        internal fun updateTargetValue(targetValue: T, animationSpec: FiniteAnimationSpec<T>) {
+            if (this.targetValue != targetValue || needsReset) {
                 this.targetValue = targetValue
+                this.animationSpec = animationSpec
+                updateAnimation(isInterrupted = !isFinished)
                 isFinished = false
-                updateAnimation()
                 // This is needed because the target change could happen during a transition
                 offsetTimeNanos = playTimeNanos
+                needsReset = false
             }
         }
 
         @PublishedApi
         @Suppress("ControlFlowWithEmptyBody", "ShowingMemberInHiddenClass")
         // This gets called *during* composition
-        internal fun updateInitialAndTargetValue(initialValue: T, targetValue: T) {
+        internal fun updateInitialAndTargetValue(
+            initialValue: T,
+            targetValue: T,
+            animationSpec: FiniteAnimationSpec<T>
+        ) {
             this.targetValue = targetValue
+            this.animationSpec = animationSpec
             if (animation.initialValue == initialValue && animation.targetValue == targetValue) {
                 // TODO(b/178811102): we should be able to return early here.
             }
@@ -460,6 +534,160 @@
             return this == initialState && targetState == [email protected]
         }
     }
+
+    /**
+     * [DeferredAnimation] can be constructed using [Transition.createDeferredAnimation] during
+     * composition and initialized later. It is useful for animations, the target values for
+     * which are unknown at composition time (e.g. layout size/position, etc).
+     *
+     * Once a [DeferredAnimation] is created, it can be configured and updated as needed using
+     * [DeferredAnimation.animate] method.
+     *
+     * @suppress
+     */
+    @InternalAnimationApi
+    inner class DeferredAnimation<T, V : AnimationVector> internal constructor(
+        val typeConverter: TwoWayConverter<T, V>,
+        val label: String
+    ) {
+        internal var data: DeferredAnimationData<T, V>? = null
+
+        internal inner class DeferredAnimationData<T, V : AnimationVector>(
+            val animation: Transition<S>.TransitionAnimationState<T, V>,
+            var transitionSpec: Segment<S>.() -> FiniteAnimationSpec<T>,
+            var targetValueByState: (state: S) -> T,
+        ) : State<T> {
+            override val value: T
+                get() {
+                    animation.updateTargetValue(
+                        targetValueByState(targetState),
+                        segment.transitionSpec()
+                    )
+                    return animation.value
+                }
+        }
+
+        /**
+         * [DeferredAnimation] allows the animation setup to be deferred until a later time after
+         * composition. [animate] can be used to set up a [DeferredAnimation]. Like other
+         * Transition animations such as [Transition.animateFloat], [DeferredAnimation] also
+         * expects [transitionSpec] and [targetValueByState] for the mapping from target state
+         * to animation spec and target value, respectively.
+         */
+        fun animate(
+            transitionSpec: Segment<S>.() -> FiniteAnimationSpec<T>,
+            targetValueByState: (state: S) -> T
+        ): State<T> {
+            val animData: DeferredAnimationData<T, V> = data ?: DeferredAnimationData(
+                TransitionAnimationState(
+                    targetValueByState(currentState),
+                    typeConverter.createZeroVectorFrom(targetValueByState(currentState)),
+                    typeConverter,
+                    label
+                ),
+                transitionSpec,
+                targetValueByState
+            ).apply {
+                data = this
+                addAnimation(this.animation)
+            }
+            return animData.apply {
+                // Update animtion data with the latest mapping
+                this.targetValueByState = targetValueByState
+                this.transitionSpec = transitionSpec
+
+                animation.updateTargetValue(
+                    targetValueByState(targetState),
+                    segment.transitionSpec()
+                )
+            }
+        }
+
+        internal fun setupSeeking() {
+            data?.apply {
+                animation.updateInitialAndTargetValue(
+                    targetValueByState(segment.initialState),
+                    targetValueByState(segment.targetState),
+                    segment.transitionSpec()
+                )
+            }
+        }
+    }
+
+    internal fun removeAnimation(deferredAnimation: DeferredAnimation<*, *>) {
+        deferredAnimation.data?.animation?.let {
+            removeAnimation(it)
+        }
+    }
+}
+
+/**
+ * This creates a [DeferredAnimation], which will not animate until it is set up using
+ * [DeferredAnimation.animate]. Once the animation is set up, it will animate from the
+ * [currentState][Transition.currentState] to [targetState][Transition.targetState]. If the
+ * [Transition] has already arrived at its target state at the time when the animation added, there
+ * will be no animation.
+ *
+ * @param typeConverter A converter to convert any value of type [T] from/to an [AnimationVector]
+ * @param label A label for differentiating this animation from others in android studio.
+ *
+ * @suppress
+ */
+@InternalAnimationApi
+@Composable
+fun <S, T, V : AnimationVector> Transition<S>.createDeferredAnimation(
+    typeConverter: TwoWayConverter<T, V>,
+    label: String = "DeferredAnimation"
+): Transition<S>.DeferredAnimation<T, V> {
+    val lazyAnim = remember(this) { DeferredAnimation(typeConverter, label) }
+    DisposableEffect(lazyAnim) {
+        onDispose {
+            removeAnimation(lazyAnim)
+        }
+    }
+    if (isSeeking) {
+        lazyAnim.setupSeeking()
+    }
+    return lazyAnim
+}
+
+/**
+ * [createChildTransition] creates a child Transition based on the mapping between parent state to
+ * child state provided in [transformToChildState]. This serves the following purposes:
+ * 1) Hoist the child transition state into parent transition. Therefore the parent Transition
+ * will be aware of whether there's any on-going animation due to the same target state change.
+ * This will further allow sequential animation to be set up when all animations have finished.
+ * 2) Separation of concerns. The child transition can respresent a much more simplified state
+ * transition when, for example, mapping from an enum parent state to a Boolean visible state for
+ * passing further down the compose tree. The child composables hence can be designed around
+ * handling a more simple and a more relevant state change.
+ *
+ * [label] is used to differentiate from other animations in the same transition in Android Studio.
+ *
+ * @sample androidx.compose.animation.core.samples.CreateChildTransitionSample
+ */
+@ExperimentalTransitionApi
+@Composable
+inline fun <S, T> Transition<S>.createChildTransition(
+    label: String = "ChildTransition",
+    transformToChildState: @Composable (parentState: S) -> T,
+): Transition<T> {
+    val initialParentState = remember(this) { this.currentState }
+    val initialState = transformToChildState(initialParentState)
+    val transition = remember(this) {
+        Transition<T>(MutableTransitionState(initialState), label)
+    }
+
+    DisposableEffect(transition) {
+        addTransition(transition)
+        onDispose {
+            removeTransition(transition)
+        }
+    }
+
+    val targetState = transformToChildState(this.targetState)
+    transition.updateTarget(targetState)
+    return transition
 }
 
 /**
@@ -496,36 +724,30 @@
     targetValueByState: @Composable (state: S) -> T
 ): State<T> {
 
+    val initialValue = targetValueByState(currentState)
     val targetValue = targetValueByState(targetState)
-    // TODO: need a better way to store initial value.
-    val initNeeded = remember(this) { mutableStateOf(true) }
-    val initValue = if (initNeeded.value) targetValueByState(currentState) else targetValue
     val transitionAnimation = remember(this) {
         // Initialize the animation state to initialState value, so if it's added during a
         // transition run, it'll participate in the animation.
         // This is preferred because it's easy to opt out - Simply adding new animation once
         // currentState == targetState would opt out.
         TransitionAnimationState(
-            initValue,
+            initialValue,
             typeConverter.createZeroVectorFrom(targetValue),
             typeConverter,
             label
         )
     }
-    transitionAnimation.animationSpec = transitionSpec(segment)
-
-    if (initNeeded.value) {
-        SideEffect {
-            initNeeded.value = false
-        }
-    }
-
+    val animationSpec = transitionSpec(segment)
     if (isSeeking) {
         // In the case of seeking, we also need to update initial value as needed
-        val initialValue = targetValueByState(segment.initialState)
-        transitionAnimation.updateInitialAndTargetValue(initialValue, targetValue)
+        transitionAnimation.updateInitialAndTargetValue(
+            initialValue,
+            targetValue,
+            animationSpec
+        )
     } else {
-        transitionAnimation.updateTargetValue(targetValue)
+        transitionAnimation.updateTargetValue(targetValue, animationSpec)
     }
 
     DisposableEffect(transitionAnimation) {
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VisibilityThresholds.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VisibilityThresholds.kt
index 14f4ce0..5b27b547 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VisibilityThresholds.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VisibilityThresholds.kt
@@ -99,4 +99,16 @@
 val Rect.Companion.VisibilityThreshold: Rect
     get() = rectVisibilityThreshold
 
-// TODO: Add Dp.DefaultAnimation = spring<Dp>(visibilityThreshold = Dp.VisibilityThreshold)
\ No newline at end of file
+// TODO: Add Dp.DefaultAnimation = spring<Dp>(visibilityThreshold = Dp.VisibilityThreshold)
+
+internal val visibilityThresholdMap: Map<TwoWayConverter<*, *>, Float> = mapOf(
+    Int.VectorConverter to 1f,
+    IntSize.VectorConverter to 1f,
+    IntOffset.VectorConverter to 1f,
+    Float.VectorConverter to 0.01f,
+    Rect.VectorConverter to PxVisibilityThreshold,
+    Size.VectorConverter to PxVisibilityThreshold,
+    Offset.VectorConverter to PxVisibilityThreshold,
+    Dp.VectorConverter to DpVisibilityThreshold,
+    DpOffset.VectorConverter to DpVisibilityThreshold
+)
\ No newline at end of file
diff --git a/compose/animation/animation/api/public_plus_experimental_1.0.0-beta07.txt b/compose/animation/animation/api/public_plus_experimental_1.0.0-beta07.txt
index 5c07774..0f00f36 100644
--- a/compose/animation/animation/api/public_plus_experimental_1.0.0-beta07.txt
+++ b/compose/animation/animation/api/public_plus_experimental_1.0.0-beta07.txt
@@ -6,9 +6,20 @@
   }
 
   public final class AnimatedVisibilityKt {
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static <T> void AnimatedVisibility(androidx.compose.animation.core.Transition<T>, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @Deprecated @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.animation.ExperimentalAnimationApi public final class AnimatedVisibilityScope {
+    method public androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit);
+    method public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
+    property public final androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
   }
 
   public final class AnimationModifierKt {
@@ -23,6 +34,12 @@
     method @androidx.compose.runtime.Composable public static <T> void Crossfade(T? targetState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
   }
 
+  @androidx.compose.animation.ExperimentalAnimationApi public enum EnterExitState {
+    enum_constant public static final androidx.compose.animation.EnterExitState PostExit;
+    enum_constant public static final androidx.compose.animation.EnterExitState PreEnter;
+    enum_constant public static final androidx.compose.animation.EnterExitState Visible;
+  }
+
   public final class EnterExitTransitionKt {
     method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Stable public static androidx.compose.animation.EnterTransition expandHorizontally(optional androidx.compose.ui.Alignment.Horizontal expandFrom, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialWidth, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> animationSpec, optional boolean clip);
     method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Stable public static androidx.compose.animation.EnterTransition expandIn(optional androidx.compose.ui.Alignment expandFrom, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,androidx.compose.ui.unit.IntSize> initialSize, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> animationSpec, optional boolean clip);
@@ -42,10 +59,22 @@
 
   @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Immutable public abstract sealed class EnterTransition {
     method @androidx.compose.runtime.Stable public final operator androidx.compose.animation.EnterTransition plus(androidx.compose.animation.EnterTransition enter);
+    field public static final androidx.compose.animation.EnterTransition.Companion Companion;
+  }
+
+  public static final class EnterTransition.Companion {
+    method public androidx.compose.animation.EnterTransition getNone();
+    property public final androidx.compose.animation.EnterTransition None;
   }
 
   @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Immutable public abstract sealed class ExitTransition {
     method @androidx.compose.runtime.Stable public final operator androidx.compose.animation.ExitTransition plus(androidx.compose.animation.ExitTransition exit);
+    field public static final androidx.compose.animation.ExitTransition.Companion Companion;
+  }
+
+  public static final class ExitTransition.Companion {
+    method public androidx.compose.animation.ExitTransition getNone();
+    property public final androidx.compose.animation.ExitTransition None;
   }
 
   @kotlin.RequiresOptIn(message="This is an experimental animation API.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface ExperimentalAnimationApi {
diff --git a/compose/animation/animation/api/public_plus_experimental_current.txt b/compose/animation/animation/api/public_plus_experimental_current.txt
index 5c07774..0f00f36 100644
--- a/compose/animation/animation/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation/api/public_plus_experimental_current.txt
@@ -6,9 +6,20 @@
   }
 
   public final class AnimatedVisibilityKt {
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, boolean visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.RowScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(androidx.compose.foundation.layout.ColumnScope, androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> visibleState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static <T> void AnimatedVisibility(androidx.compose.animation.core.Transition<T>, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> visible, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, kotlin.jvm.functions.Function1<? super androidx.compose.animation.AnimatedVisibilityScope,kotlin.Unit> content);
+    method @Deprecated @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Composable public static void AnimatedVisibility(boolean visible, optional androidx.compose.ui.Modifier modifier, androidx.compose.animation.EnterTransition enter, androidx.compose.animation.ExitTransition exit, boolean initiallyVisible, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.animation.ExperimentalAnimationApi public final class AnimatedVisibilityScope {
+    method public androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit);
+    method public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
+    property public final androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
   }
 
   public final class AnimationModifierKt {
@@ -23,6 +34,12 @@
     method @androidx.compose.runtime.Composable public static <T> void Crossfade(T? targetState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
   }
 
+  @androidx.compose.animation.ExperimentalAnimationApi public enum EnterExitState {
+    enum_constant public static final androidx.compose.animation.EnterExitState PostExit;
+    enum_constant public static final androidx.compose.animation.EnterExitState PreEnter;
+    enum_constant public static final androidx.compose.animation.EnterExitState Visible;
+  }
+
   public final class EnterExitTransitionKt {
     method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Stable public static androidx.compose.animation.EnterTransition expandHorizontally(optional androidx.compose.ui.Alignment.Horizontal expandFrom, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialWidth, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> animationSpec, optional boolean clip);
     method @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Stable public static androidx.compose.animation.EnterTransition expandIn(optional androidx.compose.ui.Alignment expandFrom, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,androidx.compose.ui.unit.IntSize> initialSize, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> animationSpec, optional boolean clip);
@@ -42,10 +59,22 @@
 
   @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Immutable public abstract sealed class EnterTransition {
     method @androidx.compose.runtime.Stable public final operator androidx.compose.animation.EnterTransition plus(androidx.compose.animation.EnterTransition enter);
+    field public static final androidx.compose.animation.EnterTransition.Companion Companion;
+  }
+
+  public static final class EnterTransition.Companion {
+    method public androidx.compose.animation.EnterTransition getNone();
+    property public final androidx.compose.animation.EnterTransition None;
   }
 
   @androidx.compose.animation.ExperimentalAnimationApi @androidx.compose.runtime.Immutable public abstract sealed class ExitTransition {
     method @androidx.compose.runtime.Stable public final operator androidx.compose.animation.ExitTransition plus(androidx.compose.animation.ExitTransition exit);
+    field public static final androidx.compose.animation.ExitTransition.Companion Companion;
+  }
+
+  public static final class ExitTransition.Companion {
+    method public androidx.compose.animation.ExitTransition getNone();
+    property public final androidx.compose.animation.ExitTransition None;
   }
 
   @kotlin.RequiresOptIn(message="This is an experimental animation API.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface ExperimentalAnimationApi {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
index 24e6a0f..31d9ea7 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
@@ -52,7 +52,7 @@
             .fillMaxWidth()
             .padding(50.dp)
     ) {
-        Text()
+        MyText()
         Spacer(Modifier.requiredHeight(20.dp))
         Button()
         Spacer(Modifier.requiredHeight(20.dp))
@@ -61,7 +61,7 @@
 }
 
 @Composable
-private fun Text() {
+private fun MyText() {
     val shortText = "Click me"
     val longText = "Very long text\nthat spans across\nmultiple lines"
     var short by remember { mutableStateOf(true) }
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
index d4f9186..f1326e7 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
@@ -34,12 +34,13 @@
 import androidx.compose.animation.slideOutHorizontally
 import androidx.compose.animation.slideOutVertically
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.selection.selectable
 import androidx.compose.material.Button
 import androidx.compose.material.Checkbox
@@ -54,6 +55,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import kotlin.math.max
+import kotlin.math.min
 
 @Composable
 fun AnimatedVisibilityDemo() {
@@ -68,60 +71,67 @@
 @OptIn(ExperimentalAnimationApi::class)
 @Composable
 fun AnimatedItems(animateContentSize: Boolean) {
-    var counter by remember { mutableStateOf(0) }
-    Box(
-        Modifier.padding(bottom = 20.dp)
-    ) {
-
-        val modifier = if (animateContentSize) Modifier.animateContentSize() else Modifier
-        Column(
-            Modifier.background(Color.LightGray).fillMaxWidth().then(modifier)
+    var itemNum by remember { mutableStateOf(0) }
+    Column {
+        Row(
+            Modifier.fillMaxWidth().padding(20.dp),
+            horizontalArrangement = Arrangement.SpaceBetween
         ) {
-            val itemNum = if (counter >= 7) 12 - counter else counter
-
-            AnimatedVisibility(visible = itemNum > 0) {
-                Item(
-                    pastelColors[0],
-                    "Expand Vertically + Fade In\nShrink " +
-                        "Vertically + Fade Out\n(Column Default)"
-                )
+            Button(onClick = { itemNum = min((itemNum + 1), 6) }) {
+                Text("Add")
             }
-            HorizontalTransition(visible = itemNum > 1) {
-                Item(pastelColors[1], "Expand Horizontally\nShrink Horizontally")
-            }
-            SlideTransition(visible = itemNum > 2) {
-                Item(
-                    pastelColors[2],
-                    "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
-                        "Fade Out"
-                )
-            }
-            AnimatedVisibility(
-                visible = itemNum > 3,
-                enter = expandVertically(),
-                exit = shrinkVertically()
-            ) {
-                Item(pastelColors[3], "Expand Vertically\nShrink Vertically")
-            }
-            FadeTransition(visible = itemNum > 4) {
-                Item(pastelColors[4], "Fade In\nFade Out")
-            }
-            FullyLoadedTransition(visible = itemNum > 5) {
-                Item(
-                    pastelColors[0],
-                    "Expand Vertically + Fade In + Slide In Vertically\n" +
-                        "Shrink Vertically + Fade Out + Slide Out Vertically"
-                )
+            Button(onClick = { itemNum = max((itemNum - 1), 0) }) {
+                Text("Remove")
             }
         }
-
-        Button(
-            modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
-            onClick = {
-                counter = (counter + 1) % 12
-            }
+        Box(
+            Modifier.padding(bottom = 20.dp)
         ) {
-            Text("Click Me")
+
+            val modifier = if (animateContentSize) Modifier.animateContentSize() else Modifier
+            Column(
+                Modifier.background(Color.LightGray).fillMaxWidth().then(modifier)
+            ) {
+
+                Column(
+                    Modifier.background(Color.LightGray).fillMaxWidth().then(modifier)
+                ) {
+                    AnimatedVisibility(visible = itemNum > 0) {
+                        Item(
+                            pastelColors[0],
+                            "Expand Vertically + Fade In\nShrink " +
+                                "Vertically + Fade Out\n(Column Default)"
+                        )
+                    }
+                    HorizontalTransition(visible = itemNum > 1) {
+                        Item(pastelColors[1], "Expand Horizontally\nShrink Horizontally")
+                    }
+                    SlideTransition(visible = itemNum > 2) {
+                        Item(
+                            pastelColors[2],
+                            "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
+                                "Fade Out"
+                        )
+                    }
+                    AnimatedVisibility(
+                        visible = itemNum > 3,
+                        enter = expandVertically(),
+                        exit = shrinkVertically()
+                    ) {
+                        Item(pastelColors[3], "Expand Vertically\nShrink Vertically")
+                    }
+                    FadeTransition(visible = itemNum > 4) {
+                        Item(pastelColors[4], "Fade In\nFade Out")
+                    }
+                    FullyLoadedTransition(visible = itemNum > 5) {
+                        Item(
+                            pastelColors[0],
+                            "Expand Vertically + Fade In + Slide In Vertically\n" +
+                                "Shrink Vertically + Fade Out + Slide Out Vertically"
+                        )
+                    }
+                }
+            }
         }
     }
 }
@@ -164,9 +174,10 @@
             targetWidth = { fullWidth -> fullWidth / 10 },
             // Overwrites the default animation with tween for this shrink animation.
             animationSpec = tween(durationMillis = 400)
-        ) + fadeOut(),
-        content = content
-    )
+        ) + fadeOut()
+    ) {
+        content()
+    }
 }
 
 @OptIn(ExperimentalAnimationApi::class)
@@ -187,9 +198,10 @@
             // Overwrites the ending position of the slide-out to 200 (pixels) to the right
             targetOffsetX = { 200 },
             animationSpec = spring(stiffness = Spring.StiffnessHigh)
-        ) + fadeOut(),
-        content = content
-    )
+        ) + fadeOut()
+    ) {
+        content()
+    }
 }
 
 @OptIn(ExperimentalAnimationApi::class)
@@ -204,9 +216,10 @@
         exit = fadeOut(
             // Overwrites the default animation with tween
             animationSpec = tween(durationMillis = 250)
-        ),
-        content = content
-    )
+        )
+    ) {
+        content()
+    }
 }
 
 @OptIn(ExperimentalAnimationApi::class)
@@ -221,7 +234,8 @@
         ) + expandVertically(
             expandFrom = Alignment.Top
         ) + fadeIn(initialAlpha = 0.3f),
-        exit = slideOutVertically() + shrinkVertically() + fadeOut(),
-        content = content
-    )
+        exit = slideOutVertically() + shrinkVertically() + fadeOut()
+    ) {
+        content()
+    }
 }
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
index 96ed035..ef08514 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
@@ -18,65 +18,77 @@
 
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.ExperimentalTransitionApi
+import androidx.compose.animation.core.MutableTransitionState
 import androidx.compose.animation.expandVertically
 import androidx.compose.animation.shrinkVertically
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.lazy.items
 import androidx.compose.material.Button
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Alignment.Companion.CenterEnd
 import androidx.compose.ui.Alignment.Companion.End
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
 
-@OptIn(ExperimentalAnimationApi::class)
+@OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
 @Composable
 fun AnimatedVisibilityLazyColumnDemo() {
-    var itemNum by remember { mutableStateOf(0) }
     Column {
+        val model = remember { MyModel() }
         Row(Modifier.fillMaxWidth()) {
             Button(
-                { itemNum = itemNum + 1 },
-                enabled = itemNum <= turquoiseColors.size - 1,
+                { model.addNewItem() },
                 modifier = Modifier.padding(15.dp).weight(1f)
             ) {
                 Text("Add")
             }
+        }
 
-            Button(
-                { itemNum = itemNum - 1 },
-                enabled = itemNum >= 1,
-                modifier = Modifier.padding(15.dp).weight(1f)
-            ) {
-                Text("Remove")
+        LaunchedEffect(model) {
+            snapshotFlow {
+                model.items.firstOrNull { it.visible.isIdle && !it.visible.targetState }
+            }.collect {
+                if (it != null) {
+                    model.pruneItems()
+                }
             }
         }
         LazyColumn {
-            itemsIndexed(turquoiseColors) { i, color ->
+            items(model.items, key = { it.itemId }) { item ->
                 AnimatedVisibility(
-                    (turquoiseColors.size - itemNum) <= i,
+                    item.visible,
                     enter = expandVertically(),
                     exit = shrinkVertically()
                 ) {
-                    Spacer(Modifier.fillMaxWidth().requiredHeight(90.dp).background(color))
+                    Box(Modifier.fillMaxWidth().requiredHeight(90.dp).background(item.color)) {
+                        Button(
+                            { model.removeItem(item) },
+                            modifier = Modifier.align(CenterEnd).padding(15.dp)
+                        ) {
+                            Text("Remove")
+                        }
+                    }
                 }
             }
         }
 
         Button(
-            { itemNum = 0 },
+            { model.removeAll() },
             modifier = Modifier.align(End).padding(15.dp)
         ) {
             Text("Clear All")
@@ -84,6 +96,44 @@
     }
 }
 
+private class MyModel {
+    private val _items: MutableList<ColoredItem> = mutableStateListOf()
+    private var lastItemId = 0
+    val items: List<ColoredItem> = _items
+
+    class ColoredItem(val visible: MutableTransitionState<Boolean>, val itemId: Int) {
+        val color: Color
+            get() = turquoiseColors.let {
+                it[itemId % it.size]
+            }
+    }
+
+    fun addNewItem() {
+        lastItemId++
+        _items.add(
+            ColoredItem(
+                MutableTransitionState(false).apply { targetState = true },
+                lastItemId
+            )
+        )
+    }
+
+    fun removeItem(item: ColoredItem) {
+        item.visible.targetState = false
+    }
+
+    @OptIn(ExperimentalTransitionApi::class)
+    fun pruneItems() {
+        _items.removeAll(items.filter { it.visible.isIdle && !it.visible.targetState })
+    }
+
+    fun removeAll() {
+        _items.forEach {
+            it.visible.targetState = false
+        }
+    }
+}
+
 private val turquoiseColors = listOf(
     Color(0xff07688C),
     Color(0xff1986AF),
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index a8aff2e..1160261 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -44,7 +44,10 @@
                     AnimatedVisibilityContentSizeChangeDemo()
                 },
                 ComposableDemo("Cross Fade") { CrossfadeDemo() },
-                ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
+                ComposableDemo("Enter/ExitTransition Combo Demo") { EnterExitCombinationDemo() },
+                ComposableDemo("Sequential Enter/Exit Demo") {
+                    SequentialEnterExitDemo()
+                },
             )
         ),
         DemoCategory(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitCombinationDemo.kt
similarity index 99%
rename from compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitCombinationDemo.kt
index cccb234..f25a6fb 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitCombinationDemo.kt
@@ -79,7 +79,7 @@
 import androidx.compose.ui.unit.dp
 
 @Composable
-fun EnterExitTransitionDemo() {
+fun EnterExitCombinationDemo() {
     Column(Modifier.fillMaxWidth().padding(top = 20.dp)) {
         val oppositeAlignment = remember { mutableStateOf(true) }
 
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SequentialEnterExitDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SequentialEnterExitDemo.kt
new file mode 100644
index 0000000..e769f8b
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SequentialEnterExitDemo.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.animation.demos
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.AnimatedVisibilityScope
+import androidx.compose.animation.EnterExitState
+import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.ExperimentalTransitionApi
+import androidx.compose.animation.core.MutableTransitionState
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Button
+import androidx.compose.material.FloatingActionButton
+import androidx.compose.material.Icon
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.text.font.FontWeight.Companion.Bold
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+/*
+ * This demo shows how to create a Transition<EnterExitState> with MutableTransitionState, and
+ * use the Transition<EnterExitState> to animate a few enter/exit transitions together. The
+ * MutableTransitionState is then used to add sequential enter/exit transitions.
+ *
+ *  APIs used:
+ * - updateTransition
+ * - MutableTransitionState
+ * - EnterExitState
+ */
+@OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
+@Composable
+fun SequentialEnterExitDemo() {
+    Box {
+        var mainContentVisible by remember {
+            mutableStateOf(MutableTransitionState(true))
+        }
+        Column(Modifier.fillMaxSize()) {
+            Spacer(Modifier.size(40.dp))
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.SpaceAround
+            ) {
+                // New MutableTransitionState instance here. This should reset the animation.
+                Button(onClick = { mainContentVisible = MutableTransitionState(false) }) {
+                    Text("Reset")
+                }
+
+                Button(
+                    onClick = { mainContentVisible.targetState = !mainContentVisible.targetState },
+                ) {
+                    Text("Toggle Visibility")
+                }
+            }
+            Spacer(Modifier.size(40.dp))
+            AnimatedVisibility(
+                visibleState = mainContentVisible,
+                modifier = Modifier.fillMaxSize(),
+                enter = fadeIn(),
+                exit = fadeOut()
+            ) {
+                Box {
+                    Column(Modifier.fillMaxSize()) {
+                        Item(Modifier.weight(1f), backgroundColor = Color(0xffff6f69))
+                        Item(Modifier.weight(1f), backgroundColor = Color(0xffffcc5c))
+                    }
+                    FloatingActionButton(
+                        onClick = {},
+                        modifier = Modifier.align(Alignment.BottomEnd).padding(20.dp),
+                        backgroundColor = MaterialTheme.colors.primary
+                    ) {
+                        Icon(Icons.Default.Favorite, contentDescription = null)
+                    }
+                }
+            }
+        }
+        AnimatedVisibility(
+            visible = mainContentVisible.targetState && mainContentVisible.isIdle,
+            modifier = Modifier.align(Alignment.Center),
+            enter = expandVertically(),
+            exit = fadeOut(animationSpec = tween(50))
+        ) {
+            Text("Transition Finished", color = Color.White, fontSize = 40.sp, fontWeight = Bold)
+        }
+    }
+}
+
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+private fun AnimatedVisibilityScope.Item(
+    modifier: Modifier,
+    backgroundColor: Color
+) {
+    val scale by transition.animateFloat { enterExitState ->
+        when (enterExitState) {
+            EnterExitState.PreEnter -> 0.9f
+            EnterExitState.Visible -> 1.0f
+            EnterExitState.PostExit -> 0.5f
+        }
+    }
+    Box(
+        modifier.fillMaxWidth().padding(5.dp).animateEnterExit(
+            enter = slideInVertically(initialOffsetY = { it }),
+            exit = ExitTransition.None
+        ).graphicsLayer {
+            scaleX = scale
+            scaleY = scale
+        }.clip(RoundedCornerShape(20.dp)).background(backgroundColor).fillMaxSize()
+    ) {}
+}
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
index e065cf5..2999fd4 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
@@ -18,12 +18,21 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.AnimatedVisibilityScope
+import androidx.compose.animation.EnterExitState
+import androidx.compose.animation.ExitTransition
 import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.ExperimentalTransitionApi
 import androidx.compose.animation.core.FastOutSlowInEasing
 import androidx.compose.animation.core.LinearOutSlowInEasing
+import androidx.compose.animation.core.MutableTransitionState
 import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateDp
+import androidx.compose.animation.core.animateFloat
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.updateTransition
 import androidx.compose.animation.expandHorizontally
 import androidx.compose.animation.expandIn
 import androidx.compose.animation.expandVertically
@@ -38,32 +47,52 @@
 import androidx.compose.animation.slideOut
 import androidx.compose.animation.slideOutHorizontally
 import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Button
 import androidx.compose.material.FloatingActionButton
 import androidx.compose.material.Icon
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
 import androidx.compose.material.Text
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
 
 @OptIn(ExperimentalAnimationApi::class)
 @Sampled
@@ -163,6 +192,51 @@
 @OptIn(ExperimentalAnimationApi::class)
 @Sampled
 @Composable
+fun AnimatedVisibilityWithBooleanVisibleParamNoReceiver() {
+    var visible by remember { mutableStateOf(true) }
+    Box(modifier = Modifier.clickable { visible = !visible }) {
+        AnimatedVisibility(
+            visible = visible,
+            modifier = Modifier.align(Alignment.Center),
+            enter = slideInVertically(
+                // Start the slide from 40 (pixels) above where the content is supposed to go, to
+                // produce a parallax effect
+                initialOffsetY = { -40 }
+            ) + expandVertically(
+                expandFrom = Alignment.Top
+            ) + fadeIn(initialAlpha = 0.3f),
+            exit = shrinkVertically() + fadeOut(animationSpec = tween(200))
+        ) { // Content that needs to appear/disappear goes here:
+            // Here we can optionally define a custom enter/exit animation by creating an animation
+            // using the Transition<EnterExitState> object from AnimatedVisibilityScope:
+            val scale by transition.animateFloat {
+                when (it) {
+                    // Scale will be animating from 0.8f to 1.0f during enter transition.
+                    EnterExitState.PreEnter -> 0.8f
+                    EnterExitState.Visible -> 1f
+                    // Scale will be animating from 1.0f to 1.2f during exit animation. If the
+                    // targetValue specified for PreEnter is the same as PostExit, the enter and
+                    // exit animation for this property will be symmetric.
+                    EnterExitState.PostExit -> 1.2f
+                }
+            }
+            Text(
+                "Content to appear/disappear",
+                Modifier.fillMaxWidth().requiredHeight(100.dp).background(Color(0xffa1feff))
+                    .graphicsLayer {
+                        // Apply our custom enter/exit transition
+                        scaleX = scale
+                        scaleY = scale
+                    }.padding(top = 20.dp),
+                textAlign = TextAlign.Center
+            )
+        }
+    }
+}
+
+@OptIn(ExperimentalAnimationApi::class)
+@Sampled
+@Composable
 fun ColumnScope.AnimatedFloatingActionButton() {
     var expanded by remember { mutableStateOf(true) }
     FloatingActionButton(
@@ -290,3 +364,340 @@
         }
     }
 }
+
+@Sampled
+@OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
+@Composable
+fun AVScopeAnimateEnterExit() {
+    @OptIn(ExperimentalAnimationApi::class)
+    @Composable
+    fun AnimatedVisibilityScope.Item(
+        modifier: Modifier,
+        backgroundColor: Color
+    ) {
+        // Creates a custom enter/exit animation for scale property.
+        val scale by transition.animateFloat { enterExitState ->
+            // Enter transition will be animating the scale from 0.9f to 1.0f
+            // (i.e. PreEnter -> Visible). Exit transition will be from 1.0f to
+            // 0.5f (i.e. Visible -> PostExit)
+            when (enterExitState) {
+                EnterExitState.PreEnter -> 0.9f
+                EnterExitState.Visible -> 1.0f
+                EnterExitState.PostExit -> 0.5f
+            }
+        }
+
+        // Since we defined `Item` as an extension function on AnimatedVisibilityScope, we can use
+        // the `animateEnterExit` modifier to produce an enter/exit animation for it. This will
+        // run simultaneously with the `AnimatedVisibility`'s enter/exit.
+        Box(
+            modifier.fillMaxWidth().padding(5.dp).animateEnterExit(
+                // Slide in from below,
+                enter = slideInVertically(initialOffsetY = { it }),
+                // No slide on the way out. So the exit animation will be scale (from the custom
+                // scale animation defined above) and fade (from AnimatedVisibility)
+                exit = ExitTransition.None
+            ).graphicsLayer {
+                scaleX = scale
+                scaleY = scale
+            }.clip(RoundedCornerShape(20.dp)).background(backgroundColor).fillMaxSize()
+        ) {
+            // Content of the item goes here...
+        }
+    }
+
+    @OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
+    @Composable
+    fun AnimateMainContent(mainContentVisible: MutableTransitionState<Boolean>) {
+        Box {
+            // Use the `MutableTransitionState<Boolean>` to specify whether AnimatedVisibility
+            // should be visible. This will also allow AnimatedVisibility animation states to be
+            // observed externally.
+            AnimatedVisibility(
+                visibleState = mainContentVisible,
+                modifier = Modifier.fillMaxSize(),
+                enter = fadeIn(),
+                exit = fadeOut()
+            ) {
+                Box {
+                    Column(Modifier.fillMaxSize()) {
+                        // We have created `Item`s below as extension functions on
+                        // AnimatedVisibilityScope in this example. So they can define their own
+                        // enter/exit to run alongside the enter/exit defined in AnimatedVisibility.
+                        Item(Modifier.weight(1f), backgroundColor = Color(0xffff6f69))
+                        Item(Modifier.weight(1f), backgroundColor = Color(0xffffcc5c))
+                    }
+                    // This FAB will be simply fading in/out as specified by the AnimatedVisibility
+                    FloatingActionButton(
+                        onClick = {},
+                        modifier = Modifier.align(Alignment.BottomEnd).padding(20.dp),
+                        backgroundColor = MaterialTheme.colors.primary
+                    ) { Icon(Icons.Default.Favorite, contentDescription = null) }
+                }
+            }
+
+            // Here we can get a signal for when the Enter/Exit animation of the content above
+            // has finished by inspecting the MutableTransitionState passed to the
+            // AnimatedVisibility. This allows sequential animation after the enter/exit.
+            AnimatedVisibility(
+                // Once the main content is visible (i.e. targetState == true), and no pending
+                // animations. We will start another enter animation sequentially.
+                visible = mainContentVisible.targetState && mainContentVisible.isIdle,
+                modifier = Modifier.align(Alignment.Center),
+                enter = expandVertically(),
+                exit = fadeOut(animationSpec = tween(50))
+            ) {
+                Text("Transition Finished")
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+@Sampled
+fun AddAnimatedVisibilityToGenericTransitionSample() {
+    @Composable
+    fun ItemMainContent() {
+        Row(Modifier.height(100.dp).fillMaxWidth(), Arrangement.SpaceEvenly) {
+            Box(
+                Modifier.size(60.dp).align(Alignment.CenterVertically)
+                    .background(Color(0xffcdb7f6), CircleShape)
+            )
+            Column(Modifier.align(Alignment.CenterVertically)) {
+                Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray))
+                Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray))
+            }
+        }
+    }
+
+    @OptIn(ExperimentalAnimationApi::class)
+    @Composable
+    fun SelectableItem() {
+        // This sample animates a number of properties, including AnimatedVisibility, as a part of
+        // the Transition going between selected and unselected.
+        Box(Modifier.padding(15.dp)) {
+            var selected by remember { mutableStateOf(false) }
+            // Creates a transition to animate visual changes when `selected` is changed.
+            val selectionTransition = updateTransition(selected)
+            // Animates the border color as a part of the transition
+            val borderColor by selectionTransition.animateColor { isSelected ->
+                if (isSelected) Color(0xff03a9f4) else Color.White
+            }
+            // Animates the background color when selected state changes
+            val contentBackground by selectionTransition.animateColor { isSelected ->
+                if (isSelected) Color(0xffdbf0fe) else Color.White
+            }
+            // Animates elevation as a part of the transition
+            val elevation by selectionTransition.animateDp { isSelected ->
+                if (isSelected) 10.dp else 2.dp
+            }
+            Surface(
+                shape = RoundedCornerShape(10.dp),
+                border = BorderStroke(2.dp, borderColor),
+                modifier = Modifier.clickable { selected = !selected },
+                color = contentBackground,
+                elevation = elevation,
+            ) {
+                Column(Modifier.fillMaxWidth()) {
+                    ItemMainContent()
+                    // Creates an AnimatedVisibility as a part of the transition, so that when
+                    // selected it's visible. This will hoist all the animations that are internal
+                    // to AnimatedVisibility (i.e. fade, slide, etc) to the transition. As a result,
+                    // `selectionTransition` will not finish until all the animations in
+                    // AnimatedVisibility as well as animations added directly to it have finished.
+                    selectionTransition.AnimatedVisibility(
+                        visible = { it },
+                        enter = expandVertically(),
+                        exit = shrinkVertically()
+                    ) {
+                        Box(Modifier.fillMaxWidth().padding(10.dp)) {
+                            Text(
+                                "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed" +
+                                    " eiusmod tempor incididunt labore et dolore magna aliqua. " +
+                                    "Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+                                    "laboris nisi ut aliquip ex ea commodo consequat. Duis aute " +
+                                    "irure dolor."
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
+@Sampled
+@Composable
+fun AnimatedVisibilityLazyColumnSample() {
+    val turquoiseColors = listOf(
+        Color(0xff07688C),
+        Color(0xff1986AF),
+        Color(0xff50B6CD),
+        Color(0xffBCF8FF),
+        Color(0xff8AEAE9),
+        Color(0xff46CECA)
+    )
+
+    // MyModel class handles the data change of the items that are displayed in LazyColumn.
+    class MyModel {
+        private val _items: MutableList<ColoredItem> = mutableStateListOf()
+        private var lastItemId = 0
+        val items: List<ColoredItem> = _items
+
+        // Each item has a MutableTransitionState field to track as well as to mutate the item's
+        // visibility. When the MutableTransitionState's targetState changes, corresponding
+        // transition will be fired. MutableTransitionState allows animation lifecycle to be
+        // observed through it's [currentState] and [isIdle]. See below for details.
+        inner class ColoredItem(val visible: MutableTransitionState<Boolean>, val itemId: Int) {
+            val color: Color
+                get() = turquoiseColors.let {
+                    it[itemId % it.size]
+                }
+        }
+
+        fun addNewItem() {
+            lastItemId++
+            _items.add(
+                ColoredItem(
+                    // Here the initial state of the MutableTransitionState is set to false, and
+                    // target state is set to true. This will result in an enter transition for
+                    // the newly added item.
+                    MutableTransitionState(false).apply { targetState = true },
+                    lastItemId
+                )
+            )
+        }
+
+        fun removeItem(item: ColoredItem) {
+            // By setting the targetState to false, this will effectively trigger an exit
+            // animation in AnimatedVisibility.
+            item.visible.targetState = false
+        }
+
+        @OptIn(ExperimentalTransitionApi::class)
+        fun pruneItems() {
+            // Inspect the animation status through MutableTransitionState. If isIdle == true,
+            // all animations have finished for the transition.
+            _items.removeAll(
+                items.filter {
+                    // This checks that the animations have finished && the animations are exit
+                    // transitions. In other words, the item has finished animating out.
+                    it.visible.isIdle && !it.visible.targetState
+                }
+            )
+        }
+
+        fun removeAll() {
+            _items.forEach {
+                it.visible.targetState = false
+            }
+        }
+    }
+
+    @OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
+    @Composable
+    fun AnimatedVisibilityInLazyColumn() {
+        Column {
+            val model = remember { MyModel() }
+            Row(Modifier.fillMaxWidth()) {
+                Button({ model.addNewItem() }, modifier = Modifier.padding(15.dp).weight(1f)) {
+                    Text("Add")
+                }
+            }
+
+            // This sets up a flow to check whether any item has finished animating out. If yes,
+            // notify the model to prune the list.
+            LaunchedEffect(model) {
+                snapshotFlow {
+                    model.items.firstOrNull { it.visible.isIdle && !it.visible.targetState }
+                }.collect {
+                    if (it != null) {
+                        model.pruneItems()
+                    }
+                }
+            }
+            LazyColumn {
+                items(model.items, key = { it.itemId }) { item ->
+                    AnimatedVisibility(
+                        item.visible,
+                        enter = expandVertically(),
+                        exit = shrinkVertically()
+                    ) {
+                        Box(Modifier.fillMaxWidth().requiredHeight(90.dp).background(item.color)) {
+                            Button(
+                                { model.removeItem(item) },
+                                modifier = Modifier.align(Alignment.CenterEnd).padding(15.dp)
+                            ) {
+                                Text("Remove")
+                            }
+                        }
+                    }
+                }
+            }
+
+            Button(
+                { model.removeAll() },
+                modifier = Modifier.align(Alignment.End).padding(15.dp)
+            ) {
+                Text("Clear All")
+            }
+        }
+    }
+}
+
+@Sampled
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+fun AVColumnScopeWithMutableTransitionState() {
+    var visible by remember { mutableStateOf(true) }
+    val colors = remember { listOf(Color(0xff2a9d8f), Color(0xffe9c46a), Color(0xfff4a261)) }
+    Column {
+        repeat(3) {
+            AnimatedVisibility(
+                visibleState = remember {
+                    // This sets up the initial state of the AnimatedVisibility to false to
+                    // guarantee an initial enter transition. In contrast, initializing this as
+                    // `MutableTransitionState(visible)` would result in no initial enter
+                    // transition.
+                    MutableTransitionState(initialState = false)
+                }.apply {
+                    // This changes the target state of the visible state. If it's different than
+                    // the initial state, an enter/exit transition will be triggered.
+                    targetState = visible
+                },
+            ) { // Content that needs to appear/disappear goes here:
+                Box(Modifier.fillMaxWidth().height(100.dp).background(colors[it]))
+            }
+        }
+    }
+}
+
+@Sampled
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+fun AnimateEnterExitPartialContent() {
+    @OptIn(ExperimentalAnimationApi::class)
+    @Composable
+    fun FullScreenNotification(visible: Boolean) {
+        AnimatedVisibility(
+            visible = visible,
+            enter = fadeIn(), exit = fadeOut()
+        ) {
+            // Fade in/out the background and foreground
+            Box(Modifier.fillMaxSize().background(Color(0x88000000))) {
+                Box(
+                    Modifier.align(Alignment.TopStart).animateEnterExit(
+                        // Slide in/out the rounded rect
+                        enter = slideInVertically(),
+                        exit = slideOutVertically()
+                    ).clip(RoundedCornerShape(10.dp)).requiredHeight(100.dp)
+                        .fillMaxWidth().background(Color.White)
+                ) {
+                    // Content of the notification goes here
+                }
+            }
+        }
+    }
+}
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
index 056774b..f879f76 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
@@ -16,29 +16,34 @@
 
 package androidx.compose.animation
 
+import androidx.compose.animation.EnterExitState.PostExit
+import androidx.compose.animation.EnterExitState.Visible
+import androidx.compose.animation.core.FastOutLinearInEasing
 import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.InternalAnimationApi
 import androidx.compose.animation.core.LinearOutSlowInEasing
+import androidx.compose.animation.core.MutableTransitionState
 import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.ExperimentalTestApi
-import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
@@ -49,14 +54,13 @@
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 @LargeTest
-@OptIn(ExperimentalTestApi::class)
+@OptIn(ExperimentalTestApi::class, InternalAnimationApi::class)
 class AnimatedVisibilityTest {
 
     @get:Rule
@@ -325,60 +329,181 @@
         }
     }
 
-    @Ignore
-    @OptIn(ExperimentalAnimationApi::class)
+    // Test different animations for fade in and fade out, in a complete run without interruptions
+    @OptIn(ExperimentalAnimationApi::class, InternalAnimationApi::class)
     @Test
     fun animateVisibilityFadeTest() {
         var visible by mutableStateOf(false)
-        val colors = mutableListOf<Int>()
+        val easing = FastOutLinearInEasing
+        val easingOut = FastOutSlowInEasing
+        var alpha by mutableStateOf(0f)
         rule.setContent {
-            Box(Modifier.size(size = 20.dp).background(Color.Black)) {
-                AnimatedVisibility(
-                    visible,
-                    enter = fadeIn(animationSpec = tween(500)),
-                    exit = fadeOut(animationSpec = tween(500)),
-                    modifier = Modifier.testTag("AnimV")
-                ) {
-                    Box(modifier = Modifier.size(size = 20.dp).background(Color.White))
+            AnimatedVisibility(
+                visible,
+                enter = fadeIn(animationSpec = tween(500, easing = easing)),
+                exit = fadeOut(animationSpec = tween(300, easing = easingOut)),
+            ) {
+                Box(modifier = Modifier.size(size = 20.dp).background(Color.White))
+                LaunchedEffect(visible) {
+                    var exit = false
+                    val enterExit = transition
+                    while (true) {
+                        withFrameNanos {
+                            if (enterExit.targetState == Visible) {
+                                alpha = enterExit.animations.firstOrNull {
+                                    it.label == "alpha"
+                                }?.value as Float
+                                val fraction =
+                                    (enterExit.playTimeNanos / 1_000_000) / 500f
+                                if (enterExit.currentState != Visible) {
+                                    assertEquals(easing.transform(fraction), alpha, 0.01f)
+                                } else {
+                                    // When currentState = targetState, the playTime will be reset
+                                    // to 0. So compare alpha against expected visible value.
+                                    assertEquals(1f, alpha)
+                                    exit = true
+                                }
+                            } else if (enterExit.targetState == PostExit) {
+                                alpha = enterExit.animations.firstOrNull {
+                                    it.label == "alpha"
+                                }?.value as Float
+                                val fraction =
+                                    (enterExit.playTimeNanos / 1_000_000) / 300f
+                                if (enterExit.currentState != PostExit) {
+                                    assertEquals(
+                                        1f - easingOut.transform(fraction),
+                                        alpha,
+                                        0.01f
+                                    )
+                                } else {
+                                    // When currentState = targetState, the playTime will be reset
+                                    // to 0. So compare alpha against expected invisible value.
+                                    assertEquals(0f, alpha)
+                                    exit = true
+                                }
+                            } else {
+                                exit = enterExit.currentState == enterExit.targetState
+                            }
+                        }
+                        if (exit) break
+                    }
                 }
             }
         }
         rule.runOnIdle {
             visible = true
         }
-        rule.mainClock.autoAdvance = false
-        while (colors.isEmpty() || colors.last() != 0xffffffff.toInt()) {
-            rule.mainClock.advanceTimeByFrame()
-            rule.onNodeWithTag("AnimV").apply {
-                val data = IntArray(1)
-                data[0] = 0
-                captureToImage().readPixels(data, 10, 10, 1, 1)
-                colors.add(data[0])
-            }
-        }
-        for (i in 1 until colors.size) {
-            // Check every color against the previous one to ensure the alpha is non-decreasing
-            // during fade in.
-            assertTrue(colors[i] >= colors[i - 1])
-        }
-        assertTrue(colors[0] < 0xfffffffff)
-        colors.clear()
         rule.runOnIdle {
+            // At this point fade in has finished, expect alpha = 1
+            assertEquals(1f, alpha)
             visible = false
         }
-        while (colors.isEmpty() || colors.last() != 0xff000000.toInt()) {
-            rule.mainClock.advanceTimeByFrame()
-            rule.onNodeWithTag("AnimV").apply {
-                val data = IntArray(1)
-                data[0] = 0
-                captureToImage().readPixels(data, 10, 10, 1, 1)
-                colors.add(data[0])
+        rule.runOnIdle {
+            // At this point fade out has finished, expect alpha = 0
+            assertEquals(0f, alpha)
+        }
+    }
+
+    @OptIn(ExperimentalAnimationApi::class)
+    @Test
+    fun testEnterTransitionNoneAndExitTransitionNone() {
+        val testModifier by mutableStateOf(TestModifier())
+        val visible = MutableTransitionState(false)
+        var disposed by mutableStateOf(false)
+        rule.mainClock.autoAdvance = false
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                AnimatedVisibility(
+                    visible, testModifier,
+                    enter = EnterTransition.None,
+                    exit = ExitTransition.None
+                ) {
+                    Box(Modifier.requiredSize(100.dp, 100.dp)) {
+                        DisposableEffect(Unit) {
+                            onDispose {
+                                disposed = true
+                            }
+                        }
+                    }
+                }
             }
         }
-        for (i in 1 until colors.size) {
-            // Check every color against the previous one to ensure the alpha is non-increasing
-            // during fade out.
-            assertTrue(colors[i] <= colors[i - 1])
+
+        rule.runOnIdle {
+            assertEquals(0, testModifier.width)
+            assertEquals(0, testModifier.height)
+            visible.targetState = true
+        }
+        rule.mainClock.advanceTimeByFrame()
+        rule.mainClock.advanceTimeByFrame()
+        rule.runOnIdle {
+            assertEquals(100, testModifier.width)
+            assertEquals(100, testModifier.height)
+            assertFalse(disposed)
+            visible.targetState = false
+        }
+        rule.mainClock.advanceTimeByFrame()
+        rule.mainClock.advanceTimeByFrame()
+        rule.runOnIdle {
+            assertTrue(disposed)
+        }
+    }
+
+    private enum class TestState { State1, State2, State3 }
+
+    @OptIn(ExperimentalAnimationApi::class)
+    @Test
+    fun testTransitionExtensionAnimatedVisibility() {
+        val testModifier by mutableStateOf(TestModifier())
+        val testState = mutableStateOf(TestState.State1)
+        var currentState = TestState.State1
+        var disposed by mutableStateOf(false)
+        rule.mainClock.autoAdvance = false
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                val transition = updateTransition(testState.value)
+                currentState = transition.currentState
+                transition.AnimatedVisibility(
+                    // Only visible in State2
+                    visible = { it == TestState.State2 },
+                    modifier = testModifier,
+                    enter = expandIn(animationSpec = tween(100)),
+                    exit = shrinkOut(animationSpec = tween(100))
+                ) {
+                    Box(Modifier.requiredSize(100.dp, 100.dp)) {
+                        DisposableEffect(Unit) {
+                            onDispose {
+                                disposed = true
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertEquals(0, testModifier.width)
+            assertEquals(0, testModifier.height)
+            testState.value = TestState.State2
+        }
+        while (currentState != TestState.State2) {
+            assertTrue(testModifier.width < 100)
+            rule.mainClock.advanceTimeByFrame()
+        }
+        rule.runOnIdle {
+            assertEquals(100, testModifier.width)
+            assertEquals(100, testModifier.height)
+            testState.value = TestState.State3
+        }
+        while (currentState != TestState.State3) {
+            assertTrue(testModifier.width > 0)
+            assertFalse(disposed)
+            rule.mainClock.advanceTimeByFrame()
+        }
+        rule.mainClock.advanceTimeByFrame()
+        rule.runOnIdle {
+            assertEquals(0, testModifier.width)
+            assertEquals(0, testModifier.height)
+            assertTrue(disposed)
         }
     }
 }
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
index 252b4b4..1a8e49a 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
@@ -16,63 +16,87 @@
 
 package androidx.compose.animation
 
+import androidx.compose.animation.EnterExitState.PostExit
+import androidx.compose.animation.EnterExitState.PreEnter
+import androidx.compose.animation.EnterExitState.Visible
+import androidx.compose.animation.core.ExperimentalTransitionApi
+import androidx.compose.animation.core.MutableTransitionState
+import androidx.compose.animation.core.Transition
+import androidx.compose.animation.core.createChildTransition
+import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.RowScope
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.key
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
 import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.util.fastMaxBy
+import kotlinx.coroutines.flow.collect
 
 /**
  * [AnimatedVisibility] composable animates the appearance and disappearance of its content, as
  * [visible] value changes. Different [EnterTransition]s and [ExitTransition]s can be defined in
  * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
- * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
+ * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink, and Slide. The enter transitions
  * and exit transitions can be combined using `+`. The order of the combination does not matter,
  * as the transition animations will start simultaneously. See [EnterTransition] and
- * [ExitTransition] for details on the three types of transition. Here's an example of combining
- * all three types of transitions together:
+ * [ExitTransition] for details on the three types of transition.
+ *
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See the second sample code snippet below for example.
+ * These custom animations will be running alongside of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish before
+ * it considers itself idle. [content] will only be removed after all the (built-in and custom)
+ * exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. If there's a need to observe the state change of the enter/exit
+ * transition and follow up additional action (e.g. remove data, sequential animation, etc),
+ * consider the AnimatedVisibility API variant that takes a [MutableTransitionState] parameter.
+ *
+ * By default, the enter transition will be a combination of [fadeIn] and [expandIn] of the
+ * content from the bottom end. And the exit transition will be shrinking the content towards the
+ * bottom end while fading out (i.e. [fadeOut] + [shrinkOut]). The expanding and shrinking will
+ * likely also animate the parent and siblings if they rely on the size of appearing/disappearing
+ * content. When the [AnimatedVisibility] composable is put in a [Row] or a [Column], the default
+ * enter and exit transitions are tailored to that particular container. See
+ * [RowScope.AnimatedVisibility] and [ColumnScope.AnimatedVisibility] for details.
+ *
+ * Here are two examples of [AnimatedVisibility]: one using the built-in enter/exit transition, the
+ * other using a custom enter/exit animation.
  *
  * @sample androidx.compose.animation.samples.FullyLoadedTransition
  *
- * This composable function creates a custom [Layout] for its content. The size of the custom
- * layout is determined by the largest width and largest height of the children. All children
- * will be arranged in a box (aligned to the top start of the [Layout]).
+ * The example blow shows how a custom enter/exit animation can be created using the Transition
+ * object (i.e. Transition<EnterExitState>) from [AnimatedVisibilityScope].
  *
- * __Note__: Once the exit transition is finished, the [content] composable will be skipped (i.e.
- * the content will be removed from the tree, and disposed).
- *
- * By default, the enter transition will be a combination of fading in and expanding the content in
- * from the bottom end. And the exit transition will be shrinking the content towards the bottom
- * end while fading out. The expanding and shrinking will likely also animate the parent and
- * siblings if they rely on the size of appearing/disappearing content. When the
- * [AnimatedVisibility] composable is put in a [Row] or a [Column], the default enter and exit
- * transitions are tailored to that particular container. See [RowScope.AnimatedVisibility] and
- * [ColumnScope.AnimatedVisibility] for details.
- *
- * [initiallyVisible] defaults to the same value as [visible]. This means when the
- * [AnimatedVisibility] is first added to the tree, there is no appearing animation. If it is
- * desired to show an appearing animation for the first appearance of the content,
- * [initiallyVisible] can be set to false and [visible] to true.
+ * @sample androidx.compose.animation.samples.AnimatedVisibilityWithBooleanVisibleParamNoReceiver
  *
  * @param visible defines whether the content should be visible
  * @param modifier modifier for the [Layout] created to contain the [content]
- * @param enter [EnterTransition]s used for the appearing animation, fading in while expanding by
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding by
  *              default
- * @param exit [ExitTransition](s) used for the disappearing animation, fading out while
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
  *             shrinking by default
- * @param initiallyVisible controls whether the first appearance should be animated, defaulting
- *                         to match [visible] (i.e. not animating the first appearance)
+ * @param content Content to appear or disappear based on the value of [visible]
  *
  * @see EnterTransition
  * @see ExitTransition
@@ -80,8 +104,7 @@
  * @see expandIn
  * @see fadeOut
  * @see shrinkOut
- * @see RowScope.AnimatedVisibility
- * @see ColumnScope.AnimatedVisibility
+ * @see AnimatedVisibilityScope
  */
 @ExperimentalAnimationApi
 @Composable
@@ -90,51 +113,63 @@
     modifier: Modifier = Modifier,
     enter: EnterTransition = fadeIn() + expandIn(),
     exit: ExitTransition = shrinkOut() + fadeOut(),
-    initiallyVisible: Boolean = visible,
-    content: @Composable () -> Unit
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
-    AnimatedVisibilityImpl(visible, modifier, enter, exit, initiallyVisible, content)
+    val transition = updateTransition(visible)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
 }
 
 /**
- * [AnimatedVisibility] composable animates the appearance and disappearance of its content, as
- * [visible] value changes. Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [RowScope.AnimatedVisibility] composable animates the appearance and disappearance of its
+ * content when the [AnimatedVisibility] is in a [Row]. The default animations are tailored
+ * specific to the [Row] layout. See more details below.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
  * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
  * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
  * and exit transitions can be combined using `+`. The order of the combination does not matter,
  * as the transition animations will start simultaneously. See [EnterTransition] and
- * [ExitTransition] for details on the three types of transition. Here's an example of using
- * [RowScope.AnimatedVisibility] in a [Row]:
+ * [ExitTransition] for details on the three types of transition.
  *
- * @sample androidx.compose.animation.samples.AnimatedFloatingActionButton
- *
- * This composable function creates a custom [Layout] for its content. The size of the custom
- * layout is determined by the largest width and largest height of the children. All children
- * will be arranged in a box (aligned to the top start of the [Layout]).
- *
- * __Note__: Once the exit transition is finished, the [content] composable will be skipped (i.e.
- * the content will be removed from the tree, and disposed).
- *
- * By default, the enter transition will be a combination of fading in and expanding the content
- * horizontally. The end of the content will be the leading edge as the content expands to its
- * full width. And the exit transition will be shrinking the content with the end of the
+ * The default [enter] and [exit] transition is configured based on the horizontal layout of a
+ * [Row]. [enter] defaults to a combination of fading in and expanding the content horizontally.
+ * (The end of the content will be the leading edge as the content expands to its
+ * full width.) And [exit] defaults to shrinking the content horizontally with the end of the
  * content being the leading edge while fading out. The expanding and shrinking will likely also
  * animate the parent and siblings in the row since they rely on the size of appearing/disappearing
  * content.
  *
- * [initiallyVisible] defaults to the same value as [visible]. This means when the
- * [AnimatedVisibility] is first added to the tree, there is no appearing animation. If it is
- * desired to show an appearing animation for the first appearance of the content,
- * [initiallyVisible] can be set to false and [visible] to true.
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. If there's a need to observe the state change of the enter/exit
+ * transition and follow up additional action (e.g. remove data, sequential animation, etc),
+ * consider the AnimatedVisibility API variant that takes a [MutableTransitionState] parameter.
+ *
+ * Here's an example of using [RowScope.AnimatedVisibility] in a [Row]:
+ * @sample androidx.compose.animation.samples.AnimatedFloatingActionButton
  *
  * @param visible defines whether the content should be visible
  * @param modifier modifier for the [Layout] created to contain the [content]
- * @param enter [EnterTransition]s used for the appearing animation, fading in while expanding
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
  *              horizontally by default
- * @param exit [ExitTransition](s) used for the disappearing animation, fading out while
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
  *             shrinking horizontally by default
- * @param initiallyVisible controls whether the first appearance should be animated, defaulting
- *                         to match [visible] (i.e. not animating the first appearance)
+ * @param content Content to appear or disappear based on the value of [visible]
  *
  * @see EnterTransition
  * @see ExitTransition
@@ -144,6 +179,7 @@
  * @see shrinkOut
  * @see AnimatedVisibility
  * @see ColumnScope.AnimatedVisibility
+ * @see AnimatedVisibilityScope
  */
 @ExperimentalAnimationApi
 @Composable
@@ -152,51 +188,62 @@
     modifier: Modifier = Modifier,
     enter: EnterTransition = fadeIn() + expandHorizontally(),
     exit: ExitTransition = fadeOut() + shrinkHorizontally(),
-    initiallyVisible: Boolean = visible,
-    content: @Composable () -> Unit
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
-    AnimatedVisibilityImpl(visible, modifier, enter, exit, initiallyVisible, content)
+    val transition = updateTransition(visible)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
 }
 
 /**
- * [AnimatedVisibility] composable animates the appearance and disappearance of its content, as
- * [visible] value changes. Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [ColumnScope.AnimatedVisibility] composable animates the appearance and disappearance of its
+ * content when the [AnimatedVisibility] is in a [Column]. The default animations are tailored
+ * specific to the [Column] layout. See more details below.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
  * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
  * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
  * and exit transitions can be combined using `+`. The order of the combination does not matter,
  * as the transition animations will start simultaneously. See [EnterTransition] and
- * [ExitTransition] for details on the three types of transition. Here's an example of using
- * [ColumnScope.AnimatedVisibility] in a [Column]:
+ * [ExitTransition] for details on the three types of transition.
  *
- * @sample androidx.compose.animation.samples.ColumnAnimatedVisibilitySample
+ * The default [enter] and [exit] transition is configured based on the vertical layout of a
+ * [Column]. [enter] defaults to a combination of fading in and expanding the content vertically.
+ * (The bottom of the content will be the leading edge as the content expands to its full height.)
+ * And the [exit] defaults to shrinking the content vertically with the bottom of the content being
+ * the leading edge while fading out. The expanding and shrinking will likely also animate the
+ * parent and siblings in the column since they rely on the size of appearing/disappearing content.
  *
- * This composable function creates a custom [Layout] for its content. The size of the custom
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
  * layout is determined by the largest width and largest height of the children. All children
- * will be arranged in a box (aligned to the top start of the [Layout]).
+ * will be aligned to the top start of the [Layout].
  *
- * __Note__: Once the exit transition is finished, the [content] composable will be skipped (i.e.
- * the content will be removed from the tree, and disposed).
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. If there's a need to observe the state change of the enter/exit
+ * transition and follow up additional action (e.g. remove data, sequential animation, etc),
+ * consider the AnimatedVisibility API variant that takes a [MutableTransitionState] parameter.
  *
- * By default, the enter transition will be a combination of fading in and expanding the content
- * vertically in the [Column]. The bottom of the content will be the leading edge as the content
- * expands to its full height. And the exit transition will be shrinking the content with the
- * bottom of the content being the leading edge while fading out. The expanding and shrinking will
- * likely also animate the parent and siblings in the column since they rely on the size of
- * appearing/disappearing content.
- *
- * [initiallyVisible] defaults to the same value as [visible]. This means when the
- * [AnimatedVisibility] is first added to the tree, there is no appearing animation. If it is
- * desired to show an appearing animation for the first appearance of the content,
- * [initiallyVisible] can be set to false and [visible] to true.
+ * Here's an example of using [ColumnScope.AnimatedVisibility] in a [Column]:
+ * @sample androidx.compose.animation.samples.ColumnAnimatedVisibilitySample
  *
  * @param visible defines whether the content should be visible
  * @param modifier modifier for the [Layout] created to contain the [content]
- * @param enter [EnterTransition]s used for the appearing animation, fading in while expanding
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
  *              vertically by default
- * @param exit [ExitTransition](s) used for the disappearing animation, fading out while
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
  *             shrinking vertically by default
- * @param initiallyVisible controls whether the first appearance should be animated, defaulting
- *                         to match [visible] (i.e. not animating the first appearance)
+ * @param content Content to appear or disappear based on the value of [visible]
  *
  * @see EnterTransition
  * @see ExitTransition
@@ -205,7 +252,7 @@
  * @see fadeOut
  * @see shrinkOut
  * @see AnimatedVisibility
- * @see ColumnScope.AnimatedVisibility
+ * @see AnimatedVisibilityScope
  */
 @ExperimentalAnimationApi
 @Composable
@@ -214,97 +261,529 @@
     modifier: Modifier = Modifier,
     enter: EnterTransition = fadeIn() + expandVertically(),
     exit: ExitTransition = fadeOut() + shrinkVertically(),
-    initiallyVisible: Boolean = visible,
-    content: @Composable () -> Unit
+    content: @Composable AnimatedVisibilityScope.() -> Unit
 ) {
-    AnimatedVisibilityImpl(visible, modifier, enter, exit, initiallyVisible, content)
+    val transition = updateTransition(visible)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
+}
+
+/**
+ * [EnterExitState] contains the three states that are involved in the enter and exit transition
+ * of [AnimatedVisibility]. More specifically, [PreEnter] and [Visible] defines the initial and
+ * target state of an *enter* transition, whereas [Visible] and [PostExit] are the initial and
+ * target state of an *exit* transition.
+ *
+ * See blow for an example of custom enter/exit animation in [AnimatedVisibility] using
+ * `Transition<EnterExitState>` (i.e. [AnimatedVisibilityScope.transition]):
+ *
+ * @sample androidx.compose.animation.samples.AnimatedVisibilityWithBooleanVisibleParamNoReceiver
+ * @see AnimatedVisibility
+ */
+@ExperimentalAnimationApi
+enum class EnterExitState {
+    /**
+     * The initial state of a custom enter animation in [AnimatedVisibility]..
+     */
+    PreEnter,
+
+    /**
+     * The `Visible` state is the target state of a custom *enter* animation, also the initial
+     * state of a custom *exit* animation in [AnimatedVisibility].
+     */
+    Visible,
+
+    /**
+     * Target state of a custom *exit* animation in [AnimatedVisibility].
+     */
+    PostExit
+}
+
+/**
+ * [AnimatedVisibility] composable animates the appearance and disappearance of its content, as
+ * [visibleState]'s [targetState][MutableTransitionState.targetState] changes. The [visibleState]
+ * can also be used to observe the state of [AnimatedVisibility]. For example:
+ * `visibleState.idIdle` indicates whether the all animations have finished in [AnimatedVisibility],
+ * and `visibleState.currentState` returns the initial state of the current animations.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
+ * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
+ * and exit transitions can be combined using `+`. The order of the combination does not matter,
+ * as the transition animations will start simultaneously. See [EnterTransition] and
+ * [ExitTransition] for details on the three types of transition.
+ *
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. Both `currentState` and `targetState` will be `false` for
+ * [visibleState].
+ *
+ * By default, the enter transition will be a combination of [fadeIn] and [expandIn] of the
+ * content from the bottom end. And the exit transition will be shrinking the content towards the
+ * bottom end while fading out (i.e. [fadeOut] + [shrinkOut]). The expanding and shrinking will
+ * likely also animate the parent and siblings if they rely on the size of appearing/disappearing
+ * content. When the [AnimatedVisibility] composable is put in a [Row] or a [Column], the default
+ * enter and exit transitions are tailored to that particular container. See
+ * [RowScope.AnimatedVisibility] and [ColumnScope.AnimatedVisibility] for details.
+ *
+ * @sample androidx.compose.animation.samples.AnimatedVisibilityLazyColumnSample
+ *
+ * @param visibleState defines whether the content should be visible
+ * @param modifier modifier for the [Layout] created to contain the [content]
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
+ *              vertically by default
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
+ *             shrinking vertically by default
+ * @param content Content to appear or disappear based on the value of [visibleState]
+ *
+ * @see EnterTransition
+ * @see ExitTransition
+ * @see fadeIn
+ * @see expandIn
+ * @see fadeOut
+ * @see shrinkOut
+ * @see AnimatedVisibility
+ * @see Transition.AnimatedVisibility
+ * @see AnimatedVisibilityScope
+ */
+@ExperimentalAnimationApi
+@Composable
+fun AnimatedVisibility(
+    visibleState: MutableTransitionState<Boolean>,
+    modifier: Modifier = Modifier,
+    enter: EnterTransition,
+    exit: ExitTransition,
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    val transition = updateTransition(visibleState)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
+}
+
+/**
+ * [RowScope.AnimatedVisibility] composable animates the appearance and disappearance of its
+ * content as [visibleState]'s [targetState][MutableTransitionState.targetState] changes. The
+ * default [enter] and [exit] transitions are tailored specific to the [Row] layout. See more
+ * details below. The [visibleState] can also be used to observe the state of [AnimatedVisibility].
+ * For example: `visibleState.idIdle` indicates whether the all animations have finished in
+ * [AnimatedVisibility], and `visibleState.currentState` returns the initial state of the current
+ * animations.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
+ * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
+ * and exit transitions can be combined using `+`. The order of the combination does not matter,
+ * as the transition animations will start simultaneously. See [EnterTransition] and
+ * [ExitTransition] for details on the three types of transition.
+ *
+ * The default [enter] and [exit] transition is configured based on the horizontal layout of a
+ * [Row]. [enter] defaults to a combination of fading in and expanding the content horizontally.
+ * (The end of the content will be the leading edge as the content expands to its
+ * full width.) And [exit] defaults to shrinking the content horizontally with the end of the
+ * content being the leading edge while fading out. The expanding and shrinking will likely also
+ * animate the parent and siblings in the row since they rely on the size of appearing/disappearing
+ * content.
+ *
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. Both `currentState` and `targetState` will be `false` for
+ * [visibleState].
+ *
+ * @param visibleState defines whether the content should be visible
+ * @param modifier modifier for the [Layout] created to contain the [content]
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
+ *              vertically by default
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
+ *             shrinking vertically by default
+ * @param content Content to appear or disappear based on the value of [visibleState]
+ *
+ * @see EnterTransition
+ * @see ExitTransition
+ * @see fadeIn
+ * @see expandIn
+ * @see fadeOut
+ * @see shrinkOut
+ * @see AnimatedVisibility
+ * @see Transition.AnimatedVisibility
+ * @see AnimatedVisibilityScope
+ */
+@ExperimentalAnimationApi
+@Composable
+fun RowScope.AnimatedVisibility(
+    visibleState: MutableTransitionState<Boolean>,
+    modifier: Modifier = Modifier,
+    enter: EnterTransition = expandHorizontally() + fadeIn(),
+    exit: ExitTransition = shrinkHorizontally() + fadeOut(),
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    val transition = updateTransition(visibleState)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
+}
+
+/**
+ * [ColumnScope.AnimatedVisibility] composable animates the appearance and disappearance of its
+ * content as [visibleState]'s [targetState][MutableTransitionState.targetState] changes. The
+ * default [enter] and [exit] transitions are tailored specific to the [Column] layout. See more
+ * details below. The [visibleState] can also be used to observe the state of [AnimatedVisibility].
+ * For example: `visibleState.idIdle` indicates whether the all animations have finished in
+ * [AnimatedVisibility], and `visibleState.currentState` returns the initial state of the current
+ * animations.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
+ * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
+ * and exit transitions can be combined using `+`. The order of the combination does not matter,
+ * as the transition animations will start simultaneously. See [EnterTransition] and
+ * [ExitTransition] for details on the three types of transition.
+ *
+ * The default [enter] and [exit] transition is configured based on the vertical layout of a
+ * [Column]. [enter] defaults to a combination of fading in and expanding the content vertically.
+ * (The bottom of the content will be the leading edge as the content expands to its full height.)
+ * And the [exit] defaults to shrinking the content vertically with the bottom of the content being
+ * the leading edge while fading out. The expanding and shrinking will likely also animate the
+ * parent and siblings in the column since they rely on the size of appearing/disappearing content.
+ *
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed. Both `currentState` and `targetState` will be `false` for
+ * [visibleState].
+ *
+ * @sample androidx.compose.animation.samples.AVColumnScopeWithMutableTransitionState
+ *
+ * @param visibleState defines whether the content should be visible
+ * @param modifier modifier for the [Layout] created to contain the [content]
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
+ *              vertically by default
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
+ *             shrinking vertically by default
+ * @param content Content to appear or disappear based on of [visibleState]
+ *
+ * @see EnterTransition
+ * @see ExitTransition
+ * @see fadeIn
+ * @see expandIn
+ * @see fadeOut
+ * @see shrinkOut
+ * @see AnimatedVisibility
+ * @see Transition.AnimatedVisibility
+ * @see AnimatedVisibilityScope
+ */
+@ExperimentalAnimationApi
+@Composable
+fun ColumnScope.AnimatedVisibility(
+    visibleState: MutableTransitionState<Boolean>,
+    modifier: Modifier = Modifier,
+    enter: EnterTransition = expandVertically() + fadeIn(),
+    exit: ExitTransition = shrinkVertically() + fadeOut(),
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    val transition = updateTransition(visibleState)
+    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
+}
+
+/**
+ * This extension function creates an [AnimatedVisibility] composable as a child Transition of
+ * the given Transition. This means: 1) the enter/exit transition is now triggered by the provided
+ * [Transition]'s [targetState][Transition.targetState] change. When the targetState changes, the
+ * visibility will be derived using the [visible] lambda and [Transition.targetState]. 2)
+ * The enter/exit transitions, as well as any custom enter/exit animations defined in
+ * [AnimatedVisibility] are now hoisted to the parent Transition. The parent Transition will wait
+ * for all of them to finish before it considers itself finished (i.e. [Transition.currentState]
+ * = [Transition.targetState]), and subsequently removes the content in the exit case.
+ *
+ * Different [EnterTransition]s and [ExitTransition]s can be defined in
+ * [enter] and [exit] for the appearance and disappearance animation. There are 3 types of
+ * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink and Slide. The enter transitions
+ * and exit transitions can be combined using `+`. The order of the combination does not matter,
+ * as the transition animations will start simultaneously. See [EnterTransition] and
+ * [ExitTransition] for details on the three types of transition.
+ *
+ * Aside from these three types of [EnterTransition] and [ExitTransition], [AnimatedVisibility]
+ * also supports custom enter/exit animations. Some use cases may benefit from custom enter/exit
+ * animations on shape, scale, color, etc. Custom enter/exit animations can be created using the
+ * `Transition<EnterExitState>` object from the [AnimatedVisibilityScope] (i.e.
+ * [AnimatedVisibilityScope.transition]). See [EnterExitState] for an example of custom animations.
+ * These custom animations will be running along side of the built-in animations specified in
+ * [enter] and [exit]. In cases where the enter/exit animation needs to be completely customized,
+ * [enter] and/or [exit] can be specified as [EnterTransition.None] and/or [ExitTransition.None]
+ * as needed. [AnimatedVisibility] will wait until *all* of enter/exit animations to finish
+ * before it considers itself idle. [content] will only be removed after all the (built-in and
+ * custom) exit animations have finished.
+ *
+ * [AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom
+ * layout is determined by the largest width and largest height of the children. All children
+ * will be aligned to the top start of the [Layout].
+ *
+ * __Note__: Once the exit transition is finished, the [content] composable will be removed
+ * from the tree, and disposed.
+ *
+ * By default, the enter transition will be a combination of [fadeIn] and [expandIn] of the
+ * content from the bottom end. And the exit transition will be shrinking the content towards the
+ * bottom end while fading out (i.e. [fadeOut] + [shrinkOut]). The expanding and shrinking will
+ * likely also animate the parent and siblings if they rely on the size of appearing/disappearing
+ * content.
+ *
+ * @sample androidx.compose.animation.samples.AddAnimatedVisibilityToGenericTransitionSample
+ *
+ * @param visible defines whether the content should be visible based on transition state T
+ * @param modifier modifier for the [Layout] created to contain the [content]
+ * @param enter EnterTransition(s) used for the appearing animation, fading in while expanding
+ *              vertically by default
+ * @param exit ExitTransition(s) used for the disappearing animation, fading out while
+ *             shrinking vertically by default
+ * @param content Content to appear or disappear based on the visibility derived from the
+ *                [Transition.targetState] and the provided [visible] lambda
+ *
+ * @see EnterTransition
+ * @see ExitTransition
+ * @see fadeIn
+ * @see expandIn
+ * @see fadeOut
+ * @see shrinkOut
+ * @see AnimatedVisibilityScope
+ * @see Transition.AnimatedVisibility
+ */
+@ExperimentalAnimationApi
+@Composable
+fun <T> Transition<T>.AnimatedVisibility(
+    visible: (T) -> Boolean,
+    modifier: Modifier = Modifier,
+    enter: EnterTransition = fadeIn() + expandIn(),
+    exit: ExitTransition = shrinkOut() + fadeOut(),
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) = AnimatedEnterExitImpl(this, visible, modifier, enter, exit, content)
+
+/**
+ * This is the scope for the content of [AnimatedVisibility]. In this scope, direct and
+ * indirect children of [AnimatedVisibility] will be able to define their own enter/exit
+ * transitions using the built-in options via [Modifier.animateEnterExit]. They will also be able
+ * define custom enter/exit animations using the [transition] object. [AnimatedVisibility] will
+ * ensure both custom and built-in enter/exit animations finish before it considers itself idle,
+ * and subsequently removes its content in the case of exit.
+ *
+ * __Note:__ Custom enter/exit animations that are created *independent* of the
+ * [AnimatedVisibilityScope.transition] will have no guarantee to finish when
+ * exiting, as [AnimatedVisibility] would have no visibility of such animations.
+ *
+ * @sample androidx.compose.animation.samples.AVScopeAnimateEnterExit
+ */
+@ExperimentalAnimationApi
+class AnimatedVisibilityScope internal constructor(transition: Transition<EnterExitState>) {
+    /**
+     * [transition] allows custom enter/exit animations to be specified. It will run simultaneously
+     * with the built-in enter/exit transitions specified in [AnimatedVisibility].
+     */
+    var transition: Transition<EnterExitState> = transition
+        internal set
+
+    /**
+     * [animateEnterExit] modifier can be used for any direct or indirect children of
+     * [AnimatedVisibility] to create a different enter/exit animation than what's specified in
+     * [AnimatedVisibility]. The visual effect of these children will be a combination of the
+     * [AnimatedVisibility]'s animation and their own enter/exit animations.
+     *
+     * [enter] and [exit] defines different [EnterTransition]s and [ExitTransition]s that will be
+     * used for the appearance and disappearance animation. There are 3 types of
+     * [EnterTransition] and [ExitTransition]: Fade, Expand/Shrink, and Slide. The enter transitions
+     * and exit transitions can be combined using `+`. The order of the combination does not matter,
+     * as the transition animations will start simultaneously. See [EnterTransition] and
+     * [ExitTransition] for details on the three types of transition.
+     *
+     * By default, the enter transition will be a combination of [fadeIn] and [expandIn] of the
+     * content from the bottom end. And the exit transition will be shrinking the content towards
+     * the bottom end while fading out (i.e. [fadeOut] + [shrinkOut]). The expanding and shrinking
+     * will likely also animate the parent and siblings if they rely on the size of
+     * appearing/disappearing content.
+     *
+     * In some cases it may be desirable to have [AnimatedVisibility] apply no animation at all for
+     * enter and/or exit, such that children of [AnimatedVisibility] can each have their distinct
+     * animations. To achieve this, [EnterTransition.None] and/or [ExitTransition.None] can be
+     * used for [AnimatedVisibility].
+     *
+     * @sample androidx.compose.animation.samples.AnimateEnterExitPartialContent
+     */
+    fun Modifier.animateEnterExit(
+        enter: EnterTransition = fadeIn() + expandIn(),
+        exit: ExitTransition = fadeOut() + shrinkOut()
+    ): Modifier = composed(
+        inspectorInfo = debugInspectorInfo {
+            name = "animateEnterExit"
+            properties["enter"] = enter
+            properties["exit"] = exit
+        }
+    ) {
+        this.then(transition.createModifier(enter, exit))
+    }
 }
 
 @ExperimentalAnimationApi
 @Composable
-private fun AnimatedVisibilityImpl(
+@Deprecated(
+    "AnimatedVisibility no longer accepts initiallyVisible as a parameter",
+    replaceWith = ReplaceWith(
+        "AnimatedVisibility(" +
+            "transitionState = remember { MutableTransitionState(initiallyVisible) }\n" +
+            ".apply { targetState = visible },\n" +
+            "modifier = modifier,\n" +
+            "enter = enter,\n" +
+            "exit = exit) {\n" +
+            "content() \n" +
+            "}",
+        "androidx.compose.animation.core.MutableTransitionState"
+    )
+)
+fun AnimatedVisibility(
     visible: Boolean,
-    modifier: Modifier,
+    modifier: Modifier = Modifier,
     enter: EnterTransition,
     exit: ExitTransition,
     initiallyVisible: Boolean,
     content: @Composable () -> Unit
+) = AnimatedVisibility(
+    visibleState = remember { MutableTransitionState(initiallyVisible) }
+        .apply { targetState = visible },
+    modifier = modifier,
+    enter = enter,
+    exit = exit
 ) {
+    content()
+}
 
-    // Set up initial transition states, based on the initial visibility.
-    var transitionState by remember {
-        mutableStateOf(if (initiallyVisible) AnimStates.Visible else AnimStates.Gone)
+// RowScope and ColumnScope AnimatedEnterExit extensions and AnimatedEnterExit without a receiver
+// converge here.
+@OptIn(ExperimentalTransitionApi::class)
+@ExperimentalAnimationApi
+@Composable
+private fun <T> AnimatedEnterExitImpl(
+    transition: Transition<T>,
+    visible: (T) -> Boolean,
+    modifier: Modifier,
+    enter: EnterTransition,
+    exit: ExitTransition,
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    val isAnimationVisible = remember(transition) {
+        mutableStateOf(visible(transition.currentState))
     }
-
-    var isAnimating by remember { mutableStateOf(false) }
-
-    // Update transition states, based on the current visibility.
-    if (visible) {
-        if (transitionState == AnimStates.Gone ||
-            transitionState == AnimStates.Exiting
-        ) {
-            transitionState = AnimStates.Entering
-            isAnimating = true
+    if (visible(transition.targetState) || isAnimationVisible.value) {
+        val childTransition = transition.createChildTransition {
+            transition.targetEnterExit(visible, it)
         }
-    } else {
-        if (transitionState == AnimStates.Visible ||
-            transitionState == AnimStates.Entering
-        ) {
-            transitionState = AnimStates.Exiting
-            isAnimating = true
+        LaunchedEffect(childTransition) {
+            snapshotFlow {
+                childTransition.currentState == EnterExitState.Visible ||
+                    childTransition.targetState == EnterExitState.Visible
+            }.collect {
+                isAnimationVisible.value = it
+            }
         }
-    }
 
-    val scope = rememberCoroutineScope()
-    val animations = remember(scope, enter, exit) {
-        // TODO: Should we delay changing enter/exit after on-going animations are finished?
-        TransitionAnimations(enter, exit, scope) {
-            isAnimating = false
-        }
-    }
-    animations.updateState(transitionState)
-
-    // If the exit animation has finished, skip the child composable altogether
-    if (transitionState == AnimStates.Gone) {
-        return
-    }
-
-    Layout(
-        content = content,
-        modifier = modifier.then(animations.modifier)
-    ) { measureables, constraints ->
-
-        val placeables = measureables.map { it.measure(constraints) }
-        val maxWidth: Int = placeables.fastMaxBy { it.width }?.width ?: 0
-        val maxHeight = placeables.fastMaxBy { it.height }?.height ?: 0
-
-        val offset: IntOffset
-        val animatedSize: IntSize
-        val animSize = animations.getAnimatedSize(
-            IntSize(maxWidth, maxHeight)
+        AnimatedEnterExitImpl(
+            childTransition,
+            modifier,
+            enter = enter,
+            exit = exit,
+            content = content
         )
-        if (animSize != null) {
-            offset = animSize.first
-            animatedSize = animSize.second
+    }
+}
+
+@OptIn(ExperimentalTransitionApi::class)
+@ExperimentalAnimationApi
+@Composable
+private inline fun AnimatedEnterExitImpl(
+    transition: Transition<EnterExitState>,
+    modifier: Modifier,
+    enter: EnterTransition,
+    exit: ExitTransition,
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    // TODO: Get some feedback on whether there's a need to observe this state change in user
+    //  code. If there is, this if check will need to be moved to measure stage, along with some
+    //  structural changes.
+    if (transition.currentState == EnterExitState.Visible ||
+        transition.targetState == EnterExitState.Visible
+    ) {
+        val scope = remember(transition) { AnimatedVisibilityScope(transition) }
+        Layout(
+            content = { scope.content() },
+            modifier = modifier.then(transition.createModifier(enter, exit))
+        ) { measureables, constraints ->
+            val placeables = measureables.map { it.measure(constraints) }
+            val maxWidth: Int = placeables.fastMaxBy { it.width }?.width ?: 0
+            val maxHeight = placeables.fastMaxBy { it.height }?.height ?: 0
+            // Position the children.
+            layout(maxWidth, maxHeight) {
+                placeables.fastForEach {
+                    it.place(0, 0)
+                }
+            }
+        }
+    }
+}
+
+// This converts Boolean visible to EnterExitState
+@ExperimentalAnimationApi
+@Composable
+private fun <T> Transition<T>.targetEnterExit(
+    visible: (T) -> Boolean,
+    targetState: T
+): EnterExitState = key(this) {
+    val hasBeenVisible = remember { mutableStateOf(false) }
+    if (visible(currentState)) {
+        hasBeenVisible.value = true
+    }
+    if (visible(targetState)) {
+        EnterExitState.Visible
+    } else {
+        // If never been visible, visible = false means PreEnter, otherwise PostExit
+        if (hasBeenVisible.value) {
+            EnterExitState.PostExit
         } else {
-            offset = IntOffset.Zero
-            animatedSize = IntSize(maxWidth, maxHeight)
-        }
-
-        // If animation has finished update state
-        if (!isAnimating) {
-            if (transitionState == AnimStates.Exiting) {
-                transitionState = AnimStates.Gone
-            } else if (transitionState == AnimStates.Entering) {
-                transitionState = AnimStates.Visible
-            }
-        }
-
-        // Position the children.
-        layout(animatedSize.width, animatedSize.height) {
-            placeables.fastForEach {
-                it.place(offset.x, offset.y)
-            }
+            EnterExitState.PreEnter
         }
     }
 }
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index e1f756b..b869a5e 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -14,16 +14,30 @@
  * limitations under the License.
  */
 
+@file:OptIn(InternalAnimationApi::class, ExperimentalAnimationApi::class)
+
 package androidx.compose.animation
 
-import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.AnimationEndReason
+import android.annotation.SuppressLint
 import androidx.compose.animation.core.AnimationVector2D
 import androidx.compose.animation.core.FiniteAnimationSpec
+import androidx.compose.animation.core.InternalAnimationApi
+import androidx.compose.animation.core.Transition
 import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.createDeferredAnimation
 import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.VisibilityThreshold
+import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.key
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
@@ -37,10 +51,6 @@
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.util.fastFirstOrNull
-import androidx.compose.ui.util.fastForEach
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 
 @RequiresOptIn(message = "This is an experimental animation API.")
 @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
@@ -92,13 +102,24 @@
             )
         )
     }
-    // TODO: Support EnterTransition.None
 
     override fun equals(other: Any?): Boolean {
         return other is EnterTransition && other.data == data
     }
 
     override fun hashCode(): Int = data.hashCode()
+
+    companion object {
+        /**
+         * This can be used when no enter transition is desired. It can be useful in cases where
+         * there are other forms of enter animation defined indirectly for an
+         * [AnimatedVisibility]. e.g.The children of the [AnimatedVisibility] have all defined
+         * their own [EnterTransition], or when the parent is fading in, etc.
+         *
+         * @see [ExitTransition.None]
+         */
+        val None: EnterTransition = EnterTransitionImpl(TransitionData())
+    }
 }
 
 /**
@@ -150,12 +171,26 @@
         )
     }
 
-    // TODO: Support ExitTransition.None
     override fun equals(other: Any?): Boolean {
         return other is ExitTransition && other.data == data
     }
 
     override fun hashCode(): Int = data.hashCode()
+
+    companion object {
+        /**
+         * This can be used when no built-in [ExitTransition] (i.e. fade/slide, etc) is desired for
+         * the [AnimatedVisibility], but rather the children are defining their own exit
+         * animation using the [Transition] scope.
+         *
+         * __Note:__ If [None] is used, and nothing is animating in the Transition<EnterExitState>
+         * scope that [AnimatedVisibility] provided, the content will be removed from
+         * [AnimatedVisibility] right away.
+         *
+         * @sample androidx.compose.animation.samples.AVScopeAnimateEnterExit
+         */
+        val None: ExitTransition = ExitTransitionImpl(TransitionData())
+    }
 }
 
 /**
@@ -556,7 +591,7 @@
  *
  * [targetOffsetX] is a lambda that takes the full width of the content and returns an
  * offset. This allows the target offset to be defined proportional to the full size, or as an
- * absolute value. It defaults to return half of negaive width, which would slide the content to
+ * absolute value. It defaults to return half of negative width, which would slide the content to
  * the left by half of its width.
  *
  * @sample androidx.compose.animation.samples.SlideTransition
@@ -615,7 +650,7 @@
 @Immutable
 internal data class ChangeSize(
     val alignment: Alignment,
-    val startSize: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) },
+    val size: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) },
     val animationSpec: FiniteAnimationSpec<IntSize> = spring(),
     val clip: Boolean = true
 )
@@ -651,517 +686,285 @@
     val changeSize: ChangeSize? = null
 )
 
-/**
- * Alignment does NOT stay consistent in enter vs. exit animations. For example, the enter could be
- * expanding from top, but exit could be shrinking towards the bottom. As a result, when such an
- * animation is interrupted, it becomes very tricky to handle that. This is why there needs to be
- * two types of size animations: alignment based and rect based. When alignment stays the same,
- * size is the only value that needs to be animated. When alignment changes, however, the only
- * sensible solution is to fall back to rect based solution. Namely, this calculates the current
- * clip rect based on alignment and size, and the final rect based on the new alignment and the
- * ending size. In rect based animations, the size will still be animated using the provided size
- * animation, and the offset will be animated using physics as a part of the interruption
- * handling logic.
- */
-internal interface SizeAnimation {
-    val anim: Animatable<IntSize, AnimationVector2D>
-    var clip: Boolean
-    val size: IntSize
-        get() = anim.value
-
-    val offset: (IntSize) -> IntOffset
-    val isAnimating: Boolean
-    val listener: (AnimationEndReason, Any) -> Unit
-
-    /**
-     * The instance returned may be different than the caller if the alignment has changed. Either
-     * way the returned animation will be configured to animate to the new target.
-     */
-    fun animateTo(
-        target: IntSize,
-        alignment: Alignment,
-        fullSize: IntSize,
-        spec: FiniteAnimationSpec<IntSize>,
-        scope: CoroutineScope,
-    ): SizeAnimation
-
-    /**
-     * Returns what the offset will be once the target size is applied.
-     */
-    fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset
-
-    val alignment: Alignment
-}
-
-/**
- * This is the animation class used to animate content size. However, this animation may get
- * interrupted before it finishes. If the new size target is based on the same alignment, this
- * instance can be re-used to handle that interruption. A more complicated and hairy case is when
- * the alignment changes (from top aligned to bottom aligned), in which case we have to fall back
- * to Rect based animation to properly handle the alignment change.
- */
-private class AlignmentBasedSizeAnimation(
-    override val anim: Animatable<IntSize, AnimationVector2D>,
-    override val alignment: Alignment,
-    override var clip: Boolean,
-    override val listener: (AnimationEndReason, Any) -> Unit
-) : SizeAnimation {
-
-    override val offset: (IntSize) -> IntOffset
-        get() = {
-            alignment.align(it, anim.value, LayoutDirection.Ltr)
-        }
-
-    override fun animateTo(
-        target: IntSize,
-        alignment: Alignment,
-        fullSize: IntSize,
-        spec: FiniteAnimationSpec<IntSize>,
-        scope: CoroutineScope,
-    ): SizeAnimation {
-        if (anim.targetValue != target) {
-            scope.launch {
-                anim.animateTo(target, spec)
-                listener(AnimationEndReason.Finished, anim.value)
-            }
-        }
-
-        if (alignment == this.alignment) {
-            return this
-        } else {
-            // Alignment changed
-            val offset = this.offset(fullSize)
-            return RectBasedSizeAnimation(anim, offset, clip, scope, listener)
-        }
-    }
-
-    override fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset {
-        scope.launch {
-            anim.snapTo(target)
-        }
-        return alignment.align(target, target, LayoutDirection.Ltr)
-    }
-
-    override val isAnimating: Boolean
-        get() = anim.isRunning
-}
-
-/**
- * This class animates the rect of the clip bounds, as a fallback for when enter and exit size
- * change animations have different alignment.
- */
-private class RectBasedSizeAnimation(
-    override val anim: Animatable<IntSize, AnimationVector2D>,
-    targetOffset: IntOffset,
-    override var clip: Boolean,
-    val scope: CoroutineScope,
-    override val listener: (AnimationEndReason, Any) -> Unit
-) : SizeAnimation {
-    private val offsetAnim: Animatable<IntOffset, AnimationVector2D>
-
-    init {
-        offsetAnim = Animatable(
-            IntOffset(0, 0), IntOffset.VectorConverter,
-            IntOffset(1, 1)
-        )
-        scope.launch {
-            offsetAnim.animateTo(targetOffset)
-            listener(AnimationEndReason.Finished, offsetAnim.value)
-        }
-    }
-
-    override val alignment: Alignment
-        get() = Alignment.TopStart
-
-    override val offset: (IntSize) -> IntOffset
-        get() = {
-            offsetAnim.value
-        }
-
-    override fun animateTo(
-        target: IntSize,
-        alignment: Alignment,
-        fullSize: IntSize,
-        spec: FiniteAnimationSpec<IntSize>,
-        scope: CoroutineScope,
-    ): SizeAnimation {
-        val targetOffSet = alignment.align(fullSize, target, LayoutDirection.Ltr)
-        if (offsetAnim.targetValue != targetOffSet) {
-            scope.launch {
-                offsetAnim.animateTo(targetOffSet)
-                listener(AnimationEndReason.Finished, offsetAnim.value)
-            }
-        }
-        if (target != anim.targetValue) {
-            scope.launch {
-                anim.animateTo(target, spec)
-                listener(AnimationEndReason.Finished, anim.value)
-            }
-        }
-        return this
-    }
-
-    override fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset {
-        val targetOffSet = alignment.align(target, target, LayoutDirection.Ltr)
-        scope.launch {
-            offsetAnim.snapTo(targetOffSet)
-            anim.snapTo(target)
-        }
-        return targetOffSet
-    }
-
-    override val isAnimating: Boolean
-        get() = (anim.isRunning || offsetAnim.isRunning)
-}
-
-private operator fun IntSize.minus(b: IntSize) =
-    IntSize(width - b.width, height - b.height)
-
-internal interface TransitionAnimation {
-    val isRunning: Boolean
-    var state: AnimStates
-    val modifier: Modifier
-    fun getAnimatedSize(fullSize: IntSize): Pair<IntOffset, IntSize>? = null
-    val listener: (AnimationEndReason, Any) -> Unit
-}
-
-/**
- * This class animates alpha through a graphics layer modifier.
- */
-private class FadeTransition(
-    val enter: Fade? = null,
-    val exit: Fade? = null,
-    val scope: CoroutineScope,
-    override val listener: (AnimationEndReason, Any) -> Unit
-) : TransitionAnimation {
-    override val isRunning: Boolean
-        get() = alphaAnim.isRunning
-    override val modifier: Modifier
-        get() = Modifier.graphicsLayer {
-            alpha = alphaAnim.value
-        }
-
-    override var state: AnimStates = AnimStates.Gone
-        set(value) {
-            if (value == field) {
-                return
-            }
-            // Animation state has changed if we get here.
-            if (value == AnimStates.Entering) {
-                // Animation is interrupted from fade out, now fade in
-                if (alphaAnim.isRunning) {
-                    enter?.apply {
-                        // If fade in animation specified, use that. Otherwise use default.
-                        animateTo(1f, animationSpec, listener)
-                    } ?: animateTo(1f, listener = listener)
-                } else {
-                    // set up initial values for alphaAnimation
-                    enter?.apply {
-                        // If fade in is defined start from pre-defined `alphaFrom`. If no fade in is defined,
-                        // snap the alpha to 1f
-                        alphaAnim = Animatable(alpha, 0.02f)
-                        scope.launch {
-                            alphaAnim.animateTo(1f, animationSpec)
-                            listener(AnimationEndReason.Finished, alphaAnim.value)
-                        }
-                        // If no enter is defined and animation isn't running, snap to alpha = 1
-                    } ?: scope.launch {
-                        alphaAnim.snapTo(1f)
-                    }
-                }
-            } else if (value == AnimStates.Exiting) {
-                if (alphaAnim.isRunning) {
-                    // interrupting alpha animation: directly animating to out value if defined,
-                    // otherwise let the fade-in finish
-                    exit?.apply {
-                        animateTo(alpha, animationSpec, listener)
-                    }
-                } else {
-                    // set up alpha animation to fade out, if fade out is defined
-                    exit?.apply {
-                        animateTo(alpha, animationSpec, listener)
-                    }
-                }
-            }
-            field = value
-        }
-
-    private fun animateTo(
-        target: Float,
-        animationSpec: FiniteAnimationSpec<Float> = spring(visibilityThreshold = 0.02f),
-        listener: (AnimationEndReason, Any) -> Unit
-    ) {
-        scope.launch {
-            alphaAnim.animateTo(target, animationSpec)
-            listener(AnimationEndReason.Finished, alphaAnim.value)
-        }
-    }
-
-    var alphaAnim = Animatable(1f, visibilityThreshold = 0.02f)
-}
-
-private class SlideTransition(
-    val enter: Slide? = null,
-    val exit: Slide? = null,
-    val scope: CoroutineScope,
-    override val listener: (AnimationEndReason, Any) -> Unit
-) : TransitionAnimation {
-    override val isRunning: Boolean
-        get() {
-            if (slideAnim?.isRunning == true) {
-                return true
-            }
-            if (state != currentState) {
-                if (state == AnimStates.Entering && enter != null) {
-                    return true
-                } else if (state == AnimStates.Exiting && exit != null) {
-                    return true
-                }
-            }
-            return false
-        }
-    override var state: AnimStates = AnimStates.Gone
-    var currentState: AnimStates = AnimStates.Gone
-    override val modifier: Modifier = Modifier.composed {
-        SlideModifier()
-    }
-
-    inner class SlideModifier : LayoutModifier {
-        override fun MeasureScope.measure(
-            measurable: Measurable,
-            constraints: Constraints
-        ): MeasureResult {
-            val placeable = measurable.measure(constraints)
-
-            updateAnimation(IntSize(placeable.width, placeable.height))
-            return layout(placeable.width, placeable.height) {
-                placeable.place(slideAnim?.value ?: IntOffset.Zero)
-            }
-        }
-    }
-
-    fun updateAnimation(fullSize: IntSize) {
-        if (state == currentState) {
-            return
-        }
-        // state changed
-        if (state == AnimStates.Entering) {
-            // Animation is interrupted from slide out, now slide in
-            enter?.apply {
-                // If slide in animation specified, use that. Otherwise use default.
-                val anim = if (slideAnim?.isRunning != true) {
-                    Animatable(
-                        slideOffset(fullSize), IntOffset.VectorConverter, IntOffset(1, 1)
-                    )
-                } else {
-                    slideAnim
-                }
-                scope.launch {
-                    anim!!.animateTo(IntOffset.Zero, animationSpec)
-                    listener(AnimationEndReason.Finished, anim.value)
-                }
-                slideAnim = anim
-            } ?: slideAnim?.also {
-                scope.launch {
-                    it.animateTo(IntOffset.Zero)
-                    listener(AnimationEndReason.Finished, it.value)
-                }
-            }
-        } else if (state == AnimStates.Exiting) {
-            // interrupting alpha animation: directly animating to out value if defined,
-            // otherwise let it finish
-            exit?.apply {
-                val anim = slideAnim
-                    ?: Animatable(
-                        IntOffset.Zero, IntOffset.VectorConverter, IntOffset(1, 1)
-                    )
-                scope.launch {
-                    anim.animateTo(slideOffset(fullSize), animationSpec)
-                    listener(AnimationEndReason.Finished, anim.value)
-                }
-                slideAnim = anim
-            }
-        }
-        currentState = state
-    }
-
-    var slideAnim: Animatable<IntOffset, AnimationVector2D>? = null
-}
-
-private class ChangeSizeTransition(
-    val enter: ChangeSize? = null,
-    val exit: ChangeSize? = null,
-    val scope: CoroutineScope,
-    override val listener: (AnimationEndReason, Any) -> Unit
-) : TransitionAnimation {
-
-    override val isRunning: Boolean
-        get() {
-            if (sizeAnim?.isAnimating == true) {
-                return true
-            }
-
-            // If the state has changed, and corresponding animations are defined, then animation
-            // will be running in this current frame in the layout stage.
-            if (state != currentState) {
-                if (state == AnimStates.Entering && enter != null) {
-                    return true
-                } else if (state == AnimStates.Exiting && exit != null) {
-                    return true
-                }
-            }
-            return false
-        }
-
-    // This is the pending state, which sets currentState in layout stage
-    override var state: AnimStates = AnimStates.Gone
-
-    // This tracks the current resolved state. State change happens in composition, but the
-    // resolution happens during layout, since we won't know the size until then.
-    var currentState: AnimStates = AnimStates.Gone
-
-    override fun getAnimatedSize(fullSize: IntSize): Pair<IntOffset, IntSize> {
-        sizeAnim?.apply {
-            if (state == currentState) {
-                // If no state change, return the current size animation value.
-                if (state == AnimStates.Entering) {
-                    animateTo(fullSize, alignment, fullSize, spring(), scope)
-                } else if (state == AnimStates.Visible) {
-                    return snapTo(fullSize, scope) to fullSize
-                }
-                return offset(fullSize) to size
-            }
-        }
-
-        // If we get here, animate state has changed.
-        if (state == AnimStates.Entering) {
-            if (enter != null) {
-                // if no on-going size animation, create a new one.
-                val anim = sizeAnim?.run {
-                    // If the animation is not running and the alignment isn't the same, prefer
-                    // AlignmentBasedSizeAnimation over rect based animation.
-                    if (!isAnimating) {
-                        null
-                    } else {
-                        this
-                    }
-                } ?: AlignmentBasedSizeAnimation(
-                    Animatable(
-                        enter.startSize.invoke(fullSize),
-                        IntSize.VectorConverter,
-                        visibilityThreshold = IntSize(1, 1)
-                    ),
-                    enter.alignment, enter.clip, listener
-                )
-                // Animate to full size
-                sizeAnim = anim.animateTo(
-                    fullSize, enter.alignment, fullSize, enter.animationSpec, scope
-                )
-            } else {
-                // If enter isn't defined for size change, re-target the current animation, if any
-                sizeAnim?.apply {
-                    animateTo(fullSize, alignment, fullSize, spring(), scope)
-                }
-            }
-        } else if (state == AnimStates.Exiting) {
-            exit?.apply {
-                // If a size change exit animation is defined, re-target on-going animation if
-                // any, otherwise create a new one.
-                val anim = sizeAnim?.run {
-                    // If the current size animation is idling, switch to AlignmentBasedAnimation if
-                    // needed.
-                    if (isRunning && alignment != exit.alignment) {
-                        null
-                    } else {
-                        this
-                    }
-                } ?: AlignmentBasedSizeAnimation(
-                    Animatable(fullSize, IntSize.VectorConverter, IntSize(1, 1)),
-                    alignment, clip, listener
-                )
-
-                sizeAnim = anim.animateTo(
-                    startSize(fullSize), alignment, fullSize, animationSpec, scope
-                )
-            }
-            // If exit isn't defined, but the enter animation is still on-going, let it finish
-        }
-        currentState = state
-        return sizeAnim?.run { offset(fullSize) to size } ?: IntOffset.Zero to fullSize
-    }
-
-    override val modifier: Modifier
-        get() {
-            val clip: Boolean = sizeAnim?.clip
-                ?: if (state == AnimStates.Entering) {
-                    enter?.clip
-                } else {
-                    exit?.clip
-                } ?: false
-            return if (clip) Modifier.clipToBounds() else Modifier
-        }
-
-    var sizeAnim: SizeAnimation? = null
-}
-
-@OptIn(ExperimentalAnimationApi::class)
-internal class TransitionAnimations constructor(
+@SuppressLint("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
+@Composable
+internal fun Transition<EnterExitState>.createModifier(
     enter: EnterTransition,
-    exit: ExitTransition,
-    scope: CoroutineScope,
-    onFinished: () -> Unit
-) {
-    // This happens during composition.
-    fun updateState(state: AnimStates) {
-        animations.fastForEach { it.state = state }
-    }
+    exit: ExitTransition
+): Modifier {
 
-    val listener: (AnimationEndReason, Any) -> Unit = { reason, _ ->
-        if (reason == AnimationEndReason.Finished && !isAnimating) {
-            onFinished()
+    // Generates up to 3 modifiers, one for each type of enter/exit transition in the order:
+    // slide then shrink/expand then alpha.
+    var modifier: Modifier = Modifier
+
+    modifier = modifier.slideInOut(
+        this,
+        rememberUpdatedState(enter.data.slide),
+        rememberUpdatedState(exit.data.slide)
+    ).shrinkExpand(
+        this,
+        rememberUpdatedState(enter.data.changeSize),
+        rememberUpdatedState(exit.data.changeSize)
+    )
+
+    // Fade - it's important to put fade in the end. Otherwise fade will clip slide.
+    // We'll animate if at any point during the transition fadeIn/fadeOut becomes non-null. This
+    // would ensure the removal of fadeIn/Out amid a fade animation doesn't result in a jump.
+    var shouldAnimateAlpha by remember(this) { mutableStateOf(false) }
+    if (currentState == targetState) {
+        shouldAnimateAlpha = false
+    } else {
+        if (enter.data.fade != null || exit.data.fade != null) {
+            shouldAnimateAlpha = true
         }
     }
 
-    // This is called after measure before placement.
-    fun getAnimatedSize(fullSize: IntSize): Pair<IntOffset, IntSize>? {
-        animations.fastForEach {
-            val animSize = it.getAnimatedSize(fullSize)
-            if (animSize != null) {
-                return animSize
+    if (shouldAnimateAlpha) {
+        val alpha by animateFloat(
+            transitionSpec = {
+                when {
+                    EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible ->
+                        enter.data.fade?.animationSpec ?: spring()
+                    EnterExitState.Visible isTransitioningTo EnterExitState.PostExit ->
+                        exit.data.fade?.animationSpec ?: spring()
+                    else -> spring()
+                }
+            },
+            label = "alpha"
+        ) {
+            when (it) {
+                EnterExitState.Visible -> 1f
+                EnterExitState.PreEnter -> enter.data.fade?.alpha ?: 1f
+                EnterExitState.PostExit -> exit.data.fade?.alpha ?: 1f
             }
         }
-        return null
+        modifier = modifier.graphicsLayer {
+            this.alpha = alpha
+        }
     }
+    return modifier
+}
 
-    val isAnimating: Boolean
-        get() = animations.fastFirstOrNull { it.isRunning }?.isRunning ?: false
-
-    val animations: List<TransitionAnimation>
-
-    init {
-        animations = mutableListOf()
-        // Only set up animations when either enter or exit transition is defined.
-        if (enter.data.slide != null || exit.data.slide != null) {
-            animations.add(
-                SlideTransition(enter.data.slide, exit.data.slide, scope, listener)
-            )
-        }
-        if (enter.data.changeSize != null || exit.data.changeSize != null) {
-            animations.add(
-                ChangeSizeTransition(enter.data.changeSize, exit.data.changeSize, scope, listener)
-            )
-        }
-        if (enter.data.fade != null || exit.data.fade != null) {
-            animations.add(
-                FadeTransition(enter.data.fade, exit.data.fade, scope, listener)
-            )
+@SuppressLint("ModifierInspectorInfo")
+private fun Modifier.slideInOut(
+    transition: Transition<EnterExitState>,
+    slideIn: State<Slide?>,
+    slideOut: State<Slide?>
+): Modifier = composed {
+    // We'll animate if at any point during the transition slideIn/slideOut becomes non-null. This
+    // would ensure the removal of slideIn/Out amid a slide animation doesn't result in a jump.
+    var shouldAnimate by remember(transition) { mutableStateOf(false) }
+    if (transition.currentState == transition.targetState) {
+        shouldAnimate = false
+    } else {
+        if (slideIn.value != null || slideOut.value != null) {
+            shouldAnimate = true
         }
     }
 
-    val modifier: Modifier
-        get() {
-            var modifier: Modifier = Modifier
-            animations.fastForEach { modifier = modifier.then(it.modifier) }
-            return modifier
+    if (shouldAnimate) {
+        val animation = transition.createDeferredAnimation(IntOffset.VectorConverter, "slide")
+        val modifier = remember(transition) {
+            SlideModifier(animation, slideIn, slideOut)
         }
+        this.then(modifier)
+    } else {
+        this
+    }
+}
+
+private val defaultOffsetAnimationSpec = spring(visibilityThreshold = IntOffset.VisibilityThreshold)
+
+private class SlideModifier(
+    val lazyAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset, AnimationVector2D>,
+    val slideIn: State<Slide?>,
+    val slideOut: State<Slide?>
+) : LayoutModifier {
+    val transitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntOffset> =
+        {
+            when {
+                EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible -> {
+                    slideIn.value?.animationSpec ?: defaultOffsetAnimationSpec
+                }
+                EnterExitState.Visible isTransitioningTo EnterExitState.PostExit -> {
+                    slideOut.value?.animationSpec ?: defaultOffsetAnimationSpec
+                }
+                else -> defaultOffsetAnimationSpec
+            }
+        }
+
+    fun targetValueByState(targetState: EnterExitState, fullSize: IntSize): IntOffset {
+        val preEnter = slideIn.value?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
+        val postExit = slideOut.value?.slideOffset?.invoke(fullSize) ?: IntOffset.Zero
+        return when (targetState) {
+            EnterExitState.Visible -> IntOffset.Zero
+            EnterExitState.PreEnter -> preEnter
+            EnterExitState.PostExit -> postExit
+        }
+    }
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints
+    ): MeasureResult {
+        val placeable = measurable.measure(constraints)
+
+        val measuredSize = IntSize(placeable.width, placeable.height)
+        return layout(placeable.width, placeable.height) {
+            val slideOffset = lazyAnimation.animate(
+                transitionSpec
+            ) {
+                targetValueByState(it, measuredSize)
+            }
+            placeable.placeWithLayer(slideOffset.value)
+        }
+    }
+}
+
+@SuppressLint("ModifierInspectorInfo")
+private fun Modifier.shrinkExpand(
+    transition: Transition<EnterExitState>,
+    expand: State<ChangeSize?>,
+    shrink: State<ChangeSize?>
+): Modifier = composed {
+    // We'll animate if at any point during the transition shrink/expand becomes non-null. This
+    // would ensure the removal of shrink/expand amid a size change animation doesn't result in a
+    // jump.
+    var shouldAnimate by remember(transition) { mutableStateOf(false) }
+    if (transition.currentState == transition.targetState) {
+        shouldAnimate = false
+    } else {
+        if (expand.value != null || shrink.value != null) {
+            shouldAnimate = true
+        }
+    }
+
+    if (shouldAnimate) {
+        val alignment: State<Alignment?> = rememberUpdatedState(
+            with(transition.segment) {
+                EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible
+            }.let {
+                if (it) {
+                    expand.value?.alignment ?: shrink.value?.alignment
+                } else {
+                    shrink.value?.alignment ?: expand.value?.alignment
+                }
+            }
+        )
+        val sizeAnimation = transition.createDeferredAnimation(
+            IntSize.VectorConverter,
+            "shrink/expand"
+        )
+        val offsetAnimation = key(transition.currentState == transition.targetState) {
+            transition.createDeferredAnimation(
+                IntOffset.VectorConverter,
+                "InterruptionHandlingOffset"
+            )
+        }
+
+        val expandShrinkModifier = remember(transition) {
+            ExpandShrinkModifier(
+                sizeAnimation,
+                offsetAnimation,
+                expand,
+                shrink,
+                alignment
+            )
+        }
+
+        if (transition.currentState == transition.targetState) {
+            expandShrinkModifier.currentAlignment = null
+        } else if (expandShrinkModifier.currentAlignment == null) {
+            expandShrinkModifier.currentAlignment = alignment.value ?: Alignment.TopStart
+        }
+        this.clipToBounds().then(expandShrinkModifier)
+    } else {
+        this
+    }
+}
+
+private val defaultSizeAnimationSpec = spring(visibilityThreshold = IntSize.VisibilityThreshold)
+
+private class ExpandShrinkModifier(
+    val sizeAnimation: Transition<EnterExitState>.DeferredAnimation<IntSize, AnimationVector2D>,
+    val offsetAnimation: Transition<EnterExitState>.DeferredAnimation<IntOffset,
+        AnimationVector2D>,
+    val expand: State<ChangeSize?>,
+    val shrink: State<ChangeSize?>,
+    val alignment: State<Alignment?>
+) : LayoutModifier {
+    var currentAlignment: Alignment? = null
+    val sizeTransitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntSize> =
+        {
+            when {
+                EnterExitState.PreEnter isTransitioningTo EnterExitState.Visible ->
+                    expand.value?.animationSpec
+                EnterExitState.Visible isTransitioningTo EnterExitState.PostExit ->
+                    shrink.value?.animationSpec
+                else -> defaultSizeAnimationSpec
+            } ?: defaultSizeAnimationSpec
+        }
+
+    fun sizeByState(targetState: EnterExitState, fullSize: IntSize): IntSize {
+        val preEnterSize = expand.value?.let { it.size(fullSize) } ?: fullSize
+        val postExitSize = shrink.value?.let { it.size(fullSize) } ?: fullSize
+
+        return when (targetState) {
+            EnterExitState.Visible -> fullSize
+            EnterExitState.PreEnter -> preEnterSize
+            EnterExitState.PostExit -> postExitSize
+        }
+    }
+
+    // This offset is only needed when the alignment value changes during the shrink/expand
+    // animation. For example, if user specify an enter that expands from the left, and an exit
+    // that shrinks towards the right, the asymmetric enter/exit will be brittle to interruption.
+    // Hence the following offset animation to smooth over such interruption.
+    fun targetOffsetByState(targetState: EnterExitState, fullSize: IntSize): IntOffset =
+        when {
+            currentAlignment == null -> IntOffset.Zero
+            alignment.value == null -> IntOffset.Zero
+            currentAlignment == alignment.value -> IntOffset.Zero
+            else -> when (targetState) {
+                EnterExitState.Visible -> IntOffset.Zero
+                EnterExitState.PreEnter -> IntOffset.Zero
+                EnterExitState.PostExit -> shrink.value?.let {
+                    val endSize = it.size(fullSize)
+                    val targetOffset = alignment.value!!.align(
+                        fullSize,
+                        endSize,
+                        LayoutDirection.Ltr
+                    )
+                    val currentOffset = currentAlignment!!.align(
+                        fullSize,
+                        endSize,
+                        LayoutDirection.Ltr
+                    )
+                    targetOffset - currentOffset
+                } ?: IntOffset.Zero
+            }
+        }
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints
+    ): MeasureResult {
+        val placeable = measurable.measure(constraints)
+
+        val measuredSize = IntSize(placeable.width, placeable.height)
+        val currentSize = sizeAnimation.animate(sizeTransitionSpec) {
+            sizeByState(it, measuredSize)
+        }.value
+
+        val offsetDelta = offsetAnimation.animate({ defaultOffsetAnimationSpec }) {
+            targetOffsetByState(it, measuredSize)
+        }.value
+
+        val offset =
+            currentAlignment?.align(measuredSize, currentSize, LayoutDirection.Ltr)
+                ?: IntOffset.Zero
+        return layout(currentSize.width, currentSize.height) {
+            placeable.place(offset.x + offsetDelta.x, offset.y + offsetDelta.y)
+        }
+    }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
index 2bb31eb..5e11763 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
@@ -154,13 +154,13 @@
             .scrollBy(y = 103.dp, density = rule.density)
 
         rule.onNodeWithTag("1")
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag("2")
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag("3")
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag("4")
             .assertIsDisplayed()
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyItemStateRestoration.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyItemStateRestoration.kt
index 7f44d31..8604782 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyItemStateRestoration.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyItemStateRestoration.kt
@@ -89,7 +89,7 @@
                 Modifier.requiredSize(20.dp),
                 state = rememberLazyListState().also { state = it }
             ) {
-                items((0..1).toList()) {
+                items((0..10).toList()) {
                     if (it == 0) {
                         realState = rememberSaveable { counter0++ }
                         DisposableEffect(Unit) {
@@ -106,8 +106,11 @@
         rule.runOnIdle {
             assertThat(realState).isEqualTo(1)
             runBlocking {
-                state.scrollToItem(1, 5)
-                state.scrollToItem(1, 6)
+                // we scroll through multiple items to make sure the 0th element is not kept in
+                // the reusable items buffer
+                state.scrollToItem(3)
+                state.scrollToItem(5)
+                state.scrollToItem(8)
             }
         }
 
@@ -185,7 +188,7 @@
                 Modifier.requiredSize(20.dp),
                 state = rememberLazyListState().also { state = it }
             ) {
-                items((0..1).toList()) {
+                items((0..10).toList()) {
                     if (it == 0) {
                         LazyRow {
                             item {
@@ -208,7 +211,11 @@
         rule.runOnIdle {
             assertThat(realState).isEqualTo(1)
             runBlocking {
-                state.scrollToItem(1, 5)
+                // we scroll through multiple items to make sure the 0th element is not kept in
+                // the reusable items buffer
+                state.scrollToItem(3)
+                state.scrollToItem(5)
+                state.scrollToItem(8)
             }
         }
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListHeadersTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListHeadersTest.kt
index 276a499..f50f8e7 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListHeadersTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListHeadersTest.kt
@@ -25,6 +25,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
 import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -162,7 +163,7 @@
             .scrollBy(y = 105.dp, density = rule.density)
 
         rule.onNodeWithTag(firstHeaderTag)
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag(secondHeaderTag)
             .assertIsDisplayed()
@@ -289,7 +290,7 @@
             .scrollBy(x = 105.dp, density = rule.density)
 
         rule.onNodeWithTag(firstHeaderTag)
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag(secondHeaderTag)
             .assertIsDisplayed()
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListSlotsReuseTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListSlotsReuseTest.kt
new file mode 100644
index 0000000..8f626d0
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListSlotsReuseTest.kt
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.lazy
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class LazyListSlotsReuseTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    val itemsSizePx = 30f
+    val itemsSizeDp = with(rule.density) { itemsSizePx.toDp() }
+
+    @Test
+    fun scroll1ItemScrolledOffItemIsKeptForReuse() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState()
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+
+        rule.onNodeWithTag("0")
+            .assertIsDisplayed()
+
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(1)
+            }
+        }
+
+        rule.onNodeWithTag("0")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("1")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun scroll2ItemsScrolledOffItemsAreKeptForReuse() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState()
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+
+        rule.onNodeWithTag("0")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("1")
+            .assertIsDisplayed()
+
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(2)
+            }
+        }
+
+        rule.onNodeWithTag("0")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("1")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("2")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun scroll3Items2OfScrolledOffItemsAreKeptForReuse() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState()
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+
+        rule.onNodeWithTag("0")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("1")
+            .assertIsDisplayed()
+
+        rule.runOnIdle {
+            runBlocking {
+                // after this step 0 and 1 are in reusable buffer
+                state.scrollToItem(2)
+
+                // this step requires one item and will take the last item from the buffer - item
+                // 1 plus will put 2 in the buffer. so expected buffer is items 2 and 0
+                state.scrollToItem(3)
+            }
+        }
+
+        // recycled
+        rule.onNodeWithTag("1")
+            .assertDoesNotExist()
+
+        // in buffer
+        rule.onNodeWithTag("0")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("2")
+            .assertExists()
+            .assertIsNotDisplayed()
+
+        // visible
+        rule.onNodeWithTag("3")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("4")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun doMultipleScrollsOneByOne() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState()
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(1) // buffer is [0]
+                state.scrollToItem(2) // 0 used, buffer is [1]
+                state.scrollToItem(3) // 1 used, buffer is [2]
+                state.scrollToItem(4) // 2 used, buffer is [3]
+            }
+        }
+
+        // recycled
+        rule.onNodeWithTag("0")
+            .assertDoesNotExist()
+        rule.onNodeWithTag("1")
+            .assertDoesNotExist()
+        rule.onNodeWithTag("2")
+            .assertDoesNotExist()
+
+        // in buffer
+        rule.onNodeWithTag("3")
+            .assertExists()
+            .assertIsNotDisplayed()
+
+        // visible
+        rule.onNodeWithTag("4")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("5")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun scrollBackwardOnce() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState(10)
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(8) // buffer is [10, 11]
+            }
+        }
+
+        // in buffer
+        rule.onNodeWithTag("10")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("11")
+            .assertExists()
+            .assertIsNotDisplayed()
+
+        // visible
+        rule.onNodeWithTag("8")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("9")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun scrollBackwardOneByOne() {
+        lateinit var state: LazyListState
+        rule.setContent {
+            state = rememberLazyListState(10)
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(9) // buffer is [11]
+                state.scrollToItem(7) // 11 reused, buffer is [9]
+                state.scrollToItem(6) // 9 reused, buffer is [8]
+            }
+        }
+
+        // in buffer
+        rule.onNodeWithTag("8")
+            .assertExists()
+            .assertIsNotDisplayed()
+
+        // visible
+        rule.onNodeWithTag("6")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("7")
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun scrollingBackReusesTheSameSlot() {
+        lateinit var state: LazyListState
+        var counter0 = 0
+        var counter1 = 10
+        var rememberedValue0 = -1
+        var rememberedValue1 = -1
+        rule.setContent {
+            state = rememberLazyListState()
+            LazyColumn(
+                Modifier.height(itemsSizeDp * 1.5f),
+                state
+            ) {
+                items(100) {
+                    if (it == 0) {
+                        rememberedValue0 = remember { counter0++ }
+                    }
+                    if (it == 1) {
+                        rememberedValue1 = remember { counter1++ }
+                    }
+                    Spacer(Modifier.height(itemsSizeDp).fillParentMaxWidth().testTag("$it"))
+                }
+            }
+        }
+        rule.runOnIdle {
+            runBlocking {
+                state.scrollToItem(2) // buffer is [0, 1]
+                state.scrollToItem(0) // scrolled back, 0 and 1 are reused back. buffer: [2, 3]
+            }
+        }
+
+        rule.runOnIdle {
+            Truth.assertWithMessage("Item 0 restored remembered value is $rememberedValue0")
+                .that(rememberedValue0).isEqualTo(0)
+            Truth.assertWithMessage("Item 1 restored remembered value is $rememberedValue1")
+                .that(rememberedValue1).isEqualTo(10)
+        }
+
+        rule.onNodeWithTag("0")
+            .assertIsDisplayed()
+        rule.onNodeWithTag("1")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("2")
+            .assertExists()
+            .assertIsNotDisplayed()
+        rule.onNodeWithTag("3")
+            .assertExists()
+            .assertIsNotDisplayed()
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
index f4d511a..31062be 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
@@ -237,7 +237,7 @@
             .scrollBy(x = 105.dp, density = rule.density)
 
         rule.onNodeWithTag("1")
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag("2")
             .assertIsDisplayed()
@@ -264,7 +264,7 @@
             .scrollBy(x = 150.dp, density = rule.density)
 
         rule.onNodeWithTag("1")
-            .assertDoesNotExist()
+            .assertIsNotDisplayed()
 
         rule.onNodeWithTag("2")
             .assertIsDisplayed()
@@ -524,10 +524,12 @@
 
     @Test
     fun scrollsLeftInRtl() {
+        lateinit var state: LazyListState
         rule.setContentWithTestViewConfiguration {
             CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
                 Box(Modifier.width(100.dp)) {
-                    LazyRow(Modifier.testTag(LazyListTag)) {
+                    state = rememberLazyListState()
+                    LazyRow(Modifier.testTag(LazyListTag), state) {
                         items(4) {
                             Spacer(
                                 Modifier.width(101.dp).fillParentMaxHeight().testTag("$it")
@@ -541,11 +543,10 @@
         rule.onNodeWithTag(LazyListTag)
             .scrollBy(x = (-150).dp, density = rule.density)
 
-        rule.onNodeWithTag("0")
-            .assertDoesNotExist()
-
-        rule.onNodeWithTag("1")
-            .assertIsDisplayed()
+        rule.runOnIdle {
+            assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+            assertThat(state.firstVisibleItemScrollOffset).isGreaterThan(0)
+        }
     }
 
     @Test
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
index acca6c2..141341d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
@@ -70,7 +70,7 @@
 
     val itemContentFactory = rememberItemContentFactory(stateOfItemsProvider, state)
 
-    val subcomposeLayoutState = remember { SubcomposeLayoutState() }
+    val subcomposeLayoutState = remember { SubcomposeLayoutState(MaxItemsToRetainForReuse) }
     LazyListPrefetcher(state, stateOfItemsProvider, itemContentFactory, subcomposeLayoutState)
 
     SubcomposeLayout(
@@ -184,6 +184,8 @@
     }
 }
 
+private const val MaxItemsToRetainForReuse = 2
+
 /**
  * Platform specific implementation of lazy list prefetching - precomposing next items in
  * advance during the scrolling.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemContentFactory.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemContentFactory.kt
index f32e896..19d0e06 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemContentFactory.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemContentFactory.kt
@@ -100,8 +100,11 @@
         val content: @Composable () -> Unit = @Composable {
             val itemsProvider = itemsProvider.value
             if (index < itemsProvider.itemsCount) {
-                val content = itemsProvider.getContent(index, scope)
-                saveableStateHolder.SaveableStateProvider(key, content)
+                val key = itemsProvider.getKey(index)
+                if (key == this.key) {
+                    val content = itemsProvider.getContent(index, scope)
+                    saveableStateHolder.SaveableStateProvider(key, content)
+                }
             }
         }
     }
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropArchitecture.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropArchitecture.kt
new file mode 100644
index 0000000..566c2ab
--- /dev/null
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropArchitecture.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ktlint-disable indent https://github.com/pinterest/ktlint/issues/967
+// Ignore lint warnings in documentation snippets
+@file:Suppress(
+    "unused", "UNUSED_PARAMETER", "UNUSED_VARIABLE", "UNUSED_ANONYMOUS_PARAMETER",
+    "RedundantSuspendModifier", "CascadeIf", "ClassName", "RemoveExplicitTypeArguments",
+    "ControlFlowWithEmptyBody", "PropertyName", "CanBeParameter"
+)
+
+package androidx.compose.integration.docs.interoperability
+
+import android.content.Context
+import android.os.Bundle
+import android.util.AttributeSet
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.ComposeView
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewmodel.compose.viewModel
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+
+/**
+ * This file lets DevRel track changes to snippets present in
+ * https://developer.android.com/jetpack/compose/interop/compose-in-existing-arch
+ *
+ * No action required if it's modified.
+ */
+
+private object InteropArchitectureSnippet1 {
+    class ExampleActivity : AppCompatActivity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+
+            setContent {
+                MaterialTheme {
+                    Column {
+                        Greeting("user1")
+                        Greeting("user2")
+                    }
+                }
+            }
+        }
+    }
+
+    @Composable
+    fun Greeting(userId: String) {
+        val greetingViewModel: GreetingViewModel = viewModel(
+            factory = GreetingViewModelFactory(userId)
+        )
+        val messageUser by greetingViewModel.message.observeAsState("")
+
+        Text(messageUser)
+    }
+
+    class GreetingViewModel(private val userId: String) : ViewModel() {
+        private val _message = MutableLiveData("Hi $userId")
+        val message: LiveData<String> = _message
+    }
+
+    class GreetingViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
+        @Suppress("UNCHECKED_CAST")
+        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+            return GreetingViewModel(userId) as T
+        }
+    }
+}
+
+private object InteropArchitectureSnippet2 {
+    @Composable
+    fun MyScreen() {
+        NavHost(rememberNavController(), startDestination = "profile/{userId}") {
+            /* ... */
+            composable("profile/{userId}") { backStackEntry ->
+                Greeting(backStackEntry.arguments?.getString("userId") ?: "")
+            }
+        }
+    }
+
+    @Composable
+    fun Greeting(userId: String) {
+        val greetingViewModel: GreetingViewModel = viewModel(
+            factory = GreetingViewModelFactory(userId)
+        )
+        val messageUser by greetingViewModel.message.observeAsState("")
+
+        Text(messageUser)
+    }
+}
+
+private object InteropArchitectureSnippet3 {
+    @Composable
+    fun BackHandler(
+        enabled: Boolean,
+        backDispatcher: OnBackPressedDispatcher,
+        onBack: () -> Unit
+    ) {
+
+        // Safely update the current `onBack` lambda when a new one is provided
+        val currentOnBack by rememberUpdatedState(onBack)
+
+        // Remember in Composition a back callback that calls the `onBack` lambda
+        val backCallback = remember {
+            // Always intercept back events. See the SideEffect for a more complete version
+            object : OnBackPressedCallback(true) {
+                override fun handleOnBackPressed() {
+                    currentOnBack()
+                }
+            }
+        }
+
+        // On every successful composition, update the callback with the `enabled` value
+        // to tell `backCallback` whether back events should be intercepted or not
+        SideEffect {
+            backCallback.isEnabled = enabled
+        }
+
+        // If `backDispatcher` changes, dispose and reset the effect
+        DisposableEffect(backDispatcher) {
+            // Add callback to the backDispatcher
+            backDispatcher.addCallback(backCallback)
+
+            // When the effect leaves the Composition, remove the callback
+            onDispose {
+                backCallback.remove()
+            }
+        }
+    }
+}
+
+private object InteropArchitectureSnippet4 {
+    class CustomViewGroup @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyle: Int = 0
+    ) : LinearLayout(context, attrs, defStyle) {
+
+        // Source of truth in the View system as mutableStateOf
+        // to make it thread-safe for Compose
+        private var text by mutableStateOf("")
+
+        private val textView: TextView
+
+        init {
+            orientation = VERTICAL
+
+            textView = TextView(context)
+            val composeView = ComposeView(context).apply {
+                setContent {
+                    MaterialTheme {
+                        TextField(value = text, onValueChange = { updateState(it) })
+                    }
+                }
+            }
+
+            addView(textView)
+            addView(composeView)
+        }
+
+        // Update both the source of truth and the TextView
+        private fun updateState(newValue: String) {
+            text = newValue
+            textView.text = newValue
+        }
+    }
+}
+
+/*
+Fakes needed for snippets to build:
+ */
+
+private class GreetingViewModel(userId: String) : ViewModel() {
+    val _message = MutableLiveData("")
+    val message: LiveData<String> = _message
+}
+private class GreetingViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+        return GreetingViewModel(userId) as T
+    }
+}
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropUi.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropUi.kt
new file mode 100644
index 0000000..5dc4770
--- /dev/null
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/InteropUi.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ktlint-disable indent https://github.com/pinterest/ktlint/issues/967
+// Ignore lint warnings in documentation snippets
+@file:Suppress(
+    "unused", "UNUSED_PARAMETER", "UNUSED_VARIABLE", "UNUSED_ANONYMOUS_PARAMETER",
+    "RedundantSuspendModifier", "CascadeIf", "ClassName", "RemoveExplicitTypeArguments",
+    "ControlFlowWithEmptyBody", "PropertyName", "CanBeParameter", "PackageDirectoryMismatch"
+)
+
+package androidx.compose.integration.docs.interoperabilityui
+
+import android.app.Activity
+import android.content.Context
+import android.os.Bundle
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonDefaults
+import androidx.compose.material.FloatingActionButton
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.AbstractComposeView
+import androidx.compose.ui.unit.dp
+
+/**
+ * This file lets DevRel track changes to snippets present in
+ * https://developer.android.com/jetpack/compose/interop/compose-in-existing-ui
+ *
+ * No action required if it's modified.
+ */
+
+private object InteropUiSnippet1 {
+    @Composable
+    fun CallToActionButton(
+        text: String,
+        onClick: () -> Unit,
+        modifier: Modifier = Modifier,
+    ) {
+        Button(
+            colors = ButtonDefaults.buttonColors(
+                backgroundColor = MaterialTheme.colors.secondary
+            ),
+            onClick = onClick,
+            modifier = modifier,
+        ) {
+            Text(text)
+        }
+    }
+
+    class CallToActionViewButton @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null,
+        defStyle: Int = 0
+    ) : AbstractComposeView(context, attrs, defStyle) {
+
+        var text by mutableStateOf<String>("")
+        var onClick by mutableStateOf<() -> Unit>({})
+
+        @Composable
+        override fun Content() {
+            YourAppTheme {
+                CallToActionButton(text, onClick)
+            }
+        }
+    }
+}
+
+private object InteropUiSnippet2 {
+    class ExampleActivity : Activity() {
+
+        private lateinit var binding: ActivityExampleBinding
+
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+            binding = ActivityExampleBinding.inflate(layoutInflater)
+            setContentView(binding.root)
+
+            binding.callToAction.apply {
+                text = getString(R.string.something)
+                onClick = { /* Do something */ }
+            }
+        }
+    }
+}
+
+private object InteropUiSnippet3 {
+    // import com.google.android.material.composethemeadapter.MdcTheme
+
+    class ExampleActivity : AppCompatActivity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+
+            setContent {
+                // Use MdcTheme instead of MaterialTheme
+                // Colors, typography, and shape have been read from the
+                // View-based theme used in this Activity
+                MdcTheme {
+                    ExampleComposable(/*...*/)
+                }
+            }
+        }
+    }
+}
+
+private object InteropUiSnippet4 {
+    class ExampleActivity : AppCompatActivity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+
+            setContent {
+                AppCompatTheme {
+                    // Colors, typography, and shape have been read from the
+                    // View-based theme used in this Activity
+                    ExampleComposable(/*...*/)
+                }
+            }
+        }
+    }
+}
+
+private object InteropUiSnippet5 {
+    class ExampleActivity : AppCompatActivity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+
+            WindowCompat.setDecorFitsSystemWindows(window, false)
+
+            setContent {
+                MaterialTheme {
+                    ProvideWindowInsets {
+                        MyScreen()
+                    }
+                }
+            }
+        }
+    }
+
+    @Composable
+    fun MyScreen() {
+        Box {
+            FloatingActionButton(
+                modifier = Modifier
+                    .align(Alignment.BottomEnd)
+                    .padding(16.dp) // normal 16dp of padding for FABs
+                    .navigationBarsPadding(), // Move it out from under the nav bar
+                onClick = { }
+            ) {
+                Icon( /* ... */)
+            }
+        }
+    }
+}
+
+private object InteropUiSnippet6 {
+    @Composable
+    fun MyComposable() {
+        BoxWithConstraints {
+            if (minWidth < 480.dp) {
+                /* Show grid with 4 columns */
+            } else if (minWidth < 720.dp) {
+                /* Show grid with 8 columns */
+            } else {
+                /* Show grid with 12 columns */
+            }
+        }
+    }
+}
+
+/*
+Fakes needed for snippets to build:
+ */
+
+private object R {
+    object string {
+        const val something = 1
+    }
+}
+
+private fun ExampleComposable() {}
+@Composable
+private fun MdcTheme(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun AppCompatTheme(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun BlueTheme(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun PinkTheme(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun YourAppTheme(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun ProvideWindowInsets(content: @Composable () -> Unit) {
+}
+
+@Composable
+private fun Icon() {
+}
+
+private class WindowCompat {
+    companion object {
+        fun setDecorFitsSystemWindows(window: Any, bool: Boolean) {}
+    }
+}
+
+private fun Modifier.navigationBarsPadding(): Modifier = this
+
+private class ActivityExampleBinding {
+    val root: Int = 0
+    lateinit var callToAction: InteropUiSnippet1.CallToActionViewButton
+    companion object {
+        fun inflate(li: LayoutInflater): ActivityExampleBinding { TODO() }
+    }
+}
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/Interoperability.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/Interoperability.kt
index ab8da92..82f2c4a 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/Interoperability.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/interoperability/Interoperability.kt
@@ -24,7 +24,6 @@
 
 package androidx.compose.integration.docs.interoperability
 
-import android.app.Activity
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -32,58 +31,36 @@
 import android.graphics.Bitmap
 import android.graphics.Color
 import android.os.Bundle
-import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.activity.OnBackPressedCallback
-import androidx.activity.OnBackPressedDispatcher
 import androidx.activity.compose.setContent
 import androidx.appcompat.app.AppCompatActivity
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
 import androidx.compose.integration.docs.databinding.ExampleLayoutBinding
 import androidx.compose.material.Button
-import androidx.compose.material.ButtonDefaults
-import androidx.compose.material.FloatingActionButton
 import androidx.compose.material.MaterialTheme
 import androidx.compose.material.Text
-import androidx.compose.material.TextField
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.AbstractComposeView
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.compose.ui.viewinterop.AndroidViewBinding
-import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.viewmodel.compose.viewModel
-import androidx.navigation.compose.NavHost
-import androidx.navigation.compose.composable
-import androidx.navigation.compose.rememberNavController
 
 /**
  * This file lets DevRel track changes to snippets present in
- * https://developer.android.com/jetpack/compose/interop
+ * https://developer.android.com/jetpack/compose/interop/interop-apis
  *
  * No action required if it's modified.
  */
@@ -251,274 +228,6 @@
     }
 }
 
-private object InteropSnippet9 {
-    // import com.google.android.material.composethemeadapter.MdcTheme
-
-    class ExampleActivity : AppCompatActivity() {
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-
-            setContent {
-                // Use MdcTheme instead of MaterialTheme
-                // Colors, typography, and shape have been read from the
-                // View-based theme used in this Activity
-                MdcTheme {
-                    ExampleComposable(/*...*/)
-                }
-            }
-        }
-    }
-}
-
-private object InteropSnippet10 {
-    class ExampleActivity : AppCompatActivity() {
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-
-            setContent {
-                AppCompatTheme {
-                    // Colors, typography, and shape have been read from the
-                    // View-based theme used in this Activity
-                    ExampleComposable(/*...*/)
-                }
-            }
-        }
-    }
-}
-
-private object InteropSnippet11 {
-    class ExampleActivity : AppCompatActivity() {
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-
-            WindowCompat.setDecorFitsSystemWindows(window, false)
-
-            setContent {
-                MaterialTheme {
-                    ProvideWindowInsets {
-                        MyScreen()
-                    }
-                }
-            }
-        }
-    }
-
-    @Composable
-    fun MyScreen() {
-        Box {
-            FloatingActionButton(
-                modifier = Modifier
-                    .align(Alignment.BottomEnd)
-                    .padding(16.dp) // normal 16dp of padding for FABs
-                    .navigationBarsPadding(), // Move it out from under the nav bar
-                onClick = { }
-            ) {
-                Icon( /* ... */)
-            }
-        }
-    }
-}
-
-private object InteropSnippet12 {
-    @Composable
-    fun MyComposable() {
-        BoxWithConstraints {
-            if (minWidth < 480.dp) {
-                /* Show grid with 4 columns */
-            } else if (minWidth < 720.dp) {
-                /* Show grid with 8 columns */
-            } else {
-                /* Show grid with 12 columns */
-            }
-        }
-    }
-}
-
-private object InteropSnippet13 {
-    class ExampleActivity : AppCompatActivity() {
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-
-            setContent {
-                MaterialTheme {
-                    Column {
-                        Greeting("user1")
-                        Greeting("user2")
-                    }
-                }
-            }
-        }
-    }
-
-    @Composable
-    fun Greeting(userId: String) {
-        val greetingViewModel: GreetingViewModel = viewModel(
-            factory = GreetingViewModelFactory(userId)
-        )
-        val messageUser by greetingViewModel.message.observeAsState("")
-
-        Text(messageUser)
-    }
-
-    class GreetingViewModel(private val userId: String) : ViewModel() {
-        private val _message = MutableLiveData("Hi $userId")
-        val message: LiveData<String> = _message
-    }
-}
-
-private object InteropSnippet14 {
-    @Composable
-    fun MyScreen() {
-        NavHost(rememberNavController(), startDestination = "profile/{userId}") {
-            /* ... */
-            composable("profile/{userId}") { backStackEntry ->
-                Greeting(backStackEntry.arguments?.getString("userId") ?: "")
-            }
-        }
-    }
-
-    @Composable
-    fun Greeting(userId: String) {
-        val greetingViewModel: GreetingViewModel = viewModel(
-            factory = GreetingViewModelFactory(userId)
-        )
-        val messageUser by greetingViewModel.message.observeAsState("")
-
-        Text(messageUser)
-    }
-}
-
-private object InteropSnippet15 {
-    @Composable
-    fun BackHandler(
-        enabled: Boolean,
-        backDispatcher: OnBackPressedDispatcher,
-        onBack: () -> Unit
-    ) {
-
-        // Safely update the current `onBack` lambda when a new one is provided
-        val currentOnBack by rememberUpdatedState(onBack)
-
-        // Remember in Composition a back callback that calls the `onBack` lambda
-        val backCallback = remember {
-            // Always intercept back events. See the SideEffect for a more complete version
-            object : OnBackPressedCallback(true) {
-                override fun handleOnBackPressed() {
-                    currentOnBack()
-                }
-            }
-        }
-
-        // On every successful composition, update the callback with the `enabled` value
-        // to tell `backCallback` whether back events should be intercepted or not
-        SideEffect {
-            backCallback.isEnabled = enabled
-        }
-
-        // If `backDispatcher` changes, dispose and reset the effect
-        DisposableEffect(backDispatcher) {
-            // Add callback to the backDispatcher
-            backDispatcher.addCallback(backCallback)
-
-            // When the effect leaves the Composition, remove the callback
-            onDispose {
-                backCallback.remove()
-            }
-        }
-    }
-}
-
-private object InteropSnippet16 {
-    class CustomViewGroup @JvmOverloads constructor(
-        context: Context,
-        attrs: AttributeSet? = null,
-        defStyle: Int = 0
-    ) : LinearLayout(context, attrs, defStyle) {
-
-        // Source of truth in the View system as mutableStateOf
-        // to make it thread-safe for Compose
-        private var text by mutableStateOf("")
-
-        private val textView: TextView
-
-        init {
-            orientation = VERTICAL
-
-            textView = TextView(context)
-            val composeView = ComposeView(context).apply {
-                setContent {
-                    MaterialTheme {
-                        TextField(value = text, onValueChange = { updateState(it) })
-                    }
-                }
-            }
-
-            addView(textView)
-            addView(composeView)
-        }
-
-        // Update both the source of truth and the TextView
-        private fun updateState(newValue: String) {
-            text = newValue
-            textView.text = newValue
-        }
-    }
-}
-
-private object InteropSnippet17 {
-    @Composable
-    fun CallToActionButton(
-        text: String,
-        onClick: () -> Unit,
-        modifier: Modifier = Modifier,
-    ) {
-        Button(
-            colors = ButtonDefaults.buttonColors(
-                backgroundColor = MaterialTheme.colors.secondary
-            ),
-            onClick = onClick,
-            modifier = modifier,
-        ) {
-            Text(text)
-        }
-    }
-
-    class CallToActionViewButton @JvmOverloads constructor(
-        context: Context,
-        attrs: AttributeSet? = null,
-        defStyle: Int = 0
-    ) : AbstractComposeView(context, attrs, defStyle) {
-
-        var text by mutableStateOf<String>("")
-        var onClick by mutableStateOf<() -> Unit>({})
-
-        @Composable
-        override fun Content() {
-            YourAppTheme {
-                CallToActionButton(text, onClick)
-            }
-        }
-    }
-}
-
-private object InteropSnippet18 {
-    class ExampleActivity : Activity() {
-
-        private lateinit var binding: ActivityExampleBinding
-
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-            binding = ActivityExampleBinding.inflate(layoutInflater)
-            setContentView(binding.root)
-
-            binding.callToAction.apply {
-                text = getString(R.string.something)
-                onClick = { /* Do something */ }
-            }
-        }
-    }
-}
-
 private object InteropSnippet19 {
     @Composable
     fun SystemBroadcastReceiver(
@@ -578,19 +287,18 @@
     object string {
         const val ok = 4
         const val plane_description = 5
-        const val something = 6
     }
 
     object dimen {
-        const val padding_small = 7
+        const val padding_small = 6
     }
 
     object drawable {
-        const val ic_plane = 8
+        const val ic_plane = 7
     }
 
     object color {
-        const val Blue700 = 9
+        const val Blue700 = 8
     }
 }
 
@@ -605,7 +313,7 @@
 
 private val data = DataExample()
 private fun startActivity(): Nothing = TODO()
-class ExampleViewModel : ViewModel() {
+private class ExampleViewModel : ViewModel() {
     val exampleLiveData = MutableLiveData(" ")
 }
 
@@ -627,35 +335,6 @@
     fun into(listener: ExampleImageLoader.Listener) {}
 }
 
-private fun ExampleComposable() {}
-@Composable
-private fun MdcTheme(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun AppCompatTheme(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun BlueTheme(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun PinkTheme(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun YourAppTheme(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun ProvideWindowInsets(content: @Composable () -> Unit) {
-}
-
-@Composable
-private fun Icon() {
-}
-
 private open class Fragment {
 
     lateinit var context: Context
@@ -669,28 +348,3 @@
 
     fun requireContext(): Context = TODO()
 }
-
-private class WindowCompat {
-    companion object {
-        fun setDecorFitsSystemWindows(window: Any, bool: Boolean) {}
-    }
-}
-
-private fun Modifier.navigationBarsPadding(): Modifier = this
-
-private class GreetingViewModel : ViewModel() {
-    val _message = MutableLiveData("")
-    val message: LiveData<String> = _message
-}
-private class GreetingViewModelFactory(val userId: String) : ViewModelProvider.Factory {
-    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
-        TODO("Not yet implemented")
-    }
-}
-private class ActivityExampleBinding {
-    val root: Int = 0
-    lateinit var callToAction: InteropSnippet17.CallToActionViewButton
-    companion object {
-        fun inflate(li: LayoutInflater): ActivityExampleBinding { TODO() }
-    }
-}
\ No newline at end of file
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateHolder.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateHolder.kt
index f9f5377..30224a5 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateHolder.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateHolder.kt
@@ -17,9 +17,9 @@
 package androidx.compose.runtime.saveable
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.key
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.ReusableContent
 import androidx.compose.runtime.remember
 
 /**
@@ -73,7 +73,7 @@
 
     @Composable
     override fun SaveableStateProvider(key: Any, content: @Composable () -> Unit) {
-        key(key) {
+        ReusableContent(key) {
             val registryHolder = remember {
                 require(parentSaveableStateRegistry?.canBeSaved(key) ?: true) {
                     "Type of the key $key is not supported. On Android you can only use types " +
@@ -85,7 +85,7 @@
                 LocalSaveableStateRegistry provides registryHolder.registry,
                 content = content
             )
-            DisposableEffect(key) {
+            DisposableEffect(Unit) {
                 require(key !in registryHolders) { "Key $key was used multiple times " }
                 savedStates -= key
                 registryHolders[key] = registryHolder
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/TypefaceAdapter.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/TypefaceAdapter.android.kt
index 188825d..85d8bcf 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/TypefaceAdapter.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/TypefaceAdapter.android.kt
@@ -248,7 +248,7 @@
                 else -> throw IllegalStateException("Unknown font type: $font")
             }
         } catch (e: Exception) {
-            throw IllegalStateException("Cannot create Typeface from $font")
+            throw IllegalStateException("Cannot create Typeface from $font", e)
         }
 
         val loadedFontIsSameAsRequest = fontWeight == font.weight && fontStyle == font.style
diff --git a/compose/ui/ui-tooling/api/1.0.0-beta07.txt b/compose/ui/ui-tooling/api/1.0.0-beta07.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/1.0.0-beta07.txt
+++ b/compose/ui/ui-tooling/api/1.0.0-beta07.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/api/current.ignore b/compose/ui/ui-tooling/api/current.ignore
new file mode 100644
index 0000000..050747e
--- /dev/null
+++ b/compose/ui/ui-tooling/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedPackage: androidx.compose.ui.tooling.inspector:
+    Removed package androidx.compose.ui.tooling.inspector
diff --git a/compose/ui/ui-tooling/api/current.txt b/compose/ui/ui-tooling/api/current.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/current.txt
+++ b/compose/ui/ui-tooling/api/current.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/api/public_plus_experimental_1.0.0-beta07.txt b/compose/ui/ui-tooling/api/public_plus_experimental_1.0.0-beta07.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/public_plus_experimental_1.0.0-beta07.txt
+++ b/compose/ui/ui-tooling/api/public_plus_experimental_1.0.0-beta07.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/api/restricted_1.0.0-beta07.txt b/compose/ui/ui-tooling/api/restricted_1.0.0-beta07.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/restricted_1.0.0-beta07.txt
+++ b/compose/ui/ui-tooling/api/restricted_1.0.0-beta07.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/api/restricted_current.ignore b/compose/ui/ui-tooling/api/restricted_current.ignore
new file mode 100644
index 0000000..050747e
--- /dev/null
+++ b/compose/ui/ui-tooling/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedPackage: androidx.compose.ui.tooling.inspector:
+    Removed package androidx.compose.ui.tooling.inspector
diff --git a/compose/ui/ui-tooling/api/restricted_current.txt b/compose/ui/ui-tooling/api/restricted_current.txt
index e392e95..1789ce2 100644
--- a/compose/ui/ui-tooling/api/restricted_current.txt
+++ b/compose/ui/ui-tooling/api/restricted_current.txt
@@ -7,95 +7,6 @@
 
 }
 
-package androidx.compose.ui.tooling.inspector {
-
-  public final class InspectorNode {
-    method public int[] getBounds();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> getChildren();
-    method public String getFileName();
-    method public int getHeight();
-    method public long getId();
-    method public int getLeft();
-    method public int getLength();
-    method public int getLineNumber();
-    method public String getName();
-    method public int getOffset();
-    method public int getPackageHash();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> getParameters();
-    method public int getTop();
-    method public int getWidth();
-    property public final int[] bounds;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> children;
-    property public final String fileName;
-    property public final int height;
-    property public final long id;
-    property public final int left;
-    property public final int length;
-    property public final int lineNumber;
-    property public final String name;
-    property public final int offset;
-    property public final int packageHash;
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.RawParameter> parameters;
-    property public final int top;
-    property public final int width;
-  }
-
-  public final class InspectorNodeKt {
-  }
-
-  public final class LayoutInspectorTree {
-    ctor public LayoutInspectorTree();
-    method public java.util.List<androidx.compose.ui.tooling.inspector.InspectorNode> convert(android.view.View view);
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> convertParameters(androidx.compose.ui.tooling.inspector.InspectorNode node);
-    method public boolean getHideSystemNodes();
-    method public void resetGeneratedId();
-    method public void setHideSystemNodes(boolean p);
-    property public final boolean hideSystemNodes;
-  }
-
-  public final class LayoutInspectorTreeKt {
-  }
-
-  public final class NodeParameter {
-    method public java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> getElements();
-    method public String getName();
-    method public androidx.compose.ui.tooling.inspector.ParameterType getType();
-    method public Object? getValue();
-    property public final java.util.List<androidx.compose.ui.tooling.inspector.NodeParameter> elements;
-    property public final String name;
-    property public final androidx.compose.ui.tooling.inspector.ParameterType type;
-    property public final Object? value;
-  }
-
-  public final class ParameterFactoryKt {
-  }
-
-  public enum ParameterType {
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Boolean;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Color;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionDp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionEm;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType DimensionSp;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Double;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Float;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType FunctionReference;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int32;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Int64;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Lambda;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType Resource;
-    enum_constant public static final androidx.compose.ui.tooling.inspector.ParameterType String;
-  }
-
-  public final class RawParameter {
-    ctor public RawParameter(String name, Object? value);
-    method public String getName();
-    method public Object? getValue();
-    property public final String name;
-    property public final Object? value;
-  }
-
-}
-
 package androidx.compose.ui.tooling.preview {
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt
deleted file mode 100644
index 57ae98f..0000000
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/InlineClassConverterTest.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import androidx.compose.material.Surface
-import androidx.compose.material.Text
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.tooling.CompositionDataRecord
-import androidx.compose.ui.tooling.Inspectable
-import androidx.compose.ui.tooling.ToolingTest
-import androidx.compose.ui.tooling.data.Group
-import androidx.compose.ui.tooling.data.UiToolingDataApi
-import androidx.compose.ui.tooling.data.asTree
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.sp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-@OptIn(UiToolingDataApi::class)
-class InlineClassConverterTest : ToolingTest() {
-
-    @Test
-    fun parameterValueTest() {
-        val slotTableRecord = CompositionDataRecord.create()
-        show {
-            Inspectable(slotTableRecord) {
-                Surface {
-                    Text(text = "OK", fontSize = 12.sp)
-                }
-            }
-        }
-
-        val tree = slotTableRecord.store.first().asTree()
-        val groups = flatten(tree)
-        val surface = find(groups, "Surface")
-        val text = find(groups, "Text")
-
-        val mapper = InlineClassConverter()
-
-        fun validate(caller: Group, parameterName: String, valueType: Class<*>) {
-            val parameter = caller.parameters.single { it.name == parameterName }
-            val value = mapper.castParameterValue(parameter.inlineClass, parameter.value)
-            assertThat(value).isInstanceOf(valueType)
-        }
-
-        validate(surface, "color", Color::class.java)
-        validate(surface, "elevation", Dp::class.java)
-        validate(text, "color", Color::class.java)
-        validate(text, "fontSize", TextUnit::class.java)
-    }
-
-    private fun flatten(group: Group): Sequence<Group> =
-        sequenceOf(group).plus(group.children.asSequence().flatMap { flatten(it) })
-
-    private fun find(groups: Sequence<Group>, calleeName: String) =
-        groups.first {
-            it.parameters.isNotEmpty() && it.name == calleeName
-        }
-}
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
deleted file mode 100644
index 7a375f3..0000000
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import android.view.View
-import android.view.ViewGroup
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.text.BasicText
-import androidx.compose.material.Button
-import androidx.compose.material.Icon
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.ModalDrawer
-import androidx.compose.material.Surface
-import androidx.compose.material.Text
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Call
-import androidx.compose.material.icons.filled.FavoriteBorder
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.layout.GraphicLayerInfo
-import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.style.TextDecoration
-import androidx.compose.ui.tooling.CompositionDataRecord
-import androidx.compose.ui.tooling.Inspectable
-import androidx.compose.ui.tooling.R
-import androidx.compose.ui.tooling.ToolingTest
-import androidx.compose.ui.tooling.data.Group
-import androidx.compose.ui.tooling.data.UiToolingDataApi
-import androidx.compose.ui.tooling.data.asTree
-import androidx.compose.ui.tooling.data.position
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.math.roundToInt
-
-private const val DEBUG = false
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 29) // Render id is not returned for api < 29
-@OptIn(UiToolingDataApi::class)
-class LayoutInspectorTreeTest : ToolingTest() {
-    private lateinit var density: Density
-    private lateinit var view: View
-
-    @Before
-    fun before() {
-        density = Density(activity)
-        view = activityTestRule.activity.findViewById<ViewGroup>(android.R.id.content)
-        isDebugInspectorInfoEnabled = true
-    }
-
-    @After
-    fun after() {
-        isDebugInspectorInfoEnabled = false
-    }
-
-    @Test
-    fun buildTree() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                Column {
-                    Text(text = "Hello World", color = Color.Green)
-                    Icon(Icons.Filled.FavoriteBorder, null)
-                    Surface {
-                        Button(onClick = {}) { Text(text = "OK") }
-                    }
-                }
-            }
-        }
-
-        // TODO: Find out if we can set "settings put global debug_view_attributes 1" in tests
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        val builder = LayoutInspectorTree()
-        val nodes = builder.convert(view)
-        dumpNodes(nodes, builder)
-
-        validate(nodes, builder, checkParameters = false) {
-            node(
-                name = "Inspectable",
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 78.9.dp,
-                children = listOf("Column")
-            )
-            node(
-                name = "Column",
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 78.9.dp,
-                children = listOf("Text", "Icon", "Surface")
-            )
-            node(
-                name = "Text",
-                isRenderNode = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 18.9.dp,
-            )
-            node(
-                name = "Icon",
-                isRenderNode = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 0.0.dp, top = 18.9.dp, width = 24.0.dp, height = 24.0.dp,
-            )
-            node(
-                name = "Surface",
-                fileName = "LayoutInspectorTreeTest.kt",
-                isRenderNode = true,
-                left = 0.0.dp,
-                top = 42.9.dp, width = 64.0.dp, height = 36.0.dp,
-                children = listOf("Button")
-            )
-            node(
-                name = "Button",
-                fileName = "LayoutInspectorTreeTest.kt",
-                isRenderNode = true,
-                left = 0.0.dp,
-                top = 42.9.dp, width = 64.0.dp, height = 36.0.dp,
-                children = listOf("Text")
-            )
-            node(
-                name = "Text",
-                isRenderNode = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 21.7.dp, top = 51.6.dp, width = 20.9.dp, height = 18.9.dp,
-            )
-        }
-    }
-
-    @Test
-    fun buildTreeWithTransformedText() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                MaterialTheme {
-                    Text(
-                        text = "Hello World",
-                        modifier = Modifier.graphicsLayer(rotationZ = 225f)
-                    )
-                }
-            }
-        }
-
-        // TODO: Find out if we can set "settings put global debug_view_attributes 1" in tests
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        val builder = LayoutInspectorTree()
-        val nodes = builder.convert(view)
-        dumpNodes(nodes, builder)
-
-        validate(nodes, builder, checkParameters = false) {
-            node(
-                name = "Inspectable",
-                hasTransformations = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                children = listOf("MaterialTheme")
-            )
-            node(
-                name = "MaterialTheme",
-                hasTransformations = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 65.0.dp, top = 49.7.dp, width = 86.dp, height = 21.7.dp,
-                children = listOf("Text")
-            )
-            node(
-                name = "Text",
-                isRenderNode = true,
-                hasTransformations = true,
-                fileName = "LayoutInspectorTreeTest.kt",
-                left = 65.0.dp, top = 49.7.dp, width = 86.dp, height = 21.7.dp,
-            )
-        }
-    }
-
-    @Test
-    fun testStitchTreeFromModelDrawerLayout() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                ModalDrawer(
-                    drawerContent = { Text("Something") },
-                    content = {
-                        Column {
-                            Text(text = "Hello World", color = Color.Green)
-                            Button(onClick = {}) { Text(text = "OK") }
-                        }
-                    }
-                )
-            }
-        }
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        dumpSlotTableSet(slotTableRecord)
-        val builder = LayoutInspectorTree()
-        val nodes = builder.convert(view)
-        dumpNodes(nodes, builder)
-
-        if (DEBUG) {
-            validate(nodes, builder, checkParameters = false) {
-                node("Inspectable", children = listOf("Box"))
-                node("Box", children = listOf("ModalDrawer"))
-                node("ModalDrawer", children = listOf("Column", "Text"))
-                node("Column", children = listOf("Text", "Button"))
-                node("Text")
-                node("Button", children = listOf("Text"))
-                node("Text")
-                node("Text")
-            }
-        }
-        assertThat(nodes.size).isEqualTo(1)
-    }
-
-    @LargeTest
-    @Test
-    fun testStitchTreeFromModelDrawerLayoutWithSystemNodes() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                ModalDrawer(
-                    drawerContent = { Text("Something") },
-                    content = {
-                        Column {
-                            Text(text = "Hello World", color = Color.Green)
-                            Button(onClick = {}) { Text(text = "OK") }
-                        }
-                    }
-                )
-            }
-        }
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        dumpSlotTableSet(slotTableRecord)
-        val builder = LayoutInspectorTree()
-        builder.hideSystemNodes = false
-        val nodes = builder.convert(view)
-        dumpNodes(nodes, builder)
-
-        if (DEBUG) {
-            validate(nodes, builder, checkParameters = false) {
-                node("Inspectable", children = listOf("Box"))
-                node("Box", children = listOf("ModalDrawer"))
-                node("ModalDrawer", children = listOf("WithConstraints"))
-                node("WithConstraints", children = listOf("SubcomposeLayout"))
-                node("SubcomposeLayout", children = listOf("Box"))
-                node("Box", children = listOf("Box", "Canvas", "Surface"))
-                node("Box", children = listOf("Column"))
-                node("Column", children = listOf("Text", "Button"))
-                node("Text", children = listOf("Text"))
-                node("Text", children = listOf("CoreText"))
-                node("CoreText", children = listOf())
-                node("Button", children = listOf("Surface"))
-                node("Surface", children = listOf("ProvideTextStyle"))
-                node("ProvideTextStyle", children = listOf("Row"))
-                node("Row", children = listOf("Text"))
-                node("Text", children = listOf("Text"))
-                node("Text", children = listOf("CoreText"))
-                node("CoreText", children = listOf())
-                node("Canvas", children = listOf("Spacer"))
-                node("Spacer", children = listOf())
-                node("Surface", children = listOf("Column"))
-                node("Column", children = listOf("Text"))
-                node("Text", children = listOf("Text"))
-                node("Text", children = listOf("CoreText"))
-                node("CoreText", children = listOf())
-            }
-        }
-        assertThat(nodes.size).isEqualTo(1)
-    }
-
-    @Test
-    fun testSpacer() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                Column {
-                    Text(text = "Hello World", color = Color.Green)
-                    Spacer(Modifier.height(16.dp))
-                    Image(Icons.Filled.Call, null)
-                }
-            }
-        }
-
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        val builder = LayoutInspectorTree()
-        val node = builder.convert(view)
-            .flatMap { flatten(it) }
-            .firstOrNull { it.name == "Spacer" }
-
-        // Spacer should show up in the Compose tree:
-        assertThat(node).isNotNull()
-    }
-
-    @Test // regression test b/174855322
-    fun testBasicText() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        show {
-            Inspectable(slotTableRecord) {
-                Column {
-                    BasicText(
-                        text = "Some text",
-                        style = TextStyle(textDecoration = TextDecoration.Underline)
-                    )
-                }
-            }
-        }
-
-        val builder = LayoutInspectorTree()
-        val node = builder.convert(view)
-            .flatMap { flatten(it) }
-            .firstOrNull { it.name == "BasicText" }
-
-        assertThat(node).isNotNull()
-
-        assertThat(node?.parameters).isNotEmpty()
-    }
-
-    @Test
-    fun testTextId() {
-        val slotTableRecord = CompositionDataRecord.create()
-
-        show {
-            Inspectable(slotTableRecord) {
-                Text(text = "Hello World")
-            }
-        }
-
-        view.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
-        val builder = LayoutInspectorTree()
-        val node = builder.convert(view)
-            .flatMap { flatten(it) }
-            .firstOrNull { it.name == "Text" }
-
-        // LayoutNode id should be captured by the Text node:
-        assertThat(node?.id).isGreaterThan(0)
-    }
-
-    @Suppress("SameParameterValue")
-    private fun validate(
-        result: List<InspectorNode>,
-        builder: LayoutInspectorTree,
-        checkParameters: Boolean,
-        block: TreeValidationReceiver.() -> Unit = {}
-    ) {
-        val nodes = result.flatMap { flatten(it) }.iterator()
-        val tree = TreeValidationReceiver(nodes, density, checkParameters, builder)
-        tree.block()
-    }
-
-    private class TreeValidationReceiver(
-        val nodeIterator: Iterator<InspectorNode>,
-        val density: Density,
-        val checkParameters: Boolean,
-        val builder: LayoutInspectorTree
-    ) {
-        fun node(
-            name: String,
-            fileName: String? = null,
-            lineNumber: Int = -1,
-            isRenderNode: Boolean = false,
-            hasTransformations: Boolean = false,
-
-            left: Dp = Dp.Unspecified,
-            top: Dp = Dp.Unspecified,
-            width: Dp = Dp.Unspecified,
-            height: Dp = Dp.Unspecified,
-            children: List<String> = listOf(),
-            block: ParameterValidationReceiver.() -> Unit = {}
-        ) {
-            assertWithMessage("No such node found: $name").that(nodeIterator.hasNext()).isTrue()
-            val node = nodeIterator.next()
-            assertThat(node.name).isEqualTo(name)
-            val message = "Node: $name"
-            assertWithMessage(message).that(node.children.map { it.name })
-                .containsExactlyElementsIn(children).inOrder()
-            fileName?.let { assertWithMessage(message).that(node.fileName).isEqualTo(fileName) }
-            if (lineNumber != -1) {
-                assertWithMessage(message).that(node.lineNumber).isEqualTo(lineNumber)
-            }
-            if (isRenderNode) {
-                assertWithMessage(message).that(node.id).isGreaterThan(0L)
-            } else {
-                assertWithMessage(message).that(node.id).isLessThan(0L)
-            }
-            if (hasTransformations) {
-                assertWithMessage(message).that(node.bounds).isNotEmpty()
-            } else {
-                assertWithMessage(message).that(node.bounds).isEmpty()
-            }
-            if (left != Dp.Unspecified) {
-                val tolerance = 5.0f
-                with(density) {
-                    assertWithMessage(message).that(node.left.toDp().value)
-                        .isWithin(tolerance).of(left.value)
-                    assertWithMessage(message).that(node.top.toDp().value)
-                        .isWithin(tolerance).of(top.value)
-                    assertWithMessage(message).that(node.width.toDp().value)
-                        .isWithin(tolerance).of(width.value)
-                    assertWithMessage(message).that(node.height.toDp().value)
-                        .isWithin(tolerance).of(height.value)
-                }
-            }
-
-            if (checkParameters) {
-                val params = builder.convertParameters(node)
-                val receiver = ParameterValidationReceiver(params.listIterator())
-                receiver.block()
-                if (receiver.parameterIterator.hasNext()) {
-                    val elementNames = mutableListOf<String>()
-                    receiver.parameterIterator.forEachRemaining { elementNames.add(it.name) }
-                    error("$name: has more parameters like: ${elementNames.joinToString()}")
-                }
-            }
-        }
-    }
-
-    private fun flatten(node: InspectorNode): List<InspectorNode> =
-        listOf(node).plus(node.children.flatMap { flatten(it) })
-
-    // region DEBUG print methods
-    private fun dumpNodes(nodes: List<InspectorNode>, builder: LayoutInspectorTree) {
-        @Suppress("ConstantConditionIf")
-        if (!DEBUG) {
-            return
-        }
-        println()
-        println("=================== Nodes ==========================")
-        nodes.forEach { dumpNode(it, indent = 0) }
-        println()
-        println("=================== validate statements ==========================")
-        nodes.forEach { generateValidate(it, builder) }
-    }
-
-    private fun dumpNode(node: InspectorNode, indent: Int) {
-        println(
-            "\"${"  ".repeat(indent * 2)}\", \"${node.name}\", \"${node.fileName}\", " +
-                "${node.lineNumber}, ${node.left}, ${node.top}, " +
-                "${node.width}, ${node.height}"
-        )
-        node.children.forEach { dumpNode(it, indent + 1) }
-    }
-
-    private fun generateValidate(
-        node: InspectorNode,
-        builder: LayoutInspectorTree,
-        generateParameters: Boolean = false
-    ) {
-        with(density) {
-            val left = round(node.left.toDp())
-            val top = round(node.top.toDp())
-            val width = if (node.width == view.width) "viewWidth" else round(node.width.toDp())
-            val height = if (node.height == view.height) "viewHeight" else round(node.height.toDp())
-
-            print(
-                """
-                  validate(
-                      name = "${node.name}",
-                      fileName = "${node.fileName}",
-                      left = $left, top = $top, width = $width, height = $height
-                """.trimIndent()
-            )
-        }
-        if (node.id > 0L) {
-            println(",")
-            print("    isRenderNode = true")
-        }
-        if (node.children.isNotEmpty()) {
-            println(",")
-            val children = node.children.joinToString { "\"${it.name}\"" }
-            print("    children = listOf($children)")
-        }
-        println()
-        print(")")
-        if (generateParameters && node.parameters.isNotEmpty()) {
-            generateParameters(builder.convertParameters(node), 0)
-        }
-        println()
-        node.children.forEach { generateValidate(it, builder) }
-    }
-
-    private fun generateParameters(parameters: List<NodeParameter>, indent: Int) {
-        val indentation = " ".repeat(indent * 2)
-        println(" {")
-        for (param in parameters) {
-            val name = param.name
-            val type = param.type
-            val value = toDisplayValue(type, param.value)
-            print("$indentation  parameter(name = \"$name\", type = $type, value = $value)")
-            if (param.elements.isNotEmpty()) {
-                generateParameters(param.elements, indent + 1)
-            }
-            println()
-        }
-        print("$indentation}")
-    }
-
-    private fun toDisplayValue(type: ParameterType, value: Any?): String =
-        when (type) {
-            ParameterType.Boolean -> value.toString()
-            ParameterType.Color ->
-                "0x${Integer.toHexString(value as Int)}${if (value < 0) ".toInt()" else ""}"
-            ParameterType.DimensionSp,
-            ParameterType.DimensionDp -> "${value}f"
-            ParameterType.Int32 -> value.toString()
-            ParameterType.String -> "\"$value\""
-            else -> value?.toString() ?: "null"
-        }
-
-    private fun dumpSlotTableSet(slotTableRecord: CompositionDataRecord) {
-        @Suppress("ConstantConditionIf")
-        if (!DEBUG) {
-            return
-        }
-        println()
-        println("=================== Groups ==========================")
-        slotTableRecord.store.forEach { dumpGroup(it.asTree(), indent = 0) }
-    }
-
-    private fun dumpGroup(group: Group, indent: Int) {
-        val position = group.position?.let { "\"$it\"" } ?: "null"
-        val box = group.box
-        val id = group.modifierInfo.mapNotNull { (it.extra as? GraphicLayerInfo)?.layerId }
-            .singleOrNull() ?: 0
-        println(
-            "\"${"  ".repeat(indent)}\", ${group.javaClass.simpleName}, \"${group.name}\", " +
-                "params: ${group.parameters.size}, children: ${group.children.size}, " +
-                "$id, $position, " +
-                "${box.left}, ${box.right}, ${box.right - box.left}, ${box.bottom - box.top}"
-        )
-        for (parameter in group.parameters) {
-            println("\"${"  ".repeat(indent + 4)}\"- ${parameter.name}")
-        }
-        group.children.forEach { dumpGroup(it, indent + 1) }
-    }
-
-    private fun round(dp: Dp): Dp = Dp((dp.value * 10.0f).roundToInt() / 10.0f)
-
-    //endregion
-}
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/ParameterFactoryTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/ParameterFactoryTest.kt
deleted file mode 100644
index 83459eb..0000000
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/ParameterFactoryTest.kt
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.wrapContentHeight
-import androidx.compose.foundation.shape.CornerSize
-import androidx.compose.foundation.shape.CutCornerShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.shape.ZeroCornerSize
-import androidx.compose.material.Text
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Call
-import androidx.compose.material.icons.rounded.Add
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.AbsoluteAlignment
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.paint
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Brush
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.Shadow
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.colorspace.ColorModel
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.Font
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.intl.Locale
-import androidx.compose.ui.text.intl.LocaleList
-import androidx.compose.ui.text.style.BaselineShift
-import androidx.compose.ui.text.style.TextDecoration
-import androidx.compose.ui.text.style.TextGeometricTransform
-import androidx.compose.ui.text.style.TextIndent
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.em
-import androidx.compose.ui.unit.sp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
-import kotlinx.coroutines.runBlocking
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@Suppress("unused")
-private fun topLevelFunction() {}
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-class ParameterFactoryTest {
-    private val factory = ParameterFactory(InlineClassConverter())
-    private val node = MutableInspectorNode().apply {
-        width = 1000
-        height = 500
-    }.build()
-
-    @Before
-    fun before() {
-        factory.density = Density(2.0f)
-        isDebugInspectorInfoEnabled = true
-    }
-
-    @After
-    fun after() {
-        isDebugInspectorInfoEnabled = false
-    }
-
-    @Test
-    fun testAbsoluteAlignment() {
-        assertThat(lookup(AbsoluteAlignment.TopLeft))
-            .isEqualTo(ParameterType.String to "TopLeft")
-        assertThat(lookup(AbsoluteAlignment.TopRight))
-            .isEqualTo(ParameterType.String to "TopRight")
-        assertThat(lookup(AbsoluteAlignment.CenterLeft))
-            .isEqualTo(ParameterType.String to "CenterLeft")
-        assertThat(lookup(AbsoluteAlignment.CenterRight))
-            .isEqualTo(ParameterType.String to "CenterRight")
-        assertThat(lookup(AbsoluteAlignment.BottomLeft))
-            .isEqualTo(ParameterType.String to "BottomLeft")
-        assertThat(lookup(AbsoluteAlignment.BottomRight))
-            .isEqualTo(ParameterType.String to "BottomRight")
-        assertThat(lookup(AbsoluteAlignment.Left))
-            .isEqualTo(ParameterType.String to "Left")
-        assertThat(lookup(AbsoluteAlignment.Right))
-            .isEqualTo(ParameterType.String to "Right")
-    }
-
-    @Test
-    fun testAlignment() {
-        assertThat(lookup(Alignment.Top)).isEqualTo(ParameterType.String to "Top")
-        assertThat(lookup(Alignment.Bottom)).isEqualTo(ParameterType.String to "Bottom")
-        assertThat(lookup(Alignment.CenterVertically))
-            .isEqualTo(ParameterType.String to "CenterVertically")
-
-        assertThat(lookup(Alignment.Start)).isEqualTo(ParameterType.String to "Start")
-        assertThat(lookup(Alignment.End)).isEqualTo(ParameterType.String to "End")
-        assertThat(lookup(Alignment.CenterHorizontally))
-            .isEqualTo(ParameterType.String to "CenterHorizontally")
-
-        assertThat(lookup(Alignment.TopStart)).isEqualTo(ParameterType.String to "TopStart")
-        assertThat(lookup(Alignment.TopCenter)).isEqualTo(ParameterType.String to "TopCenter")
-        assertThat(lookup(Alignment.TopEnd)).isEqualTo(ParameterType.String to "TopEnd")
-        assertThat(lookup(Alignment.CenterStart)).isEqualTo(ParameterType.String to "CenterStart")
-        assertThat(lookup(Alignment.Center)).isEqualTo(ParameterType.String to "Center")
-        assertThat(lookup(Alignment.CenterEnd)).isEqualTo(ParameterType.String to "CenterEnd")
-        assertThat(lookup(Alignment.BottomStart)).isEqualTo(ParameterType.String to "BottomStart")
-        assertThat(lookup(Alignment.BottomCenter)).isEqualTo(ParameterType.String to "BottomCenter")
-        assertThat(lookup(Alignment.BottomEnd)).isEqualTo(ParameterType.String to "BottomEnd")
-    }
-
-    @Test
-    fun testAnnotatedString() {
-        assertThat(lookup(AnnotatedString("Hello"))).isEqualTo(ParameterType.String to "Hello")
-    }
-
-    @Test
-    fun testArrangement() {
-        assertThat(lookup(Arrangement.Top)).isEqualTo(ParameterType.String to "Top")
-        assertThat(lookup(Arrangement.Bottom)).isEqualTo(ParameterType.String to "Bottom")
-        assertThat(lookup(Arrangement.Center)).isEqualTo(ParameterType.String to "Center")
-        assertThat(lookup(Arrangement.Start)).isEqualTo(ParameterType.String to "Start")
-        assertThat(lookup(Arrangement.End)).isEqualTo(ParameterType.String to "End")
-        assertThat(lookup(Arrangement.SpaceEvenly)).isEqualTo(ParameterType.String to "SpaceEvenly")
-        assertThat(lookup(Arrangement.SpaceBetween))
-            .isEqualTo(ParameterType.String to "SpaceBetween")
-        assertThat(lookup(Arrangement.SpaceAround)).isEqualTo(ParameterType.String to "SpaceAround")
-    }
-
-    @Test
-    fun testBaselineShift() {
-        assertThat(lookup(BaselineShift.None)).isEqualTo(ParameterType.String to "None")
-        assertThat(lookup(BaselineShift.Subscript)).isEqualTo(ParameterType.String to "Subscript")
-        assertThat(lookup(BaselineShift.Superscript))
-            .isEqualTo(ParameterType.String to "Superscript")
-        assertThat(lookup(BaselineShift(0.0f))).isEqualTo(ParameterType.String to "None")
-        assertThat(lookup(BaselineShift(-0.5f))).isEqualTo(ParameterType.String to "Subscript")
-        assertThat(lookup(BaselineShift(0.5f))).isEqualTo(ParameterType.String to "Superscript")
-        assertThat(lookup(BaselineShift(0.1f))).isEqualTo(ParameterType.Float to 0.1f)
-        assertThat(lookup(BaselineShift(0.75f))).isEqualTo(ParameterType.Float to 0.75f)
-    }
-
-    @Test
-    fun testBoolean() {
-        assertThat(lookup(true)).isEqualTo(ParameterType.Boolean to true)
-        assertThat(lookup(false)).isEqualTo(ParameterType.Boolean to false)
-    }
-
-    @Test
-    fun testBorder() {
-        validate(factory.create(node, "borderstroke", BorderStroke(2.0.dp, Color.Magenta))!!) {
-            parameter("borderstroke", ParameterType.String, "BorderStroke") {
-                parameter("brush", ParameterType.Color, Color.Magenta.toArgb())
-                parameter("width", ParameterType.DimensionDp, 2.0f)
-            }
-        }
-    }
-
-    @Test
-    fun testBrush() {
-        assertThat(lookup(SolidColor(Color.Red)))
-            .isEqualTo(ParameterType.Color to Color.Red.toArgb())
-        validate(
-            factory.create(
-                node,
-                "brush",
-                Brush.linearGradient(
-                    colors = listOf(Color.Red, Color.Blue),
-                    start = Offset(0.0f, 0.5f),
-                    end = Offset(5.0f, 10.0f)
-                )
-            )!!
-        ) {
-            parameter("brush", ParameterType.String, "LinearGradient") {
-                parameter("colors", ParameterType.String, "") {
-                    parameter("0", ParameterType.Color, Color.Red.toArgb())
-                    parameter("1", ParameterType.Color, Color.Blue.toArgb())
-                }
-                // Parameters are traversed in alphabetical order through reflection queries.
-                // Validate createdSize exists before validating end parameter
-                parameter("createdSize", ParameterType.String, "Unspecified")
-                parameter("end", ParameterType.String, Offset::class.java.simpleName) {
-                    parameter("x", ParameterType.DimensionDp, 2.5f)
-                    parameter("y", ParameterType.DimensionDp, 5.0f)
-                }
-                parameter("start", ParameterType.String, Offset::class.java.simpleName) {
-                    parameter("x", ParameterType.DimensionDp, 0.0f)
-                    parameter("y", ParameterType.DimensionDp, 0.25f)
-                }
-                parameter("tileMode", ParameterType.String, "Clamp")
-            }
-        }
-        // TODO: add tests for RadialGradient & ShaderBrush
-    }
-
-    @Test
-    fun testColor() {
-        assertThat(lookup(Color.Blue)).isEqualTo(ParameterType.Color to 0xff0000ff.toInt())
-        assertThat(lookup(Color.Red)).isEqualTo(ParameterType.Color to 0xffff0000.toInt())
-        assertThat(lookup(Color.Transparent)).isEqualTo(ParameterType.Color to 0x00000000)
-        assertThat(lookup(Color.Unspecified)).isEqualTo(ParameterType.String to "Unspecified")
-    }
-
-    @Test
-    fun testComposableLambda() = runBlocking {
-        // capture here to force the lambda to not be created as a singleton.
-        val capture = "Hello World"
-        val c: @Composable () -> Unit = { Text(text = capture) }
-        val result = lookup(c as Any) ?: error("Lookup of ComposableLambda failed")
-        val array = result.second as Array<*>
-        assertThat(result.first).isEqualTo(ParameterType.Lambda)
-        assertThat(array).hasLength(1)
-        assertThat(array[0]?.javaClass?.name).isEqualTo(
-            "${ParameterFactoryTest::class.java.name}\$testComposableLambda\$1\$c\$1"
-        )
-    }
-
-    @Test
-    fun testCornerBasedShape() {
-        validate(
-            factory.create(
-                node, "corner",
-                RoundedCornerShape(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp)
-            )!!
-        ) {
-            parameter("corner", ParameterType.String, RoundedCornerShape::class.java.simpleName) {
-                parameter("bottomEnd", ParameterType.DimensionDp, 2.5f)
-                parameter("bottomStart", ParameterType.DimensionDp, 0.7f)
-                parameter("topEnd", ParameterType.DimensionDp, 0.5f)
-                parameter("topStart", ParameterType.DimensionDp, 2.0f)
-            }
-        }
-        validate(factory.create(node, "corner", CutCornerShape(2))!!) {
-            parameter("corner", ParameterType.String, CutCornerShape::class.java.simpleName) {
-                parameter("bottomEnd", ParameterType.DimensionDp, 5.0f)
-                parameter("bottomStart", ParameterType.DimensionDp, 5.0f)
-                parameter("topEnd", ParameterType.DimensionDp, 5.0f)
-                parameter("topStart", ParameterType.DimensionDp, 5.0f)
-            }
-        }
-        validate(factory.create(node, "corner", RoundedCornerShape(1.0f, 10.0f, 2.0f, 3.5f))!!) {
-            parameter("corner", ParameterType.String, RoundedCornerShape::class.java.simpleName) {
-                parameter("bottomEnd", ParameterType.DimensionDp, 1.0f)
-                parameter("bottomStart", ParameterType.DimensionDp, 1.75f)
-                parameter("topEnd", ParameterType.DimensionDp, 5.0f)
-                parameter("topStart", ParameterType.DimensionDp, 0.5f)
-            }
-        }
-    }
-
-    @Test
-    fun testCornerSize() {
-        assertThat(lookup(ZeroCornerSize)).isEqualTo(ParameterType.String to "ZeroCornerSize")
-        assertThat(lookup(CornerSize(2.4.dp))).isEqualTo(ParameterType.DimensionDp to 2.4f)
-        assertThat(lookup(CornerSize(2.4f))).isEqualTo(ParameterType.DimensionDp to 1.2f)
-        assertThat(lookup(CornerSize(3))).isEqualTo(ParameterType.DimensionDp to 7.5f)
-    }
-
-    @Test
-    fun testDouble() {
-        assertThat(lookup(3.1428)).isEqualTo(ParameterType.Double to 3.1428)
-    }
-
-    @Test
-    fun testDp() {
-        assertThat(lookup(2.0.dp)).isEqualTo(ParameterType.DimensionDp to 2.0f)
-        assertThat(lookup(Dp.Hairline)).isEqualTo(ParameterType.DimensionDp to 0.0f)
-        assertThat(lookup(Dp.Unspecified)).isEqualTo(ParameterType.DimensionDp to Float.NaN)
-        assertThat(lookup(Dp.Infinity))
-            .isEqualTo(ParameterType.DimensionDp to Float.POSITIVE_INFINITY)
-    }
-
-    @Test
-    fun testEnum() {
-        assertThat(lookup(ColorModel.Lab)).isEqualTo(ParameterType.String to "Lab")
-        assertThat(lookup(ColorModel.Rgb)).isEqualTo(ParameterType.String to "Rgb")
-        assertThat(lookup(ColorModel.Cmyk)).isEqualTo(ParameterType.String to "Cmyk")
-    }
-
-    @Test
-    fun testFloat() {
-        assertThat(lookup(3.1428f)).isEqualTo(ParameterType.Float to 3.1428f)
-    }
-
-    @Test
-    fun testFontFamily() {
-        assertThat(lookup(FontFamily.Cursive)).isEqualTo(ParameterType.String to "Cursive")
-        assertThat(lookup(FontFamily.Default)).isEqualTo(ParameterType.String to "Default")
-        assertThat(lookup(FontFamily.SansSerif)).isEqualTo(ParameterType.String to "SansSerif")
-        assertThat(lookup(FontFamily.Serif)).isEqualTo(ParameterType.String to "Serif")
-        assertThat(lookup(FontFamily.Monospace)).isEqualTo(ParameterType.String to "Monospace")
-    }
-
-    @Test
-    fun testFontListFontFamily() {
-        val family = FontFamily(
-            listOf(
-                Font(1234, FontWeight.Normal, FontStyle.Italic),
-                Font(1235, FontWeight.Normal, FontStyle.Normal),
-                Font(1236, FontWeight.Bold, FontStyle.Italic),
-                Font(1237, FontWeight.Bold, FontStyle.Normal)
-            )
-        )
-        assertThat(lookup(family)).isEqualTo(ParameterType.Resource to 1235)
-    }
-
-    @Test
-    fun testFontWeight() {
-        assertThat(lookup(FontWeight.Thin)).isEqualTo(ParameterType.String to "W100")
-        assertThat(lookup(FontWeight.ExtraLight)).isEqualTo(ParameterType.String to "W200")
-        assertThat(lookup(FontWeight.Light)).isEqualTo(ParameterType.String to "W300")
-        assertThat(lookup(FontWeight.Normal)).isEqualTo(ParameterType.String to "W400")
-        assertThat(lookup(FontWeight.Medium)).isEqualTo(ParameterType.String to "W500")
-        assertThat(lookup(FontWeight.SemiBold)).isEqualTo(ParameterType.String to "W600")
-        assertThat(lookup(FontWeight.Bold)).isEqualTo(ParameterType.String to "W700")
-        assertThat(lookup(FontWeight.ExtraBold)).isEqualTo(ParameterType.String to "W800")
-        assertThat(lookup(FontWeight.Black)).isEqualTo(ParameterType.String to "W900")
-        assertThat(lookup(FontWeight.W100)).isEqualTo(ParameterType.String to "W100")
-        assertThat(lookup(FontWeight.W200)).isEqualTo(ParameterType.String to "W200")
-        assertThat(lookup(FontWeight.W300)).isEqualTo(ParameterType.String to "W300")
-        assertThat(lookup(FontWeight.W400)).isEqualTo(ParameterType.String to "W400")
-        assertThat(lookup(FontWeight.W500)).isEqualTo(ParameterType.String to "W500")
-        assertThat(lookup(FontWeight.W600)).isEqualTo(ParameterType.String to "W600")
-        assertThat(lookup(FontWeight.W700)).isEqualTo(ParameterType.String to "W700")
-        assertThat(lookup(FontWeight.W800)).isEqualTo(ParameterType.String to "W800")
-        assertThat(lookup(FontWeight.W900)).isEqualTo(ParameterType.String to "W900")
-    }
-
-    @Test
-    fun testFunctionReference() {
-        val ref1 = ::testInt
-        val map1 = lookup(ref1)!!
-        val array1 = map1.second as Array<*>
-        assertThat(map1.first).isEqualTo(ParameterType.FunctionReference)
-        assertThat(array1.contentEquals(arrayOf(ref1, "testInt"))).isTrue()
-        val ref2 = ::topLevelFunction
-        val map2 = lookup(ref2)!!
-        val array2 = map2.second as Array<*>
-        assertThat(map2.first).isEqualTo(ParameterType.FunctionReference)
-        assertThat(array2.contentEquals(arrayOf(ref2, "topLevelFunction"))).isTrue()
-    }
-
-    @Test
-    fun testPaddingValues() {
-        validate(factory.create(node, "padding", PaddingValues(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp))!!) {
-            parameter(
-                "padding",
-                ParameterType.String,
-                "PaddingValuesImpl"
-            ) {
-                parameter("bottom", ParameterType.DimensionDp, 0.7f)
-                parameter("end", ParameterType.DimensionDp, 2.5f)
-                parameter("start", ParameterType.DimensionDp, 2.0f)
-                parameter("top", ParameterType.DimensionDp, 0.5f)
-            }
-        }
-    }
-
-    @Test
-    fun testInt() {
-        assertThat(lookup(12345)).isEqualTo(ParameterType.Int32 to 12345)
-    }
-
-    @Test
-    fun testLambda() {
-        val a: (Int) -> Int = { it }
-        val map = lookup(a)!!
-        val array = map.second as Array<*>
-        assertThat(map.first).isEqualTo(ParameterType.Lambda)
-        assertThat(array.contentEquals(arrayOf<Any>(a))).isTrue()
-    }
-
-    @Test
-    fun testLocale() {
-        assertThat(lookup(Locale("fr-CA"))).isEqualTo(ParameterType.String to "fr-CA")
-        assertThat(lookup(Locale("fr-BE"))).isEqualTo(ParameterType.String to "fr-BE")
-    }
-
-    @Test
-    fun testLocaleList() {
-        validate(factory.create(node, "locales", LocaleList(Locale("fr-ca"), Locale("fr-be")))!!) {
-            parameter("locales", ParameterType.String, "") {
-                parameter("0", ParameterType.String, "fr-CA")
-                parameter("1", ParameterType.String, "fr-BE")
-            }
-        }
-    }
-
-    @Test
-    fun testLong() {
-        assertThat(lookup(12345L)).isEqualTo(ParameterType.Int64 to 12345L)
-    }
-
-    @Test
-    fun testModifier() {
-        validate(
-            factory.create(
-                node, "modifier",
-                Modifier
-                    .background(Color.Blue)
-                    .border(width = 5.dp, color = Color.Red)
-                    .padding(2.0.dp)
-                    .fillMaxWidth()
-                    .wrapContentHeight(Alignment.Bottom)
-                    .width(30.0.dp)
-                    .paint(TestPainter(10f, 20f))
-            )!!
-        ) {
-            parameter("modifier", ParameterType.String, "") {
-                parameter("background", ParameterType.Color, Color.Blue.toArgb()) {
-                    parameter("color", ParameterType.Color, Color.Blue.toArgb())
-                    parameter("shape", ParameterType.String, "RectangleShape")
-                }
-                parameter("border", ParameterType.Color, Color.Red.toArgb()) {
-                    parameter("color", ParameterType.Color, Color.Red.toArgb())
-                    parameter("shape", ParameterType.String, "RectangleShape")
-                    parameter("width", ParameterType.DimensionDp, 5.0f)
-                }
-                parameter("padding", ParameterType.DimensionDp, 2.0f)
-                parameter("fillMaxWidth", ParameterType.String, "") {
-                    parameter("fraction", ParameterType.Float, 1.0f)
-                }
-                parameter("wrapContentHeight", ParameterType.String, "") {
-                    parameter("align", ParameterType.String, "Bottom")
-                    parameter("unbounded", ParameterType.Boolean, false)
-                }
-                parameter("width", ParameterType.DimensionDp, 30.0f)
-                parameter("paint", ParameterType.String, "") {
-                    parameter("alignment", ParameterType.String, "Center")
-                    parameter("alpha", ParameterType.Float, 1.0f)
-                    parameter("contentScale", ParameterType.String, "Inside")
-                    parameter("painter", ParameterType.String, "TestPainter") {
-                        parameter("alpha", ParameterType.Float, 1.0f)
-                        parameter("color", ParameterType.Color, Color.Red.toArgb())
-                        parameter("drawLambda", ParameterType.Lambda, null)
-                        parameter("height", ParameterType.Float, 20.0f)
-                        parameter("intrinsicSize", ParameterType.String, "Size") {
-                            parameter("height", ParameterType.Float, 20.0f)
-                            parameter("maxDimension", ParameterType.Float, 20.0f)
-                            parameter("minDimension", ParameterType.Float, 10.0f)
-                            parameter("packedValue", ParameterType.Int64, 4692750812821061632L)
-                            parameter("width", ParameterType.Float, 10.0f)
-                        }
-                        parameter("layoutDirection", ParameterType.String, "Ltr")
-                        parameter("useLayer", ParameterType.Boolean, false)
-                        parameter("width", ParameterType.Float, 10.0f)
-                    }
-                    parameter("sizeToIntrinsics", ParameterType.Boolean, true)
-                }
-            }
-        }
-    }
-
-    @Test
-    fun testSingleModifier() {
-        validate(factory.create(node, "modifier", Modifier.padding(2.0.dp))!!) {
-            parameter("modifier", ParameterType.String, "") {
-                parameter("padding", ParameterType.DimensionDp, 2.0f)
-            }
-        }
-    }
-
-    @Test
-    fun testSingleModifierWithParameters() {
-        validate(factory.create(node, "modifier", Modifier.padding(1.dp, 2.dp, 3.dp, 4.dp))!!) {
-            parameter("modifier", ParameterType.String, "") {
-                parameter("padding", ParameterType.String, "") {
-                    parameter("bottom", ParameterType.DimensionDp, 4.0f)
-                    parameter("end", ParameterType.DimensionDp, 3.0f)
-                    parameter("start", ParameterType.DimensionDp, 1.0f)
-                    parameter("top", ParameterType.DimensionDp, 2.0f)
-                }
-            }
-        }
-    }
-
-    @Test
-    fun testOffset() {
-        validate(factory.create(node, "offset", Offset(1.0f, 5.0f))!!) {
-            parameter("offset", ParameterType.String, Offset::class.java.simpleName) {
-                parameter("x", ParameterType.DimensionDp, 0.5f)
-                parameter("y", ParameterType.DimensionDp, 2.5f)
-            }
-        }
-        validate(factory.create(node, "offset", Offset.Zero)!!) {
-            parameter("offset", ParameterType.String, "Zero")
-        }
-    }
-
-    @Test
-    fun testRecursiveStructure() {
-        val v1 = MyClass()
-        val v2 = MyClass()
-        v1.other = v2
-        v2.other = v1
-        val name = MyClass::class.java.simpleName
-        validate(factory.create(node, "mine", v1)!!) {
-            parameter("mine", ParameterType.String, name) {
-                parameter("other", ParameterType.String, name) {
-                    parameter("other", ParameterType.String, name) {
-                        parameter("other", ParameterType.String, name) {
-                            parameter("other", ParameterType.String, name) {
-                                parameter("other", ParameterType.String, name) {
-                                    parameter("other", ParameterType.String, name) {
-                                        parameter("other", ParameterType.String, name) {
-                                            parameter("other", ParameterType.String, name) {
-                                                parameter("other", ParameterType.String, name)
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    @Test
-    fun testDoNotRecurseIntoAndroidAndJavaPackages() {
-        runBlocking {
-            assertThat(factory.create(node, "v1", java.net.URL("http://domain.com"))).isNull()
-            assertThat(factory.create(node, "v1", android.app.Notification())).isNull()
-        }
-    }
-
-    @Test
-    fun testShadow() {
-        assertThat(lookup(Shadow.None)).isEqualTo(ParameterType.String to "None")
-        validate(factory.create(node, "shadow", Shadow(Color.Cyan, Offset.Zero, 2.5f))!!) {
-            parameter("shadow", ParameterType.String, Shadow::class.java.simpleName) {
-                parameter("blurRadius", ParameterType.DimensionDp, 1.25f)
-                parameter("color", ParameterType.Color, Color.Cyan.toArgb())
-                parameter("offset", ParameterType.String, "Zero")
-            }
-        }
-        validate(factory.create(node, "shadow", Shadow(Color.Blue, Offset(1.0f, 4.0f), 1.5f))!!) {
-            parameter("shadow", ParameterType.String, Shadow::class.java.simpleName) {
-                parameter("blurRadius", ParameterType.DimensionDp, 0.75f)
-                parameter("color", ParameterType.Color, Color.Blue.toArgb())
-                parameter("offset", ParameterType.String, Offset::class.java.simpleName) {
-                    parameter("x", ParameterType.DimensionDp, 0.5f)
-                    parameter("y", ParameterType.DimensionDp, 2.0f)
-                }
-            }
-        }
-    }
-
-    @Test
-    fun testShape() {
-        assertThat(lookup(RectangleShape)).isEqualTo(ParameterType.String to "RectangleShape")
-    }
-
-    @Test
-    fun testString() {
-        assertThat(lookup("Hello")).isEqualTo(ParameterType.String to "Hello")
-    }
-
-    @Test
-    fun testTextDecoration() {
-        assertThat(lookup(TextDecoration.None)).isEqualTo(ParameterType.String to "None")
-        assertThat(lookup(TextDecoration.LineThrough))
-            .isEqualTo(ParameterType.String to "LineThrough")
-        assertThat(lookup(TextDecoration.Underline))
-            .isEqualTo(ParameterType.String to "Underline")
-        assertThat(lookup(TextDecoration.LineThrough + TextDecoration.Underline))
-            .isEqualTo(ParameterType.String to "LineThrough+Underline")
-    }
-
-    @Test
-    fun testTextGeometricTransform() {
-        validate(factory.create(node, "transform", TextGeometricTransform(2.0f, 1.5f))!!) {
-            parameter(
-                "transform", ParameterType.String,
-                TextGeometricTransform::class.java.simpleName
-            ) {
-                parameter("scaleX", ParameterType.Float, 2.0f)
-                parameter("skewX", ParameterType.Float, 1.5f)
-            }
-        }
-    }
-
-    @Test
-    fun testTextIndent() {
-        assertThat(lookup(TextIndent.None)).isEqualTo(ParameterType.String to "None")
-
-        validate(factory.create(node, "textIndent", TextIndent(4.0.sp, 0.5.sp))!!) {
-            parameter("textIndent", ParameterType.String, "TextIndent") {
-                parameter("firstLine", ParameterType.DimensionSp, 4.0f)
-                parameter("restLine", ParameterType.DimensionSp, 0.5f)
-            }
-        }
-    }
-
-    @Test
-    fun testTextStyle() {
-        val style = TextStyle(
-            color = Color.Red,
-            textDecoration = TextDecoration.Underline
-        )
-        validate(factory.create(node, "style", style)!!) {
-            parameter("style", ParameterType.String, TextStyle::class.java.simpleName) {
-                parameter("background", ParameterType.String, "Unspecified")
-                parameter("color", ParameterType.Color, Color.Red.toArgb())
-                parameter("fontSize", ParameterType.String, "Unspecified")
-                parameter("letterSpacing", ParameterType.String, "Unspecified")
-                parameter("lineHeight", ParameterType.String, "Unspecified")
-                parameter("textDecoration", ParameterType.String, "Underline")
-            }
-        }
-    }
-
-    @Test
-    fun testTextUnit() {
-        assertThat(lookup(TextUnit.Unspecified)).isEqualTo(ParameterType.String to "Unspecified")
-        assertThat(lookup(12.0.sp)).isEqualTo(ParameterType.DimensionSp to 12.0f)
-        assertThat(lookup(2.0.em)).isEqualTo(ParameterType.DimensionEm to 2.0f)
-        assertThat(lookup(9.0f.sp)).isEqualTo(ParameterType.DimensionSp to 9.0f)
-        assertThat(lookup(10.sp)).isEqualTo(ParameterType.DimensionSp to 10.0f)
-        assertThat(lookup(26.0.sp)).isEqualTo(ParameterType.DimensionSp to 26.0f)
-        assertThat(lookup(2.0f.em)).isEqualTo(ParameterType.DimensionEm to 2.0f)
-        assertThat(lookup(1.em)).isEqualTo(ParameterType.DimensionEm to 1.0f)
-        assertThat(lookup(3.0.em)).isEqualTo(ParameterType.DimensionEm to 3.0f)
-    }
-
-    @Test
-    fun testVectorAssert() {
-        assertThat(lookup(Icons.Filled.Call)).isEqualTo(ParameterType.String to "Filled.Call")
-        assertThat(lookup(Icons.Rounded.Add)).isEqualTo(ParameterType.String to "Rounded.Add")
-    }
-
-    private fun lookup(value: Any): Pair<ParameterType, Any?>? {
-        val parameter = factory.create(node, "property", value) ?: return null
-        assertThat(parameter.elements).isEmpty()
-        return Pair(parameter.type, parameter.value)
-    }
-
-    private fun validate(
-        parameter: NodeParameter,
-        expected: ParameterValidationReceiver.() -> Unit = {}
-    ) {
-        val elements = ParameterValidationReceiver(listOf(parameter).listIterator())
-        elements.expected()
-    }
-}
-
-private class TestPainter(
-    val width: Float,
-    val height: Float
-) : Painter() {
-
-    var color = Color.Red
-
-    override val intrinsicSize: Size
-        get() = Size(width, height)
-
-    override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean {
-        color = if (layoutDirection == LayoutDirection.Rtl) Color.Blue else Color.Red
-        return true
-    }
-
-    override fun DrawScope.onDraw() {
-        drawRect(color = color)
-    }
-}
-
-class ParameterValidationReceiver(val parameterIterator: Iterator<NodeParameter>) {
-    fun parameter(
-        name: String,
-        type: ParameterType,
-        value: Any?,
-        block: ParameterValidationReceiver.() -> Unit = {}
-    ) {
-        assertWithMessage("No such element found: $name").that(parameterIterator.hasNext()).isTrue()
-        val parameter = parameterIterator.next()
-        assertThat(parameter.name).isEqualTo(name)
-        assertWithMessage(name).that(parameter.type).isEqualTo(type)
-        if (type != ParameterType.Lambda || value != null) {
-            assertWithMessage(name).that(parameter.value).isEqualTo(value)
-        }
-        var elements: List<NodeParameter> = parameter.elements
-        if (name != "modifier") {
-            // Do not sort modifiers: the order is important
-            elements = elements.sortedBy { it.name }
-        }
-        val children = ParameterValidationReceiver(elements.listIterator())
-        children.block()
-        if (children.parameterIterator.hasNext()) {
-            val elementNames = mutableListOf<String>()
-            while (children.parameterIterator.hasNext()) {
-                elementNames.add(children.parameterIterator.next().name)
-            }
-            error("$name: has more elements like: ${elementNames.joinToString()}")
-        }
-    }
-}
-
-class MyClass {
-    var other: MyClass? = null
-}
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/SynthesizedLambdaNameTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/SynthesizedLambdaNameTest.kt
deleted file mode 100644
index 68c361e..0000000
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/SynthesizedLambdaNameTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-private val topLambda1 = {}
-private val topLambda2 = withArgument {}
-private val topLambda3 = withArguments({}, {})
-
-private fun withArgument(a: (Int) -> Unit = {}): (Int) -> Unit = a
-private fun withArguments(a1: () -> Unit = {}, a2: () -> Unit = {}): List<() -> Unit> =
-    listOf(a1, a2)
-
-/**
- * Test the compiler generated lambda names.
- *
- * There is code in Studio that relies on this format.
- * If this test should start to fail, please check the LambdaResolver in the Layout Inspector.
- */
-@SmallTest
-@Suppress("JoinDeclarationAndAssignment")
-class SynthesizedLambdaNameTest {
-    private val cls = SynthesizedLambdaNameTest::class.java.name
-    private val memberLambda1 = {}
-    private val memberLambda2 = withArgument {}
-    private val memberLambda3 = withArguments({}, {})
-    private val initLambda1: (Int) -> Unit
-    private val initLambda2: (Int) -> Unit
-    private val defaultLambda1 = withArgument()
-    private val defaultLambda2 = withArguments()
-
-    init {
-        initLambda1 = withArgument {}
-        initLambda2 = withArgument {}
-    }
-
-    @Test
-    fun testSynthesizedNames() {
-        assertThat(name(topLambda1)).isEqualTo("${cls}Kt\$topLambda1$1")
-        assertThat(name(topLambda2)).isEqualTo("${cls}Kt\$topLambda2$1")
-        assertThat(name(topLambda3[0])).isEqualTo("${cls}Kt\$topLambda3$1")
-        assertThat(name(topLambda3[1])).isEqualTo("${cls}Kt\$topLambda3$2")
-        assertThat(name(memberLambda1)).isEqualTo("$cls\$memberLambda1$1")
-        assertThat(name(memberLambda2)).isEqualTo("$cls\$memberLambda2$1")
-        assertThat(name(memberLambda3[0])).isEqualTo("$cls\$memberLambda3$1")
-        assertThat(name(memberLambda3[1])).isEqualTo("$cls\$memberLambda3$2")
-        assertThat(name(initLambda1)).isEqualTo("$cls$1")
-        assertThat(name(initLambda2)).isEqualTo("$cls$2")
-        assertThat(name(defaultLambda1)).isEqualTo("${cls}Kt\$withArgument$1")
-        assertThat(name(defaultLambda2[0])).isEqualTo("${cls}Kt\$withArguments$1")
-        assertThat(name(defaultLambda2[1])).isEqualTo("${cls}Kt\$withArguments$2")
-    }
-
-    private fun name(lambda: Any) = lambda.javaClass.name
-}
\ No newline at end of file
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InlineClassConverter.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InlineClassConverter.kt
deleted file mode 100644
index e80975f..0000000
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InlineClassConverter.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-/**
- * Converter for casting a parameter represented by its primitive value to its inline class type.
- *
- * For example: an androidx.compose.ui.graphics.Color instance is often represented by a long
- */
-internal class InlineClassConverter {
-    // Map from inline type name to inline class and conversion lambda
-    private val typeMap = mutableMapOf<String, (Any) -> Any>()
-    // Return value used in functions
-    private val notInlineType: (Any) -> Any = { it }
-
-    /**
-     * Clear any cached data.
-     */
-    fun clear() {
-        typeMap.clear()
-    }
-
-    /**
-     * Cast the specified [value] to a value of type [inlineClassName] if possible.
-     *
-     * @param inlineClassName the fully qualified name of the inline class.
-     * @param value the value to convert to an instance of [inlineClassName].
-     */
-    fun castParameterValue(inlineClassName: String?, value: Any?): Any? =
-        if (value != null && inlineClassName != null)
-            typeMapperFor(inlineClassName)(value) else value
-
-    private fun typeMapperFor(typeName: String): (Any) -> (Any) =
-        typeMap.getOrPut(typeName) { loadTypeMapper(typeName.replace('.', '/')) }
-
-    private fun loadTypeMapper(className: String): (Any) -> Any {
-        val javaClass = loadClassOrNull(className) ?: return notInlineType
-        val create = javaClass.declaredConstructors.singleOrNull() ?: return notInlineType
-        create.isAccessible = true
-        return { value -> create.newInstance(value) }
-    }
-
-    private fun loadClassOrNull(className: String): Class<*>? =
-        try {
-            javaClass.classLoader!!.loadClass(className)
-        } catch (ex: Exception) {
-            null
-        }
-}
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InspectorNode.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InspectorNode.kt
deleted file mode 100644
index ae66150..0000000
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/InspectorNode.kt
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import androidx.compose.ui.layout.LayoutInfo
-
-private val EmptyIntArray = IntArray(0)
-
-/**
- * Node representing a Composable for the Layout Inspector.
- */
-class InspectorNode internal constructor(
-    /**
-     * The associated render node id or 0.
-     */
-    val id: Long,
-
-    /**
-     * The name of the Composable.
-     */
-    val name: String,
-
-    /**
-     * The fileName where the Composable was called.
-     */
-    val fileName: String,
-
-    /**
-     * A hash of the package name to help disambiguate duplicate [fileName] values.
-     *
-     * This hash is calculated by,
-     *
-     *   `packageName.fold(0) { hash, current -> hash * 31 + current.toInt() }?.absoluteValue`
-     *
-     * where the package name is the dotted name of the package. This can be used to disambiguate
-     * which file is referenced by [fileName]. This number is -1 if there was no package hash
-     * information generated such as when the file does not contain a package declaration.
-     */
-    val packageHash: Int,
-
-    /**
-     * The line number where the Composable was called.
-     */
-    val lineNumber: Int,
-
-    /**
-     * The UTF-16 offset in the file where the Composable was called
-     */
-    val offset: Int,
-
-    /**
-     * The number of UTF-16 code point comprise the Composable call
-     */
-    val length: Int,
-
-    /**
-     * Left side of the Composable in pixels.
-     */
-    val left: Int,
-
-    /**
-     * Top of the Composable in pixels.
-     */
-    val top: Int,
-
-    /**
-     * Width of the Composable in pixels.
-     */
-    val width: Int,
-
-    /**
-     * Width of the Composable in pixels.
-     */
-    val height: Int,
-
-    /**
-     * The 4 corners of the node after modifier transformations.
-     * If there are no coordinate transforms the array will be empty.
-     * Otherwise the content will be 8 integers representing 4 (x,y) corners
-     * in clockwise order of the original, untransformed coordinates.
-     */
-    val bounds: IntArray,
-
-    /**
-     * The parameters of this Composable.
-     */
-    val parameters: List<RawParameter>,
-
-    /**
-     * The children nodes of this Composable.
-     */
-    val children: List<InspectorNode>
-)
-
-/**
- * Parameter definition with a raw value reference.
- */
-class RawParameter(val name: String, val value: Any?)
-
-/**
- * Mutable version of [InspectorNode].
- */
-internal class MutableInspectorNode {
-    var id = 0L
-    var layoutNodes = mutableListOf<LayoutInfo>()
-    var name = ""
-    var fileName = ""
-    var packageHash = -1
-    var lineNumber = 0
-    var offset = 0
-    var length = 0
-    var left = 0
-    var top = 0
-    var width = 0
-    var height = 0
-    var bounds = EmptyIntArray
-    val parameters = mutableListOf<RawParameter>()
-    val children = mutableListOf<InspectorNode>()
-
-    fun reset() {
-        markUnwanted()
-        id = 0L
-        left = 0
-        top = 0
-        width = 0
-        height = 0
-        layoutNodes.clear()
-        bounds = EmptyIntArray
-        children.clear()
-    }
-
-    fun markUnwanted() {
-        name = ""
-        fileName = ""
-        packageHash = -1
-        lineNumber = 0
-        offset = 0
-        length = 0
-        parameters.clear()
-    }
-
-    fun shallowCopy(node: InspectorNode): MutableInspectorNode = apply {
-        id = node.id
-        name = node.name
-        fileName = node.fileName
-        packageHash = node.packageHash
-        lineNumber = node.lineNumber
-        offset = node.offset
-        length = node.length
-        left = node.left
-        top = node.top
-        width = node.width
-        height = node.height
-        bounds = node.bounds
-        parameters.addAll(node.parameters)
-        children.addAll(node.children)
-    }
-
-    fun build(): InspectorNode =
-        InspectorNode(
-            id, name, fileName, packageHash, lineNumber, offset, length, left, top, width, height,
-            bounds, parameters.toList(), children.toList()
-        )
-}
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt
deleted file mode 100644
index 85f0933..0000000
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTree.kt
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import android.view.View
-import androidx.compose.runtime.tooling.CompositionData
-import androidx.compose.runtime.InternalComposeApi
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.layout.GraphicLayerInfo
-import androidx.compose.ui.layout.LayoutInfo
-import androidx.compose.ui.tooling.R
-import androidx.compose.ui.tooling.data.Group
-import androidx.compose.ui.tooling.data.NodeGroup
-import androidx.compose.ui.tooling.data.ParameterInformation
-import androidx.compose.ui.tooling.data.UiToolingDataApi
-import androidx.compose.ui.tooling.data.asTree
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.toSize
-import java.util.ArrayDeque
-import java.util.Collections
-import java.util.IdentityHashMap
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-private val systemPackages = setOf(
-    -1,
-    packageNameHash("androidx.compose.animation"),
-    packageNameHash("androidx.compose.animation.core"),
-    packageNameHash("androidx.compose.desktop"),
-    packageNameHash("androidx.compose.foundation"),
-    packageNameHash("androidx.compose.foundation.layout"),
-    packageNameHash("androidx.compose.foundation.text"),
-    packageNameHash("androidx.compose.material"),
-    packageNameHash("androidx.compose.material.ripple"),
-    packageNameHash("androidx.compose.runtime"),
-    packageNameHash("androidx.compose.ui"),
-    packageNameHash("androidx.compose.ui.layout"),
-    packageNameHash("androidx.compose.ui.platform"),
-    packageNameHash("androidx.compose.ui.tooling"),
-    packageNameHash("androidx.compose.ui.selection"),
-    packageNameHash("androidx.compose.ui.semantics"),
-    packageNameHash("androidx.compose.ui.viewinterop"),
-    packageNameHash("androidx.compose.ui.window"),
-)
-
-private val unwantedCalls = setOf(
-    "emit",
-    "remember",
-    "CompositionLocalProvider",
-    "Content",
-    "Inspectable",
-    "ProvideAndroidCompositionLocals",
-    "ProvideCommonCompositionLocals",
-)
-
-private fun packageNameHash(packageName: String) =
-    packageName.fold(0) { hash, char -> hash * 31 + char.toInt() }.absoluteValue
-
-/**
- * Generator of a tree for the Layout Inspector.
- */
-class LayoutInspectorTree {
-    @Suppress("MemberVisibilityCanBePrivate")
-    var hideSystemNodes = true
-    private val inlineClassConverter = InlineClassConverter()
-    private val parameterFactory = ParameterFactory(inlineClassConverter)
-    private val cache = ArrayDeque<MutableInspectorNode>()
-    private var generatedId = -1L
-    /** Map from [LayoutInfo] to the nearest [InspectorNode] that contains it */
-    private val claimedNodes = IdentityHashMap<LayoutInfo, InspectorNode>()
-    /** Map from parent tree to child trees that are about to be stitched together */
-    private val treeMap = IdentityHashMap<MutableInspectorNode, MutableList<MutableInspectorNode>>()
-    /** Map from owner node to child trees that are about to be stitched to this owner */
-    private val ownerMap = IdentityHashMap<InspectorNode, MutableList<MutableInspectorNode>>()
-    /** Set of tree nodes that were stitched into another tree */
-    private val stitched =
-        Collections.newSetFromMap(IdentityHashMap<MutableInspectorNode, Boolean>())
-
-    /**
-     * Converts the [CompositionData] set held by [view] into a list of root nodes.
-     */
-    @OptIn(InternalComposeApi::class)
-    fun convert(view: View): List<InspectorNode> {
-        parameterFactory.density = Density(view.context)
-        @Suppress("UNCHECKED_CAST")
-        val tables = view.getTag(R.id.inspection_slot_table_set) as? Set<CompositionData>
-            ?: return emptyList()
-        clear()
-        val result = convert(tables)
-        clear()
-        return result
-    }
-
-    /**
-     * Converts the [RawParameter]s of the [node] into displayable parameters.
-     */
-    fun convertParameters(node: InspectorNode): List<NodeParameter> {
-        return node.parameters.mapNotNull { parameterFactory.create(node, it.name, it.value) }
-    }
-
-    /**
-     * Reset the generated id. Nodes are assigned an id if there isn't a layout node id present.
-     */
-    @Suppress("unused")
-    fun resetGeneratedId() {
-        generatedId = -1L
-    }
-
-    private fun clear() {
-        cache.clear()
-        inlineClassConverter.clear()
-        claimedNodes.clear()
-        treeMap.clear()
-        ownerMap.clear()
-        stitched.clear()
-    }
-
-    @OptIn(InternalComposeApi::class)
-    private fun convert(tables: Set<CompositionData>): List<InspectorNode> {
-        val trees = tables.map { convert(it) }
-        return when (trees.size) {
-            0 -> listOf()
-            1 -> addTree(mutableListOf(), trees.single())
-            else -> stitchTreesByLayoutInfo(trees)
-        }
-    }
-
-    /**
-     * Stitch separate trees together using the [LayoutInfo]s found in the [CompositionData]s.
-     *
-     * Some constructs in Compose (e.g. ModalDrawer) will result is multiple
-     * [CompositionData]s. This code will attempt to stitch the resulting [InspectorNode] trees
-     * together by looking at the parent of each [LayoutInfo].
-     *
-     * If this algorithm is successful the result of this function will be a list with a single
-     * tree.
-     */
-    private fun stitchTreesByLayoutInfo(trees: List<MutableInspectorNode>): List<InspectorNode> {
-        val layoutToTreeMap = IdentityHashMap<LayoutInfo, MutableInspectorNode>()
-        trees.forEach { tree -> tree.layoutNodes.forEach { layoutToTreeMap[it] = tree } }
-        trees.forEach { tree ->
-            val layout = tree.layoutNodes.lastOrNull()
-            val parentLayout = generateSequence(layout) { it.parentInfo }.firstOrNull {
-                val otherTree = layoutToTreeMap[it]
-                otherTree != null && otherTree != tree
-            }
-            if (parentLayout != null) {
-                val ownerNode = claimedNodes[parentLayout]
-                val ownerTree = layoutToTreeMap[parentLayout]
-                if (ownerNode != null && ownerTree != null) {
-                    ownerMap.getOrPut(ownerNode) { mutableListOf() }.add(tree)
-                    treeMap.getOrPut(ownerTree) { mutableListOf() }.add(tree)
-                }
-            }
-        }
-        var parentTree = findDeepParentTree()
-        while (parentTree != null) {
-            addSubTrees(parentTree)
-            treeMap.remove(parentTree)
-            parentTree = findDeepParentTree()
-        }
-        val result = mutableListOf<InspectorNode>()
-        trees.asSequence().filter { !stitched.contains(it) }.forEach { addTree(result, it) }
-        return result
-    }
-
-    /**
-     * Return a parent tree where the children trees (to be stitched under the parent) are not
-     * a parent themselves. Do this to avoid rebuilding the same tree more than once.
-     */
-    private fun findDeepParentTree(): MutableInspectorNode? =
-        treeMap.entries.asSequence()
-            .filter { (_, children) -> children.none { treeMap.containsKey(it) } }
-            .firstOrNull()?.key
-
-    private fun addSubTrees(tree: MutableInspectorNode) {
-        for ((index, child) in tree.children.withIndex()) {
-            tree.children[index] = addSubTrees(child) ?: child
-        }
-    }
-
-    /**
-     * Rebuild [node] with any possible sub trees added (stitched in).
-     * Return the rebuild node, or null if no changes were found in this node or its children.
-     * Lazily allocate the new node to avoid unnecessary allocations.
-     */
-    private fun addSubTrees(node: InspectorNode): InspectorNode? {
-        var newNode: MutableInspectorNode? = null
-        for ((index, child) in node.children.withIndex()) {
-            val newChild = addSubTrees(child)
-            if (newChild != null) {
-                val newCopy = newNode ?: newNode(node)
-                newCopy.children[index] = newChild
-                newNode = newCopy
-            }
-        }
-        val trees = ownerMap[node]
-        if (trees == null && newNode == null) {
-            return null
-        }
-        val newCopy = newNode ?: newNode(node)
-        if (trees != null) {
-            trees.forEach { addTree(newCopy.children, it) }
-            stitched.addAll(trees)
-        }
-        return buildAndRelease(newCopy)
-    }
-
-    /**
-     * Add [tree] to the end of the [out] list.
-     * The root nodes of [tree] may be a fake node that hold a list of [LayoutInfo].
-     */
-    private fun addTree(
-        out: MutableList<InspectorNode>,
-        tree: MutableInspectorNode
-    ): List<InspectorNode> {
-        tree.children.forEach {
-            if (it.name.isNotEmpty()) {
-                out.add(it)
-            } else {
-                out.addAll(it.children)
-            }
-        }
-        return out
-    }
-
-    @OptIn(InternalComposeApi::class, UiToolingDataApi::class)
-    private fun convert(table: CompositionData): MutableInspectorNode {
-        val fakeParent = newNode()
-        addToParent(fakeParent, listOf(convert(table.asTree())), buildFakeChildNodes = true)
-        return fakeParent
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun convert(group: Group): MutableInspectorNode {
-        val children = convertChildren(group)
-        val parent = parse(group)
-        addToParent(parent, children)
-        return parent
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun convertChildren(group: Group): List<MutableInspectorNode> {
-        if (group.children.isEmpty()) {
-            return emptyList()
-        }
-        val result = mutableListOf<MutableInspectorNode>()
-        for (child in group.children) {
-            val node = convert(child)
-            if (node.name.isNotEmpty() || node.children.isNotEmpty() ||
-                node.id != 0L || node.layoutNodes.isNotEmpty()
-            ) {
-                result.add(node)
-            } else {
-                release(node)
-            }
-        }
-        return result
-    }
-
-    /**
-     * Adds the nodes in [input] to the children of [parentNode].
-     * Nodes without a reference to a wanted Composable are skipped unless [buildFakeChildNodes].
-     * A single skipped render id and layoutNode will be added to [parentNode].
-     */
-    private fun addToParent(
-        parentNode: MutableInspectorNode,
-        input: List<MutableInspectorNode>,
-        buildFakeChildNodes: Boolean = false
-    ) {
-        var id: Long? = null
-        input.forEach { node ->
-            if (node.name.isEmpty() && !(buildFakeChildNodes && node.layoutNodes.isNotEmpty())) {
-                parentNode.children.addAll(node.children)
-                if (node.id != 0L) {
-                    // If multiple siblings with a render ids are dropped:
-                    // Ignore them all. And delegate the drawing to a parent in the inspector.
-                    id = if (id == null) node.id else 0L
-                }
-            } else {
-                node.id = if (node.id != 0L) node.id else --generatedId
-                val resultNode = node.build()
-                // TODO: replace getOrPut with putIfAbsent which requires API level 24
-                node.layoutNodes.forEach { claimedNodes.getOrPut(it) { resultNode } }
-                parentNode.children.add(resultNode)
-            }
-            if (node.bounds.isNotEmpty() && sameBoundingRectangle(parentNode, node)) {
-                parentNode.bounds = node.bounds
-            }
-            parentNode.layoutNodes.addAll(node.layoutNodes)
-            release(node)
-        }
-        val nodeId = id
-        parentNode.id = if (parentNode.id == 0L && nodeId != null) nodeId else parentNode.id
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun parse(group: Group): MutableInspectorNode {
-        val node = newNode()
-        node.id = getRenderNode(group)
-        parsePosition(group, node)
-        parseLayoutInfo(group, node)
-        if (node.height <= 0 && node.width <= 0) {
-            return markUnwanted(node)
-        }
-        if (!parseCallLocation(group, node) && group.name.isNullOrEmpty()) {
-            return markUnwanted(node)
-        }
-        group.name?.let { node.name = it }
-        if (unwantedGroup(node)) {
-            return markUnwanted(node)
-        }
-        addParameters(group.parameters, node)
-        return node
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun parsePosition(group: Group, node: MutableInspectorNode) {
-        val box = group.box
-        node.top = box.top
-        node.left = box.left
-        node.height = box.bottom - box.top
-        node.width = box.right - box.left
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun parseLayoutInfo(group: Group, node: MutableInspectorNode) {
-        val layoutInfo = (group as? NodeGroup)?.node as? LayoutInfo ?: return
-        node.layoutNodes.add(layoutInfo)
-        val box = group.box
-        val size = box.size.toSize()
-        val coordinates = layoutInfo.coordinates
-        val topLeft = toIntOffset(coordinates.localToWindow(Offset.Zero))
-        val topRight = toIntOffset(coordinates.localToWindow(Offset(size.width, 0f)))
-        val bottomRight = toIntOffset(coordinates.localToWindow(Offset(size.width, size.height)))
-        val bottomLeft = toIntOffset(coordinates.localToWindow(Offset(0f, size.height)))
-        if (
-            topLeft.x == box.left && topLeft.y == box.top &&
-            topRight.x == box.right && topRight.y == box.top &&
-            bottomRight.x == box.right && bottomRight.y == box.bottom &&
-            bottomLeft.x == box.left && bottomLeft.y == box.bottom
-        ) {
-            return
-        }
-        node.bounds = intArrayOf(
-            topLeft.x, topLeft.y,
-            topRight.x, topRight.y,
-            bottomRight.x, bottomRight.y,
-            bottomLeft.x, bottomLeft.y
-        )
-    }
-
-    private fun toIntOffset(offset: Offset): IntOffset =
-        IntOffset(offset.x.roundToInt(), offset.y.roundToInt())
-
-    private fun markUnwanted(node: MutableInspectorNode): MutableInspectorNode =
-        node.apply { markUnwanted() }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun parseCallLocation(group: Group, node: MutableInspectorNode): Boolean {
-        val location = group.location ?: return false
-        val fileName = location.sourceFile ?: return false
-        node.fileName = fileName
-        node.packageHash = location.packageHash
-        node.lineNumber = location.lineNumber
-        node.offset = location.offset
-        node.length = location.length
-        return true
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun getRenderNode(group: Group): Long =
-        group.modifierInfo.asSequence()
-            .map { it.extra }
-            .filterIsInstance<GraphicLayerInfo>()
-            .map { it.layerId }
-            .firstOrNull() ?: 0
-
-    @OptIn(UiToolingDataApi::class)
-    private fun addParameters(parameters: List<ParameterInformation>, node: MutableInspectorNode) =
-        parameters.forEach { addParameter(it, node) }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun addParameter(parameter: ParameterInformation, node: MutableInspectorNode) {
-        val castedValue = castValue(parameter)
-        node.parameters.add(RawParameter(parameter.name, castedValue))
-    }
-
-    @OptIn(UiToolingDataApi::class)
-    private fun castValue(parameter: ParameterInformation): Any? {
-        val value = parameter.value ?: return null
-        if (parameter.inlineClass == null) return value
-        return inlineClassConverter.castParameterValue(parameter.inlineClass, value)
-    }
-
-    private fun unwantedGroup(node: MutableInspectorNode): Boolean =
-        node.packageHash in systemPackages && (hideSystemNodes || node.name in unwantedCalls)
-
-    private fun newNode(): MutableInspectorNode =
-        if (cache.isNotEmpty()) cache.pop() else MutableInspectorNode()
-
-    private fun newNode(copyFrom: InspectorNode): MutableInspectorNode =
-        newNode().shallowCopy(copyFrom)
-
-    private fun release(node: MutableInspectorNode) {
-        node.reset()
-        cache.add(node)
-    }
-
-    private fun buildAndRelease(node: MutableInspectorNode): InspectorNode {
-        val result = node.build()
-        release(node)
-        return result
-    }
-
-    private fun sameBoundingRectangle(
-        node1: MutableInspectorNode,
-        node2: MutableInspectorNode
-    ): Boolean =
-        node1.left == node2.left &&
-            node1.top == node2.top &&
-            node1.width == node2.width &&
-            node1.height == node2.height
-}
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/NodeParameter.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/NodeParameter.kt
deleted file mode 100644
index 86bd7ad..0000000
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/NodeParameter.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-/**
- * Holds data representing a Composable parameter for the Layout Inspector.
- */
-class NodeParameter internal constructor(
-    /**
-     * The name of the parameter.
-     */
-    val name: String,
-
-    /**
-     * The type of the parameter.
-     */
-    val type: ParameterType,
-
-    /**
-     * The value of the parameter.
-     */
-    val value: Any?
-) {
-    /**
-     * Sub elements of the parameter.
-     */
-    val elements = mutableListOf<NodeParameter>()
-}
-
-/**
- * The type of a parameter.
- */
-enum class ParameterType {
-    String,
-    Boolean,
-    Double,
-    Float,
-    Int32,
-    Int64,
-    Color,
-    Resource,
-    DimensionDp,
-    DimensionSp,
-    DimensionEm,
-    Lambda,
-    FunctionReference,
-}
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/ParameterFactory.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/ParameterFactory.kt
deleted file mode 100644
index 0e935b5..0000000
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/inspector/ParameterFactory.kt
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.tooling.inspector
-
-import android.util.Log
-import android.view.View
-import androidx.compose.foundation.shape.CornerSize
-import androidx.compose.runtime.internal.ComposableLambda
-import androidx.compose.ui.AbsoluteAlignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.Shadow
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.InspectableValue
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.font.FontListFontFamily
-import androidx.compose.ui.text.font.FontStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.font.ResourceFont
-import androidx.compose.ui.text.intl.Locale
-import androidx.compose.ui.text.intl.LocaleList
-import androidx.compose.ui.text.style.BaselineShift
-import androidx.compose.ui.text.style.TextDecoration
-import androidx.compose.ui.tooling.inspector.ParameterType.DimensionDp
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.TextUnit
-import androidx.compose.ui.unit.TextUnitType
-import java.lang.reflect.Field
-import kotlin.jvm.internal.FunctionReference
-import kotlin.jvm.internal.Lambda
-import kotlin.math.abs
-import kotlin.reflect.KClass
-import kotlin.reflect.KProperty1
-import kotlin.reflect.full.allSuperclasses
-import kotlin.reflect.full.declaredMemberProperties
-import kotlin.reflect.jvm.isAccessible
-import kotlin.reflect.jvm.javaField
-import kotlin.reflect.jvm.javaGetter
-import java.lang.reflect.Modifier as JavaModifier
-
-private const val MAX_RECURSIONS = 10
-private const val MAX_ITERABLE = 25
-
-/**
- * Factory of [NodeParameter]s.
- *
- * Each parameter value is converted to a user readable value.
- */
-internal class ParameterFactory(private val inlineClassConverter: InlineClassConverter) {
-    /**
-     * A map from known values to a user readable string representation.
-     */
-    private val valueLookup = mutableMapOf<Any, String>()
-
-    /**
-     * The classes we have loaded constants from.
-     */
-    private val valuesLoaded = mutableSetOf<Class<*>>()
-
-    /**
-     * Do not load constant names from instances of these classes.
-     * We prefer showing the raw values of Color and Dimensions.
-     */
-    private val ignoredClasses = listOf(Color::class.java, Dp::class.java)
-    private var creatorCache: ParameterCreator? = null
-    private val kotlinReflectionSupported = try {
-        Class.forName("kotlin.reflect.full.KClasses")
-        true
-    } catch (ex: Exception) {
-        false
-    }
-
-    /**
-     * Do not decompose instances or lookup constants from these package prefixes
-     *
-     * The following instances are known to contain self recursion:
-     * - kotlinx.coroutines.flow.StateFlowImpl
-     * - androidx.compose.ui.node.LayoutNode
-     */
-    private val ignoredPackagePrefixes = listOf(
-        "android.", "java.", "javax.", "kotlinx.", "androidx.compose.ui.node."
-    )
-
-    var density = Density(1.0f)
-
-    init {
-        val textDecorationCombination = TextDecoration.combine(
-            listOf(TextDecoration.LineThrough, TextDecoration.Underline)
-        )
-        valueLookup[textDecorationCombination] = "LineThrough+Underline"
-        valueLookup[Color.Unspecified] = "Unspecified"
-        valueLookup[RectangleShape] = "RectangleShape"
-        valuesLoaded.add(Enum::class.java)
-        valuesLoaded.add(Any::class.java)
-
-        // AbsoluteAlignment is not found from an instance of BiasAbsoluteAlignment,
-        // because Alignment has no file level class.
-        loadConstantsFromEnclosedClasses(AbsoluteAlignment::class.java)
-    }
-
-    /**
-     * Create a [NodeParameter] from the specified parameter [name] and [value].
-     *
-     * Attempt to convert the value to a user readable value.
-     * For now: return null when a conversion is not possible/found.
-     */
-    fun create(node: InspectorNode, name: String, value: Any?): NodeParameter? {
-        val creator = creatorCache ?: ParameterCreator()
-        try {
-            return creator.create(node, name, value)
-        } finally {
-            creatorCache = creator
-        }
-    }
-
-    private fun loadConstantsFrom(javaClass: Class<*>) {
-        if (valuesLoaded.contains(javaClass) ||
-            ignoredPackagePrefixes.any { javaClass.name.startsWith(it) }
-        ) {
-            return
-        }
-        val related = generateSequence(javaClass) { it.superclass }.plus(javaClass.interfaces)
-        related.forEach { aClass ->
-            val topClass = generateSequence(aClass) { safeEnclosingClass(it) }.last()
-            loadConstantsFromEnclosedClasses(topClass)
-            findPackageLevelClass(topClass)?.let { loadConstantsFromStaticFinal(it) }
-        }
-    }
-
-    private fun safeEnclosingClass(klass: Class<*>): Class<*>? = try {
-        klass.enclosingClass
-    } catch (_: Error) {
-        // Exceptions seen on API 23...
-        null
-    }
-
-    private fun findPackageLevelClass(javaClass: Class<*>): Class<*>? = try {
-        // Note: This doesn't work when @file.JvmName is specified
-        Class.forName("${javaClass.name}Kt")
-    } catch (ex: Throwable) {
-        null
-    }
-
-    private fun loadConstantsFromEnclosedClasses(javaClass: Class<*>) {
-        if (valuesLoaded.contains(javaClass)) {
-            return
-        }
-        loadConstantsFromObjectInstance(javaClass.kotlin)
-        loadConstantsFromStaticFinal(javaClass)
-        valuesLoaded.add(javaClass)
-        javaClass.declaredClasses.forEach { loadConstantsFromEnclosedClasses(it) }
-    }
-
-    /**
-     * Load all constants from companion objects and singletons
-     *
-     * Exclude: primary types and types of ignoredClasses, open and lateinit vals.
-     */
-    private fun loadConstantsFromObjectInstance(kClass: KClass<*>) {
-        try {
-            val instance = kClass.objectInstance ?: return
-            kClass.declaredMemberProperties.asSequence()
-                .filter { it.isFinal && !it.isLateinit }
-                .mapNotNull { constantValueOf(it, instance)?.let { key -> Pair(key, it.name) } }
-                .filter { !ignoredValue(it.first) }
-                .toMap(valueLookup)
-        } catch (_: Throwable) {
-            // KT-16479 :  kotlin reflection does currently not support packages and files.
-            // We load top level values using Java reflection instead.
-            // Ignore other reflection errors as well
-        }
-    }
-
-    /**
-     * Load all constants from top level values from Java.
-     *
-     * Exclude: primary types and types of ignoredClasses.
-     * Since this is Java, inline types will also (unfortunately) be excluded.
-     */
-    private fun loadConstantsFromStaticFinal(javaClass: Class<*>) {
-        try {
-            javaClass.declaredMethods.asSequence()
-                .filter {
-                    it.returnType != Void.TYPE &&
-                        JavaModifier.isStatic(it.modifiers) &&
-                        JavaModifier.isFinal(it.modifiers) &&
-                        !it.returnType.isPrimitive &&
-                        it.parameterTypes.isEmpty() &&
-                        it.name.startsWith("get")
-                }
-                .mapNotNull { javaClass.getDeclaredField(it.name.substring(3)) }
-                .mapNotNull { constantValueOf(it)?.let { key -> Pair(key, it.name) } }
-                .filter { !ignoredValue(it.first) }
-                .toMap(valueLookup)
-        } catch (_: ReflectiveOperationException) {
-            // ignore reflection errors
-        } catch (_: NoClassDefFoundError) {
-            // ignore missing classes on lower level SDKs
-        }
-    }
-
-    private fun constantValueOf(field: Field?): Any? = try {
-        field?.isAccessible = true
-        field?.get(null)
-    } catch (_: ReflectiveOperationException) {
-        // ignore reflection errors
-        null
-    }
-
-    private fun constantValueOf(property: KProperty1<out Any, *>, instance: Any): Any? = try {
-        val field = property.javaField
-        field?.isAccessible = true
-        inlineClassConverter.castParameterValue(inlineResultClass(property), field?.get(instance))
-    } catch (_: ReflectiveOperationException) {
-        // ignore reflection errors
-        null
-    }
-
-    private fun inlineResultClass(property: KProperty1<out Any, *>): String? {
-        // The Java getter name will be mangled if it contains parameters of an inline class.
-        // The mangled part starts with a '-'.
-        if (property.javaGetter?.name?.contains('-') == true) {
-            return property.returnType.toString()
-        }
-        return null
-    }
-
-    private fun ignoredValue(value: Any?): Boolean =
-        value == null ||
-            ignoredClasses.any { ignored -> ignored.isInstance(value) } ||
-            value::class.java.isPrimitive
-
-    /**
-     * Convenience class for building [NodeParameter]s.
-     */
-    private inner class ParameterCreator {
-        private var node: InspectorNode? = null
-        private var recursions = 0
-
-        fun create(node: InspectorNode, name: String, value: Any?): NodeParameter? = try {
-            this.node = node
-            recursions = 0
-            create(name, value)
-        } finally {
-            this.node = null
-        }
-
-        private fun create(name: String, value: Any?): NodeParameter? {
-            if (value == null || recursions >= MAX_RECURSIONS) {
-                return null
-            }
-            try {
-                recursions++
-                createFromConstant(name, value)?.let { return it }
-                return when (value) {
-                    is AnnotatedString -> NodeParameter(name, ParameterType.String, value.text)
-                    is BaselineShift -> createFromBaselineShift(name, value)
-                    is Boolean -> NodeParameter(name, ParameterType.Boolean, value)
-                    is ComposableLambda -> createFromCLambda(name, value)
-                    is Color -> NodeParameter(name, ParameterType.Color, value.toArgb())
-                    is CornerSize -> createFromCornerSize(name, value)
-                    is Double -> NodeParameter(name, ParameterType.Double, value)
-                    is Dp -> NodeParameter(name, DimensionDp, value.value)
-                    is Enum<*> -> NodeParameter(name, ParameterType.String, value.toString())
-                    is Float -> NodeParameter(name, ParameterType.Float, value)
-                    is FunctionReference -> NodeParameter(
-                        name, ParameterType.FunctionReference, arrayOf<Any>(value, value.name)
-                    )
-                    is FontListFontFamily -> createFromFontListFamily(name, value)
-                    is FontWeight -> NodeParameter(name, ParameterType.Int32, value.weight)
-                    is Modifier -> createFromModifier(name, value)
-                    is InspectableValue -> createFromInspectableValue(name, value)
-                    is Int -> NodeParameter(name, ParameterType.Int32, value)
-                    is Iterable<*> -> createFromIterable(name, value)
-                    is Lambda<*> -> createFromLambda(name, value)
-                    is Locale -> NodeParameter(name, ParameterType.String, value.toString())
-                    is LocaleList ->
-                        NodeParameter(name, ParameterType.String, value.localeList.joinToString())
-                    is Long -> NodeParameter(name, ParameterType.Int64, value)
-                    is Offset -> createFromOffset(name, value)
-                    is Shadow -> createFromShadow(name, value)
-                    is SolidColor -> NodeParameter(name, ParameterType.Color, value.value.toArgb())
-                    is String -> NodeParameter(name, ParameterType.String, value)
-                    is TextUnit -> createFromTextUnit(name, value)
-                    is ImageVector -> createFromImageVector(name, value)
-                    is View -> NodeParameter(name, ParameterType.String, value.javaClass.simpleName)
-                    else -> createFromKotlinReflection(name, value)
-                }
-            } finally {
-                recursions--
-            }
-        }
-
-        private fun createFromBaselineShift(name: String, value: BaselineShift): NodeParameter {
-            val converted = when (value.multiplier) {
-                BaselineShift.None.multiplier -> "None"
-                BaselineShift.Subscript.multiplier -> "Subscript"
-                BaselineShift.Superscript.multiplier -> "Superscript"
-                else -> return NodeParameter(name, ParameterType.Float, value.multiplier)
-            }
-            return NodeParameter(name, ParameterType.String, converted)
-        }
-
-        private fun createFromCLambda(name: String, value: ComposableLambda): NodeParameter? = try {
-            val lambda = value.javaClass.getDeclaredField("_block")
-                .apply { isAccessible = true }
-                .get(value)
-            NodeParameter(name, ParameterType.Lambda, arrayOf<Any?>(lambda))
-        } catch (_: Throwable) {
-            null
-        }
-
-        private fun createFromConstant(name: String, value: Any): NodeParameter? {
-            if (!kotlinReflectionSupported) {
-                return null
-            }
-            loadConstantsFrom(value.javaClass)
-            return valueLookup[value]?.let { NodeParameter(name, ParameterType.String, it) }
-        }
-
-        private fun createFromCornerSize(name: String, value: CornerSize): NodeParameter {
-            val size = Size(node!!.width.toFloat(), node!!.height.toFloat())
-            val pixels = value.toPx(size, density)
-            return NodeParameter(name, DimensionDp, with(density) { pixels.toDp().value })
-        }
-
-        // For now: select ResourceFontFont closest to W400 and Normal, and return the resId
-        private fun createFromFontListFamily(
-            name: String,
-            value: FontListFontFamily
-        ): NodeParameter? =
-            findBestResourceFont(value)?.let {
-                NodeParameter(name, ParameterType.Resource, it.resId)
-            }
-
-        private fun createFromKotlinReflection(name: String, value: Any): NodeParameter? {
-            val kClass = value::class
-            val qualifiedName = kClass.qualifiedName
-            if (kClass.simpleName == null ||
-                qualifiedName == null ||
-                ignoredPackagePrefixes.any { qualifiedName.startsWith(it) } ||
-                !kotlinReflectionSupported
-            ) {
-                // Exit without creating a parameter for:
-                // - internal synthetic classes
-                // - certain android packages
-                // - if kotlin reflection library not available
-                return null
-            }
-            val parameter = NodeParameter(name, ParameterType.String, kClass.simpleName)
-            val properties = mutableMapOf<String, KProperty1<Any, *>>()
-            try {
-                sequenceOf(kClass).plus(kClass.allSuperclasses.asSequence())
-                    .flatMap { it.declaredMemberProperties.asSequence() }
-                    .filterIsInstance<KProperty1<Any, *>>()
-                    .associateByTo(properties) { it.name }
-            } catch (ex: Throwable) {
-                Log.w("Compose", "Could not decompose ${kClass.simpleName}")
-                return parameter
-            }
-            properties.values.mapNotNullTo(parameter.elements) {
-                create(it.name, valueOf(it, value))
-            }
-            return parameter
-        }
-
-        private fun valueOf(property: KProperty1<Any, *>, instance: Any): Any? = try {
-            property.isAccessible = true
-            // Bug in kotlin reflection API: if the type is a nullable inline type with a null
-            // value, we get an IllegalArgumentException in this line:
-            property.get(instance)
-        } catch (ex: Throwable) {
-            // TODO: Remove this warning since this is expected with nullable inline types
-            Log.w("Compose", "Could not get value of ${property.name}")
-            null
-        }
-
-        private fun createFromInspectableValue(
-            name: String,
-            value: InspectableValue
-        ): NodeParameter {
-            val tempValue = value.valueOverride ?: ""
-            val parameterName = name.ifEmpty { value.nameFallback } ?: "element"
-            val parameterValue = if (tempValue is InspectableValue) "" else tempValue
-            val parameter = create(parameterName, parameterValue)
-                ?: NodeParameter(parameterName, ParameterType.String, "")
-            val elements = parameter.elements
-            value.inspectableElements.mapNotNullTo(elements) { create(it.name, it.value) }
-            return parameter
-        }
-
-        private fun createFromIterable(name: String, value: Iterable<*>): NodeParameter {
-            val parameter = NodeParameter(name, ParameterType.String, "")
-            val elements = parameter.elements
-            value.asSequence()
-                .mapNotNull { create(elements.size.toString(), it) }
-                .takeWhile { elements.size < MAX_ITERABLE }
-                .toCollection(elements)
-            return parameter
-        }
-
-        private fun createFromLambda(name: String, value: Lambda<*>): NodeParameter =
-            NodeParameter(name, ParameterType.Lambda, arrayOf<Any>(value))
-
-        private fun createFromModifier(name: String, value: Modifier): NodeParameter? =
-            when {
-                name.isNotEmpty() -> {
-                    val parameter = NodeParameter(name, ParameterType.String, "")
-                    val elements = parameter.elements
-                    value.foldIn(elements) { acc, m ->
-                        create("", m)?.let { param -> acc.apply { add(param) } } ?: acc
-                    }
-                    parameter
-                }
-                value is InspectableValue -> createFromInspectableValue(name, value)
-                else -> null
-            }
-
-        private fun createFromOffset(name: String, value: Offset): NodeParameter {
-            val parameter = NodeParameter(name, ParameterType.String, Offset::class.java.simpleName)
-            val elements = parameter.elements
-            elements.add(NodeParameter("x", DimensionDp, with(density) { value.x.toDp().value }))
-            elements.add(NodeParameter("y", DimensionDp, with(density) { value.y.toDp().value }))
-            return parameter
-        }
-
-        // Special handling of blurRadius: convert to dp:
-        private fun createFromShadow(name: String, value: Shadow): NodeParameter? {
-            val parameter = createFromKotlinReflection(name, value) ?: return null
-            val elements = parameter.elements
-            val index = elements.indexOfFirst { it.name == "blurRadius" }
-            if (index >= 0) {
-                val blurRadius = with(density) { value.blurRadius.toDp().value }
-                elements[index] = NodeParameter("blurRadius", DimensionDp, blurRadius)
-            }
-            return parameter
-        }
-
-        @Suppress("DEPRECATION")
-        private fun createFromTextUnit(name: String, value: TextUnit): NodeParameter =
-            when (value.type) {
-                TextUnitType.Sp -> NodeParameter(name, ParameterType.DimensionSp, value.value)
-                TextUnitType.Em -> NodeParameter(name, ParameterType.DimensionEm, value.value)
-                TextUnitType.Unspecified ->
-                    NodeParameter(name, ParameterType.String, "Unspecified")
-            }
-
-        private fun createFromImageVector(name: String, value: ImageVector): NodeParameter =
-            NodeParameter(name, ParameterType.String, value.name)
-
-        /**
-         * Select a resource font among the font in the family to represent the font
-         *
-         * Prefer the font closest to [FontWeight.Normal] and [FontStyle.Normal]
-         */
-        private fun findBestResourceFont(value: FontListFontFamily): ResourceFont? =
-            value.fonts.asSequence().filterIsInstance<ResourceFont>().minByOrNull {
-                abs(it.weight.weight - FontWeight.Normal.weight) + it.style.ordinal
-            }
-    }
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
index 335f16c..b15b091 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt
@@ -20,7 +20,7 @@
 
 import androidx.compose.runtime.Applier
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ComposeNode
+import androidx.compose.runtime.ReusableComposeNode
 import androidx.compose.runtime.SkippableUpdater
 import androidx.compose.runtime.currentComposer
 import androidx.compose.ui.Modifier
@@ -71,7 +71,7 @@
 ) {
     val density = LocalDensity.current
     val layoutDirection = LocalLayoutDirection.current
-    ComposeNode<ComposeUiNode, Applier<Any>>(
+    ReusableComposeNode<ComposeUiNode, Applier<Any>>(
         factory = ComposeUiNode.Constructor,
         update = {
             set(measurePolicy, ComposeUiNode.SetMeasurePolicy)
@@ -192,7 +192,7 @@
     val density = LocalDensity.current
     val layoutDirection = LocalLayoutDirection.current
 
-    ComposeNode<LayoutNode, Applier<Any>>(
+    ReusableComposeNode<LayoutNode, Applier<Any>>(
         factory = LayoutNode.Constructor,
         update = {
             set(materialized, ComposeUiNode.SetModifier)
diff --git a/emoji2/emoji2/api/current.txt b/emoji2/emoji2/api/current.txt
index f69bb70..f723bb9 100644
--- a/emoji2/emoji2/api/current.txt
+++ b/emoji2/emoji2/api/current.txt
@@ -2,7 +2,7 @@
 package androidx.emoji2.text {
 
   public final class DefaultEmojiCompatConfig {
-    method public static androidx.emoji2.text.EmojiCompat.Config? create(android.content.Context);
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
   }
 
   @AnyThread public class EmojiCompat {
diff --git a/emoji2/emoji2/api/public_plus_experimental_current.txt b/emoji2/emoji2/api/public_plus_experimental_current.txt
index f69bb70..f723bb9 100644
--- a/emoji2/emoji2/api/public_plus_experimental_current.txt
+++ b/emoji2/emoji2/api/public_plus_experimental_current.txt
@@ -2,7 +2,7 @@
 package androidx.emoji2.text {
 
   public final class DefaultEmojiCompatConfig {
-    method public static androidx.emoji2.text.EmojiCompat.Config? create(android.content.Context);
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
   }
 
   @AnyThread public class EmojiCompat {
diff --git a/emoji2/emoji2/api/restricted_current.txt b/emoji2/emoji2/api/restricted_current.txt
index f69bb70..f723bb9 100644
--- a/emoji2/emoji2/api/restricted_current.txt
+++ b/emoji2/emoji2/api/restricted_current.txt
@@ -2,7 +2,7 @@
 package androidx.emoji2.text {
 
   public final class DefaultEmojiCompatConfig {
-    method public static androidx.emoji2.text.EmojiCompat.Config? create(android.content.Context);
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
   }
 
   @AnyThread public class EmojiCompat {
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
index a03db5a..1c9db25 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/DefaultEmojiCompatConfig.java
@@ -93,8 +93,9 @@
      * could be found.
      */
     @Nullable
-    public static EmojiCompat.Config create(@NonNull Context context) {
-        return new DefaultEmojiCompatConfigFactory(null).create(context);
+    public static FontRequestEmojiCompatConfig create(@NonNull Context context) {
+        return (FontRequestEmojiCompatConfig) new DefaultEmojiCompatConfigFactory(null)
+                .create(context);
     }
 
     /**
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
index b5714595..69fd6904 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompatInitializer.java
@@ -17,8 +17,17 @@
 package androidx.emoji2.text;
 
 import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.WorkerThread;
+import androidx.core.os.TraceCompat;
 import androidx.startup.Initializer;
 
 import java.util.Collections;
@@ -27,16 +36,21 @@
 /**
  * Initializer for configuring EmojiCompat with the system installed downloadable font provider.
  *
+ * <p>This initializer will initialize EmojiCompat immediately then defer loading the font for a
+ * short delay to avoid delaying application startup. Typically, the font will be loaded shortly
+ * after the first screen of your application loads, which means users may see system emoji
+ * briefly prior to the compat font loading.</p>
+ *
  * <p>This is the recommended configuration for all apps that don't need specialized configuration,
- * and don't need to control the thread that initialization runs on. For more information see
- * {@link androidx.emoji2.text.DefaultEmojiCompatConfig}.</p>
+ * and don't need to control the background thread that initialization runs on. For more information
+ * see {@link androidx.emoji2.text.DefaultEmojiCompatConfig}.</p>
  *
  * <p>In addition to the reasons listed in {@code DefaultEmojiCompatConfig} you may wish to disable
  * this automatic configuration if you intend to call initialization from an existing background
  * thread pool in your application.</p>
  *
- * <p></p>This is enabled by default by including the `:emoji2:emoji2` gradle artifact. To disable
- * the default configuration (and allow manual configuration) add this to your manifest:</p>
+ * <p>This is enabled by default by including the {@code :emoji2:emoji2} gradle artifact. To
+ * disable the default configuration (and allow manual configuration) add this to your manifest:</p>
  *
  * <pre>
  *     <provider
@@ -52,6 +66,8 @@
  * @see androidx.emoji2.text.DefaultEmojiCompatConfig
  */
 public class EmojiCompatInitializer implements Initializer<Boolean> {
+    private static final long STARTUP_THREAD_CREATION_DELAY_MS = 500L;
+    private static final String S_INITIALIZER_THREAD_NAME = "EmojiCompatInitializer";
 
     /**
      * Initialize EmojiCompat with the app's context.
@@ -62,8 +78,18 @@
     @NonNull
     @Override
     public Boolean create(@NonNull Context context) {
-        // note: super create requires this be non-null, share if the configuration was successful
-        // TODO(b/187328685): re-enable this after investigating startup performance
+        if (Build.VERSION.SDK_INT >= 19) {
+            final Handler mainHandler;
+            if (Build.VERSION.SDK_INT >= 28) {
+                mainHandler = Handler28Impl.createAsync(Looper.getMainLooper());
+            } else {
+                mainHandler = new Handler(Looper.getMainLooper());
+            }
+            EmojiCompat.init(new BackgroundDefaultConfig(context));
+            mainHandler.postDelayed(new LoadEmojiCompatRunnable(),
+                    STARTUP_THREAD_CREATION_DELAY_MS);
+            return true;
+        }
         return false;
     }
 
@@ -75,4 +101,109 @@
     public List<Class<? extends Initializer<?>>> dependencies() {
         return Collections.emptyList();
     }
+
+    static class LoadEmojiCompatRunnable implements Runnable {
+        @Override
+        public void run() {
+            try {
+                // this is main thread, so mark what we're doing (this trace includes thread
+                // start time in BackgroundLoadingLoader.load
+                TraceCompat.beginSection("EmojiCompat.EmojiCompatInitializer.run");
+                if (EmojiCompat.isConfigured()) {
+                    EmojiCompat.get().load();
+                }
+            } finally {
+                TraceCompat.endSection();
+            }
+        }
+    }
+
+    @RequiresApi(19)
+    static class BackgroundDefaultConfig extends EmojiCompat.Config {
+        protected BackgroundDefaultConfig(Context context) {
+            super(new BackgroundDefaultLoader(context));
+            setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+        }
+    }
+
+    @RequiresApi(19)
+    static class BackgroundDefaultLoader implements EmojiCompat.MetadataRepoLoader {
+        private final Context mContext;
+
+        BackgroundDefaultLoader(Context context) {
+            mContext = context.getApplicationContext();
+        }
+
+        @Nullable
+        private HandlerThread mThread;
+
+        @Override
+        public void load(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback) {
+            Handler handler = getThreadHandler();
+            handler.post(() -> doLoad(loaderCallback, handler));
+        }
+
+        @WorkerThread
+        void doLoad(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback,
+                @NonNull Handler handler) {
+            try {
+                FontRequestEmojiCompatConfig config = DefaultEmojiCompatConfig.create(mContext);
+                if (config == null) {
+                    throw new RuntimeException("EmojiCompat font provider not available on this "
+                            + "device.");
+                }
+                config.setHandler(handler);
+                config.getMetadataRepoLoader().load(new EmojiCompat.MetadataRepoLoaderCallback() {
+                    @Override
+                    public void onLoaded(@NonNull MetadataRepo metadataRepo) {
+                        try {
+                            // main thread is notified before returning, so we can quit now
+                            loaderCallback.onLoaded(metadataRepo);
+                        } finally {
+                            quitHandlerThread();
+                        }
+                    }
+
+                    @Override
+                    public void onFailed(@Nullable Throwable throwable) {
+                        try {
+                            // main thread is notified before returning, so we can quit now
+                            loaderCallback.onFailed(throwable);
+                        } finally {
+                            quitHandlerThread();
+                        }
+                    }
+                });
+            } catch (Throwable t) {
+                loaderCallback.onFailed(t);
+                quitHandlerThread();
+            }
+        }
+
+        void quitHandlerThread() {
+            if (mThread != null) {
+                mThread.quitSafely();
+            }
+        }
+
+        @NonNull
+        private Handler getThreadHandler() {
+            mThread = new HandlerThread(S_INITIALIZER_THREAD_NAME,
+                    Process.THREAD_PRIORITY_BACKGROUND);
+            mThread.start();
+            return new Handler(mThread.getLooper());
+        }
+    }
+
+    @RequiresApi(28)
+    private static class Handler28Impl {
+        private Handler28Impl() {
+            // Non-instantiable.
+        }
+
+        // avoid aligning with vsync when available (API 28+)
+        public static Handler createAsync(Looper looper) {
+            return Handler.createAsync(looper);
+        }
+    }
 }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
index 1e3006e..c261675 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
@@ -32,6 +32,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.TypefaceCompatUtil;
+import androidx.core.os.TraceCompat;
 import androidx.core.provider.FontRequest;
 import androidx.core.provider.FontsContractCompat;
 import androidx.core.provider.FontsContractCompat.FontFamilyResult;
@@ -165,6 +166,10 @@
      * given FontRequest.
      */
     private static class FontRequestMetadataLoader implements EmojiCompat.MetadataRepoLoader {
+        private static final String S_TRACE_BUILD_TYPEFACE =
+                "EmojiCompat.FontRequestEmojiCompatConfig.buildTypeface";
+        private static final String S_TRACE_THREAD_CREATION =
+                "EmojiCompat.FontRequestEmojiCompatConfig.threadCreation";
         private final @NonNull Context mContext;
         private final @NonNull FontRequest mRequest;
         private final @NonNull FontProviderHelper mFontProviderHelper;
@@ -209,11 +214,17 @@
         public void load(@NonNull final EmojiCompat.MetadataRepoLoaderCallback loaderCallback) {
             Preconditions.checkNotNull(loaderCallback, "LoaderCallback cannot be null");
             synchronized (mLock) {
-                if (mHandler == null) {
-                    // Developer didn't give a thread for fetching. Create our own one.
-                    mThread = new HandlerThread("emojiCompat", Process.THREAD_PRIORITY_BACKGROUND);
-                    mThread.start();
-                    mHandler = new Handler(mThread.getLooper());
+                try {
+                    TraceCompat.beginSection(S_TRACE_THREAD_CREATION);
+                    if (mHandler == null) {
+                        // Developer didn't give a thread for fetching. Create our own one.
+                        mThread = new HandlerThread("emojiCompat",
+                                Process.THREAD_PRIORITY_BACKGROUND);
+                        mThread.start();
+                        mHandler = new Handler(mThread.getLooper());
+                    }
+                } finally {
+                    TraceCompat.endSection();
                 }
                 mHandler.post(new Runnable() {
                     @Override
@@ -312,13 +323,21 @@
                     throw new RuntimeException("fetchFonts result is not OK. (" + resultCode + ")");
                 }
 
-                // TODO: Good to add new API to create Typeface from FD not to open FD twice.
-                final Typeface typeface = mFontProviderHelper.buildTypeface(mContext, font);
-                final ByteBuffer buffer = TypefaceCompatUtil.mmap(mContext, null, font.getUri());
-                if (buffer == null) {
-                    throw new RuntimeException("Unable to open file.");
+                final MetadataRepo metadataRepo;
+                try {
+                    TraceCompat.beginSection(S_TRACE_BUILD_TYPEFACE);
+                    // TODO: Good to add new API to create Typeface from FD not to open FD twice.
+                    final Typeface typeface = mFontProviderHelper.buildTypeface(mContext, font);
+                    final ByteBuffer buffer = TypefaceCompatUtil.mmap(mContext, null,
+                            font.getUri());
+                    if (buffer == null) {
+                        throw new RuntimeException("Unable to open file.");
+                    }
+                    metadataRepo = MetadataRepo.create(typeface, buffer);
+                } finally {
+                    TraceCompat.endSection();
                 }
-                mCallback.onLoaded(MetadataRepo.create(typeface, buffer));
+                mCallback.onLoaded(metadataRepo);
                 cleanUp();
             } catch (Throwable t) {
                 mCallback.onFailed(t);
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
index bc31e26..a168667 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
@@ -24,6 +24,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.os.TraceCompat;
 import androidx.core.util.Preconditions;
 import androidx.emoji2.text.flatbuffer.MetadataList;
 
@@ -41,6 +42,7 @@
      * The default children size of the root node.
      */
     private static final int DEFAULT_ROOT_SIZE = 1024;
+    private static final String S_TRACE_CREATE_REPO = "EmojiCompat.MetadataRepo.create";
 
     /**
      * MetadataList that contains the emoji metadata.
@@ -87,7 +89,12 @@
     @NonNull
     @RestrictTo(RestrictTo.Scope.TESTS)
     public static MetadataRepo create(@NonNull final Typeface typeface) {
-        return new MetadataRepo(typeface, new MetadataList());
+        try {
+            TraceCompat.beginSection(S_TRACE_CREATE_REPO);
+            return new MetadataRepo(typeface, new MetadataList());
+        } finally {
+            TraceCompat.endSection();
+        }
     }
 
     /**
@@ -100,7 +107,12 @@
     @NonNull
     public static MetadataRepo create(@NonNull final Typeface typeface,
             @NonNull final InputStream inputStream) throws IOException {
-        return new MetadataRepo(typeface, MetadataListReader.read(inputStream));
+        try {
+            TraceCompat.beginSection(S_TRACE_CREATE_REPO);
+            return new MetadataRepo(typeface, MetadataListReader.read(inputStream));
+        } finally {
+            TraceCompat.endSection();
+        }
     }
 
     /**
@@ -113,7 +125,12 @@
     @NonNull
     public static MetadataRepo create(@NonNull final Typeface typeface,
             @NonNull final ByteBuffer byteBuffer) throws IOException {
-        return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer));
+        try {
+            TraceCompat.beginSection(S_TRACE_CREATE_REPO);
+            return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer));
+        } finally {
+            TraceCompat.endSection();
+        }
     }
 
     /**
@@ -126,8 +143,14 @@
     @NonNull
     public static MetadataRepo create(@NonNull final AssetManager assetManager,
             @NonNull final String assetPath) throws IOException {
-        final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath);
-        return new MetadataRepo(typeface, MetadataListReader.read(assetManager, assetPath));
+        try {
+            TraceCompat.beginSection(S_TRACE_CREATE_REPO);
+            final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath);
+            return new MetadataRepo(typeface,
+                    MetadataListReader.read(assetManager, assetPath));
+        } finally {
+            TraceCompat.endSection();
+        }
     }
 
     /**
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/README.md b/emoji2/integration-tests/init-disabled-macrobenchmark-target/README.md
new file mode 100644
index 0000000..95567d1
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/README.md
@@ -0,0 +1,2 @@
+A simple app with emoji2 startup initializer removed.
+
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/build.gradle b/emoji2/integration-tests/init-disabled-macrobenchmark-target/build.gradle
new file mode 100644
index 0000000..5f1098a
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.application")
+    id("kotlin-android")
+}
+
+android {
+    buildTypes {
+        release {
+            minifyEnabled true
+            shrinkResources true
+            proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+        }
+    }
+}
+
+dependencies {
+    implementation(KOTLIN_STDLIB)
+    implementation(CONSTRAINT_LAYOUT, { transitive = true })
+    implementation(project(":arch:core:core-runtime"))
+    implementation(project(":appcompat:appcompat"))
+    implementation(project(":startup:startup-runtime"))
+    implementation(MATERIAL)
+}
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..cffda4d
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<!--
+  ~ 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.
+  -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.emoji2.integration.macrobenchmark.disabled.target">
+
+    <application
+        android:label="Emoji2 Init Enabled Macrobenchmark Target"
+        android:allowBackup="false"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat"
+        tools:ignore="MissingApplicationIcon">
+
+        <!-- Profileable to enable macrobenchmark profiling -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+
+        <!--
+        Activities need to be exported so the macrobenchmark can discover them
+        under the new package visibility changes for Android 11.
+         -->
+        <activity
+            android:name=".SimpleTextActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.emoji2.integration.macrobenchmark.disabled.target.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <provider
+            android:name="androidx.startup.InitializationProvider"
+            android:authorities="${applicationId}.androidx-startup"
+            android:exported="false"
+            tools:node="merge">
+            <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
+                tools:node="remove" />
+        </provider>
+    </application>
+</manifest>
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/disabled/target/SimpleTextActivity.kt b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/disabled/target/SimpleTextActivity.kt
new file mode 100644
index 0000000..a4ae6f5
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/disabled/target/SimpleTextActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.emoji2.integration.macrobenchmark.disabled.target
+
+import android.os.Bundle
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+
+class SimpleTextActivity : 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)
+    }
+}
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/layout/activity_main.xml b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..6ec3889
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+-->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/txtNotice"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        android:textSize="50sp"
+        tools:text="🐻‍❄️ (disabled)" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..207eaaa
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<resources>
+    <string name="app_notice">"🐻‍❄️" Appcompat emoji2 (disabled) test app.</string>
+</resources>
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle b/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle
new file mode 100644
index 0000000..1ef079d
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/build.gradle
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 28
+    }
+}
+
+dependencies {
+    androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
+    androidTestImplementation(project(":internal-testutils-macrobenchmark"))
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+}
+
+def installReleaseTarget = tasks.getByPath(
+    ":emoji2:integration-tests:init-disabled-macrobenchmark-target:installRelease"
+)
+// Define a task dependency so the app is installed before we run macro benchmarks.
+tasks.getByPath(":emoji2:integration-tests:init-disabled-macrobenchmark:connectedCheck")
+    .dependsOn(installReleaseTarget)
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/AndroidManifest.xml b/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..67818b1
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 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.
+  -->
+<manifest package="androidx.emoji2.integration.macrobenchmark.disabled.test"/>
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt b/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt
new file mode 100644
index 0000000..488b9d8
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/disabled/EmojiStartupBenchmark.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.emoji2.integration.macrobenchmark.disabled
+
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.testutils.measureStartup
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class EmojiStartupBenchmark {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    @Test
+    fun disabledstartup() {
+        benchmarkRule.measureStartup(
+            compilationMode = CompilationMode.None,
+            startupMode = StartupMode.COLD,
+            packageName = "androidx.emoji2.integration.macrobenchmark.disabled.target"
+        ) {
+            action = "androidx.emoji2.integration.macrobenchmark.disabled.target.MAIN"
+        }
+    }
+}
diff --git a/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0ca6a87
--- /dev/null
+++ b/emoji2/integration-tests/init-disabled-macrobenchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 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.
+  -->
+<manifest package="androidx.emoji2.integration.macrobenchmark.disabled" />
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/README.md b/emoji2/integration-tests/init-enabled-macrobenchmark-target/README.md
new file mode 100644
index 0000000..890837d
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/README.md
@@ -0,0 +1 @@
+A simple app with emoji2 startup initializer enabled.
\ No newline at end of file
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/build.gradle b/emoji2/integration-tests/init-enabled-macrobenchmark-target/build.gradle
new file mode 100644
index 0000000..9c0aa54
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/build.gradle
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.application")
+    id("kotlin-android")
+}
+
+android {
+    buildTypes {
+        release {
+            minifyEnabled true
+            shrinkResources true
+            proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+        }
+    }
+}
+
+dependencies {
+    implementation(KOTLIN_STDLIB)
+    implementation(CONSTRAINT_LAYOUT, { transitive = true })
+    implementation(project(":arch:core:core-runtime"))
+    implementation(project(":appcompat:appcompat"))
+    implementation(MATERIAL)
+}
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..eff5f4c
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ 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.
+  -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.emoji2.integration.macrobenchmark.enabled.target">
+
+    <application
+        android:label="Emoji2 Init Enabled Macrobenchmark Target"
+        android:allowBackup="false"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AppCompat"
+        tools:ignore="MissingApplicationIcon">
+
+        <!-- Profileable to enable macrobenchmark profiling -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+
+        <!--
+        Activities need to be exported so the macrobenchmark can discover them
+        under the new package visibility changes for Android 11.
+         -->
+        <activity
+            android:name=".SimpleTextActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.emoji2.integration.macrobenchmark.enabled.target.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/enabled/target/SimpleTextActivity.kt b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/enabled/target/SimpleTextActivity.kt
new file mode 100644
index 0000000..e46d648
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/java/androidx/emoji2/integration/macrobenchmark/enabled/target/SimpleTextActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.emoji2.integration.macrobenchmark.enabled.target
+
+import android.os.Bundle
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+
+class SimpleTextActivity : 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)
+    }
+}
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/layout/activity_main.xml b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..c81807d
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+-->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/txtNotice"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        android:textSize="50sp"
+        tools:text="🐻‍❄️" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..11715d5
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark-target/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<resources>
+    <string name="app_notice">"🐻‍❄️" Appcompat emoji2 (enabled) test app.</string>
+</resources>
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle b/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle
new file mode 100644
index 0000000..c9ebc39
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 28
+    }
+}
+
+dependencies {
+    androidTestImplementation(project(":emoji2:emoji2"))
+    androidTestImplementation(project(":benchmark:benchmark-macro-junit4"))
+    androidTestImplementation(project(":internal-testutils-macrobenchmark"))
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+}
+
+def installReleaseTarget = tasks.getByPath(
+        ":emoji2:integration-tests:init-enabled-macrobenchmark-target:installRelease"
+)
+
+// Define a task dependency so the app is installed before we run macro benchmarks.
+tasks.getByPath(":emoji2:integration-tests:init-enabled-macrobenchmark:connectedCheck")
+    .dependsOn(installReleaseTarget)
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/AndroidManifest.xml b/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..dbacc9c
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 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.
+  -->
+<manifest package="androidx.emoji2.integration.macrobenchmark.enabled.test"/>
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt b/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt
new file mode 100644
index 0000000..61e06cb
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/src/androidTest/java/androidx/emoji2/integration/macrobenchmark/enabled/EmojiStartupBenchmark.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.emoji2.integration.macrobenchmark.enabled
+
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.emoji2.text.DefaultEmojiCompatConfig
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.testutils.measureStartup
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class EmojiStartupBenchmark {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    @Test
+    fun enabledstartup() {
+        // only run this test if the device can configure emoji2
+        assumeTrue(hasDiscoverableFontProviderOnDevice())
+        benchmarkRule.measureStartup(
+            compilationMode = CompilationMode.None,
+            startupMode = StartupMode.COLD,
+            packageName = "androidx.emoji2.integration.macrobenchmark.enabled.target"
+        ) {
+            action = "androidx.emoji2.integration.macrobenchmark.enabled.target.MAIN"
+        }
+    }
+
+    private fun hasDiscoverableFontProviderOnDevice(): Boolean {
+        val context = InstrumentationRegistry.getInstrumentation().targetContext
+        return DefaultEmojiCompatConfig.create(context) != null
+    }
+}
\ No newline at end of file
diff --git a/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml b/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..040c742
--- /dev/null
+++ b/emoji2/integration-tests/init-enabled-macrobenchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 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.
+  -->
+<manifest package="androidx.emoji2.integration.macrobenchmark.enabled" />
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentResultTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentResultTest.kt
index 4635777..3d6b8e2 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentResultTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentResultTest.kt
@@ -16,7 +16,10 @@
 
 package androidx.fragment.app
 
+import android.app.Activity
 import android.os.Bundle
+import android.os.Parcelable
+import androidx.activity.result.ActivityResult
 import androidx.fragment.app.test.FragmentTestActivity
 import androidx.fragment.test.R
 import androidx.test.core.app.ActivityScenario
@@ -380,6 +383,54 @@
                 .isEqualTo("resultGood")
         }
     }
+
+    @Test
+    fun testReplaceResultWithParcelableOnRecreation() {
+        with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+            var fm = withActivity {
+                setContentView(R.layout.simple_container)
+                supportFragmentManager
+            }
+            var fragment1 = ParcelableResultFragment()
+
+            fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "fragment1")
+                .commit()
+            executePendingTransactions()
+
+            val fragment2 = StrictFragment()
+
+            fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit()
+            executePendingTransactions()
+
+            val resultBundle = Bundle()
+            val expectedResult = ActivityResult(Activity.RESULT_OK, null)
+            resultBundle.putParcelable("bundleKey", expectedResult)
+
+            fm.setFragmentResult("requestKey", resultBundle)
+
+            assertWithMessage("The result is not set")
+                .that(fragment1.actualResult)
+                .isNull()
+
+            recreate()
+
+            fm = withActivity { supportFragmentManager }
+
+            withActivity {
+                fm.popBackStackImmediate()
+            }
+
+            fragment1 = fm.findFragmentByTag("fragment1") as ParcelableResultFragment
+
+            assertWithMessage("The result is incorrect")
+                .that(fragment1.actualResult)
+                .isEqualTo(expectedResult)
+        }
+    }
 }
 
 class ResultFragment : StrictFragment() {
@@ -434,4 +485,18 @@
         }
         parentFragmentManager.setFragmentResult("requestKey", resultBundle)
     }
-}
\ No newline at end of file
+}
+
+class ParcelableResultFragment : StrictFragment() {
+    var actualResult: Parcelable? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        parentFragmentManager.setFragmentResultListener(
+            "requestKey", this,
+            FragmentResultListener
+            { _, bundle -> actualResult = bundle.getParcelable<ActivityResult>("bundleKey") }
+        )
+    }
+}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentViewLifecycleOwnerTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentViewLifecycleOwnerTest.kt
new file mode 100644
index 0000000..67ae872
--- /dev/null
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentViewLifecycleOwnerTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.fragment.app
+
+import androidx.fragment.app.test.FragmentTestActivity
+import androidx.fragment.test.R
+import androidx.lifecycle.HasDefaultViewModelProviderFactory
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.test.core.app.ActivityScenario
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class FragmentViewLifecycleOwnerTest {
+
+    /**
+     * Test representing a Non-Hilt case, in which the default factory is not overwritten at the
+     * Fragment level.
+     */
+    @Test
+    fun defaultFactoryNotOverwritten() {
+        with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+            val fm = withActivity {
+                setContentView(R.layout.simple_container)
+                supportFragmentManager
+            }
+            val fragment = StrictViewFragment()
+
+            fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .commit()
+            executePendingTransactions()
+
+            val defaultFactory1 = (
+                fragment.viewLifecycleOwner as HasDefaultViewModelProviderFactory
+                ).defaultViewModelProviderFactory
+            val defaultFactory2 = (
+                fragment.viewLifecycleOwner as HasDefaultViewModelProviderFactory
+                ).defaultViewModelProviderFactory
+
+            // Assure that multiple call return the same default factory
+            assertThat(defaultFactory1).isSameInstanceAs(defaultFactory2)
+            assertThat(defaultFactory1).isNotSameInstanceAs(
+                fragment.defaultViewModelProviderFactory
+            )
+        }
+    }
+
+    /**
+     * Test representing a Hilt case, in which the default factory is overwritten at the
+     * Fragment level.
+     */
+    @Test
+    fun defaultFactoryOverwritten() {
+        with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+            val fm = withActivity {
+                setContentView(R.layout.simple_container)
+                supportFragmentManager
+            }
+            val fragment = FragmentWithFactoryOverride()
+
+            fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .commit()
+            executePendingTransactions()
+
+            val defaultFactory = (
+                fragment.viewLifecycleOwner as HasDefaultViewModelProviderFactory
+                ).defaultViewModelProviderFactory
+
+            assertThat(defaultFactory).isInstanceOf(FakeViewModelProviderFactory::class.java)
+        }
+    }
+
+    private class TestViewModel : ViewModel()
+
+    class FakeViewModelProviderFactory : ViewModelProvider.Factory {
+        private var createCalled: Boolean = false
+        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+            require(modelClass == TestViewModel::class.java)
+            createCalled = true
+            @Suppress("UNCHECKED_CAST")
+            return TestViewModel() as T
+        }
+    }
+
+    public class FragmentWithFactoryOverride : StrictViewFragment() {
+        public override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory =
+            FakeViewModelProviderFactory()
+    }
+}
\ No newline at end of file
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
index a66d652..42ad4dc 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveRestoreBackStackTest.kt
@@ -24,7 +24,7 @@
 import androidx.lifecycle.ViewModelProvider
 import androidx.test.core.app.ActivityScenario
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
+import androidx.test.filters.LargeTest
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
@@ -32,7 +32,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4::class)
 class SaveRestoreBackStackTest {
 
@@ -272,6 +272,7 @@
             assertWithMessage("ViewModel should not be cleared after commit()")
                 .that(originalViewModel.cleared)
                 .isFalse()
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
 
             fm.saveBackStack("replacement")
             executePendingTransactions()
@@ -279,6 +280,7 @@
             assertWithMessage("Saved Fragments should have their state saved")
                 .that(fragmentReplacement.calledOnSaveInstanceState)
                 .isTrue()
+            assertThat(fm.backStackEntryCount).isEqualTo(0)
 
             // Saved Fragments should be destroyed
             assertWithMessage("Saved Fragments should be destroyed")
@@ -303,6 +305,7 @@
             assertThat(stateSavedReplacement.savedState).isEqualTo("saved")
             assertThat(stateSavedReplacement.unsavedState).isNull()
             assertThat(stateSavedReplacement.viewModel).isSameInstanceAs(originalViewModel)
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
         }
     }
 
@@ -331,6 +334,7 @@
             assertWithMessage("ViewModel should not be cleared after commit()")
                 .that(originalViewModel.cleared)
                 .isFalse()
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
 
             fm.saveBackStack("replacement")
             executePendingTransactions()
@@ -338,6 +342,7 @@
             assertWithMessage("Saved Fragments should have their state saved")
                 .that(fragmentReplacement.calledOnSaveInstanceState)
                 .isTrue()
+            assertThat(fm.backStackEntryCount).isEqualTo(0)
 
             // Saved Fragments should be destroyed
             assertWithMessage("Saved Fragments should be destroyed")
@@ -369,6 +374,63 @@
             assertThat(stateSavedReplacement.savedState).isEqualTo("saved")
             assertThat(stateSavedReplacement.unsavedState).isNull()
             assertThat(stateSavedReplacement.viewModel).isSameInstanceAs(originalViewModel)
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun restoreBackStackWithoutExecutePendingTransactions() {
+        with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+            val fm = withActivity {
+                supportFragmentManager
+            }
+            val fragmentBase = StrictFragment()
+            val fragmentReplacement = StateSaveFragment("saved", "unsaved")
+
+            fm.beginTransaction()
+                .add(R.id.content, fragmentBase)
+                .commit()
+            executePendingTransactions()
+
+            fm.beginTransaction()
+                .setReorderingAllowed(true)
+                .replace(R.id.content, fragmentReplacement)
+                .addToBackStack("replacement")
+                .commit()
+            executePendingTransactions()
+
+            val originalViewModel = fragmentReplacement.viewModel
+            assertWithMessage("ViewModel should not be cleared after commit()")
+                .that(originalViewModel.cleared)
+                .isFalse()
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
+
+            withActivity {
+                fm.saveBackStack("replacement")
+                // Immediately restore the back stack without calling executePendingTransactions
+                fm.restoreBackStack("replacement")
+            }
+            executePendingTransactions()
+
+            assertWithMessage("Saved Fragments should not go through onSaveInstanceState")
+                .that(fragmentReplacement.calledOnSaveInstanceState)
+                .isFalse()
+            assertWithMessage("Saved Fragments should not have been destroyed")
+                .that(fragmentReplacement.calledOnDestroy)
+                .isFalse()
+            assertWithMessage("ViewModel should not be cleared after saveBackStack()")
+                .that(originalViewModel.cleared)
+                .isFalse()
+
+            assertWithMessage("Fragment should still be returned by FragmentManager")
+                .that(fm.findFragmentById(R.id.content))
+                .isSameInstanceAs(fragmentReplacement)
+
+            // Assert that restored fragment has its saved state restored
+            assertThat(fragmentReplacement.savedState).isEqualTo("saved")
+            assertThat(fragmentReplacement.unsavedState).isEqualTo("unsaved")
+            assertThat(fragmentReplacement.viewModel).isSameInstanceAs(originalViewModel)
+            assertThat(fm.backStackEntryCount).isEqualTo(1)
         }
     }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index e691044..70ec336 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -142,6 +142,17 @@
         mManager = manager;
     }
 
+    BackStackRecord(@NonNull BackStackRecord bse) {
+        super(bse.mManager.getFragmentFactory(), bse.mManager.getHost() != null
+                ? bse.mManager.getHost().getContext().getClassLoader()
+                : null, bse);
+        mManager = bse.mManager;
+        mCommitted = bse.mCommitted;
+        mIndex = bse.mIndex;
+        mBeingSaved = bse.mBeingSaved;
+    }
+
+
     @Override
     public int getId() {
         return mIndex;
@@ -281,15 +292,6 @@
         }
     }
 
-    void runOnExecuteRunnables() {
-        if (mExecuteRunnables != null) {
-            for (int i = 0; i < mExecuteRunnables.size(); i++) {
-                mExecuteRunnables.get(i).run();
-            }
-            mExecuteRunnables = null;
-        }
-    }
-
     public void runOnCommitRunnables() {
         if (mCommitRunnables != null) {
             for (int i = 0; i < mCommitRunnables.size(); i++) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
index c102873..06e1df3 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
@@ -48,7 +48,14 @@
         // These will populate the transactions we instantiate.
         HashMap<String, Fragment> fragments = new HashMap<>(mFragments.size());
         for (String fWho : mFragments) {
-            // Retrieve any saved state, clearing it out for future calls
+            Fragment existingFragment = fm.getFragmentStore().findFragmentByWho(fWho);
+            if (existingFragment != null) {
+                // If the Fragment still exists, this means the saveBackStack()
+                // hasn't executed yet, so we can use the existing Fragment directly
+                fragments.put(existingFragment.mWho, existingFragment);
+                continue;
+            }
+            // Otherwise, retrieve any saved state, clearing it out for future calls
             FragmentState fragmentState = fm.getFragmentStore().setSavedState(fWho, null);
             if (fragmentState != null) {
                 Fragment fragment = fragmentState.instantiate(fm.getFragmentFactory(),
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index c33fffe..0a07f7c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -289,7 +289,7 @@
     @Nullable FragmentViewLifecycleOwner mViewLifecycleOwner;
     MutableLiveData<LifecycleOwner> mViewLifecycleOwnerLiveData = new MutableLiveData<>();
 
-    private ViewModelProvider.Factory mDefaultFactory;
+    ViewModelProvider.Factory mDefaultFactory;
 
     SavedStateRegistryController mSavedStateRegistryController;
 
@@ -2939,7 +2939,7 @@
             @Nullable Bundle savedInstanceState) {
         mChildFragmentManager.noteStateNotSaved();
         mPerformedCreateView = true;
-        mViewLifecycleOwner = new FragmentViewLifecycleOwner(getViewModelStore());
+        mViewLifecycleOwner = new FragmentViewLifecycleOwner(this, getViewModelStore());
         mView = onCreateView(inflater, container, savedInstanceState);
         if (mView != null) {
             // Initialize the view lifecycle
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 85a3a37..1c7ab0e 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1758,11 +1758,6 @@
         }
         executeOps(records, isRecordPop, startIndex, endIndex);
 
-        for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
-            final BackStackRecord record = records.get(recordNum);
-            record.runOnExecuteRunnables();
-        }
-
         // The last operation determines the overall direction, this ensures that operations
         // such as push, push, pop, push are correctly considered a push
         boolean isPop = isRecordPop.get(endIndex - 1);
@@ -1997,11 +1992,11 @@
         }
 
         List<BackStackRecord> backStackRecords = backStackState.instantiate(this);
+        boolean added = false;
         for (BackStackRecord record : backStackRecords) {
-            records.add(record);
-            isRecordPop.add(false);
+            added = record.generateOps(records, isRecordPop) || added;
         }
-        return true;
+        return added;
     }
 
     boolean saveBackStackState(@NonNull ArrayList<BackStackRecord> records,
@@ -2095,20 +2090,17 @@
         final BackStackState backStackState = new BackStackState(
                 fragments, backStackRecordStates);
         for (int i = mBackStack.size() - 1; i >= index; i--) {
-            final BackStackRecord record = mBackStack.remove(i);
+            BackStackRecord record = mBackStack.remove(i);
+
+            // Create a copy of the record to save
+            BackStackRecord copy = new BackStackRecord(record);
+            copy.collapseOps();
+            BackStackRecordState state = new BackStackRecordState(copy);
+            backStackRecordStates.set(i - index, state);
+
+            // And now mark the record as being saved to ensure that each
+            // fragment saves its state properly
             record.mBeingSaved = true;
-            // Get a callback when the BackStackRecord is actually finished
-            final int currentIndex = i;
-            record.addOnExecuteRunnable(new Runnable() {
-                @Override
-                public void run() {
-                    // First collapse the record to remove expanded ops and get it ready to save
-                    record.collapseOps();
-                    // Then save the state
-                    BackStackRecordState state = new BackStackRecordState(record);
-                    backStackRecordStates.set(currentIndex - index, state);
-                }
-            });
             records.add(record);
             isRecordPop.add(true);
         }
@@ -2381,7 +2373,9 @@
         ArrayList<String> savedResultKeys = fms.mResultKeys;
         if (savedResultKeys != null) {
             for (int i = 0; i < savedResultKeys.size(); i++) {
-                mResults.put(savedResultKeys.get(i), fms.mResults.get(i));
+                Bundle savedResult = fms.mResults.get(i);
+                savedResult.setClassLoader(mHost.getContext().getClassLoader());
+                mResults.put(savedResultKeys.get(i), savedResult);
             }
         }
         mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
index 1ed008c..65a30e5 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
@@ -98,6 +98,18 @@
             this.mOldMaxState = fragment.mMaxState;
             this.mCurrentMaxState = state;
         }
+
+        Op(Op op) {
+            this.mCmd = op.mCmd;
+            this.mFragment = op.mFragment;
+            this.mFromExpandedOp = op.mFromExpandedOp;
+            this.mEnterAnim = op.mEnterAnim;
+            this.mExitAnim = op.mExitAnim;
+            this.mPopEnterAnim = op.mPopEnterAnim;
+            this.mPopExitAnim = op.mPopExitAnim;
+            this.mOldMaxState = op.mOldMaxState;
+            this.mCurrentMaxState = op.mCurrentMaxState;
+        }
     }
 
     private final FragmentFactory mFragmentFactory;
@@ -122,7 +134,6 @@
     ArrayList<String> mSharedElementTargetNames;
     boolean mReorderingAllowed = false;
 
-    ArrayList<Runnable> mExecuteRunnables;
     ArrayList<Runnable> mCommitRunnables;
 
     /**
@@ -141,6 +152,35 @@
         mClassLoader = classLoader;
     }
 
+    FragmentTransaction(@NonNull FragmentFactory fragmentFactory,
+            @Nullable ClassLoader classLoader, @NonNull FragmentTransaction ft) {
+        this(fragmentFactory, classLoader);
+        for (Op op : ft.mOps) {
+            mOps.add(new Op(op));
+        }
+        mEnterAnim = ft.mEnterAnim;
+        mExitAnim = ft.mExitAnim;
+        mPopEnterAnim = ft.mPopEnterAnim;
+        mPopExitAnim = ft.mPopExitAnim;
+        mTransition = ft.mTransition;
+        mAddToBackStack = ft.mAddToBackStack;
+        mAllowAddToBackStack = ft.mAllowAddToBackStack;
+        mName = ft.mName;
+        mBreadCrumbShortTitleRes = ft.mBreadCrumbShortTitleRes;
+        mBreadCrumbShortTitleText = ft.mBreadCrumbShortTitleText;
+        mBreadCrumbTitleRes = ft.mBreadCrumbTitleRes;
+        mBreadCrumbTitleText = ft.mBreadCrumbTitleText;
+        if (ft.mSharedElementSourceNames != null) {
+            mSharedElementSourceNames = new ArrayList<>();
+            mSharedElementSourceNames.addAll(ft.mSharedElementSourceNames);
+        }
+        if (ft.mSharedElementTargetNames != null) {
+            mSharedElementTargetNames = new ArrayList<>();
+            mSharedElementTargetNames.addAll(ft.mSharedElementTargetNames);
+        }
+        mReorderingAllowed = ft.mReorderingAllowed;
+    }
+
     void addOp(Op op) {
         mOps.add(op);
         op.mEnterAnim = mEnterAnim;
@@ -826,18 +866,6 @@
     }
 
     /**
-     * Add a runnable that is run immediately after the transaction is executed.
-     * This differs from the commit runnables in that it happens before any
-     * fragments move to their expected state.
-     */
-    void addOnExecuteRunnable(@NonNull Runnable runnable) {
-        if (mExecuteRunnables == null) {
-            mExecuteRunnables = new ArrayList<>();
-        }
-        mExecuteRunnables.add(runnable);
-    }
-
-    /**
      * Add a Runnable to this transaction that will be run after this transaction has
      * been committed. If fragment transactions are {@link #setReorderingAllowed(boolean) optimized}
      * this may be after other subsequent fragment operations have also taken place, or operations
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentViewLifecycleOwner.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentViewLifecycleOwner.java
index 65f16a4..ef96a00 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentViewLifecycleOwner.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentViewLifecycleOwner.java
@@ -16,25 +16,36 @@
 
 package androidx.fragment.app;
 
+import android.app.Application;
+import android.content.Context;
+import android.content.ContextWrapper;
 import android.os.Bundle;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.lifecycle.HasDefaultViewModelProviderFactory;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleRegistry;
+import androidx.lifecycle.SavedStateViewModelFactory;
+import androidx.lifecycle.ViewModelProvider;
 import androidx.lifecycle.ViewModelStore;
 import androidx.lifecycle.ViewModelStoreOwner;
 import androidx.savedstate.SavedStateRegistry;
 import androidx.savedstate.SavedStateRegistryController;
 import androidx.savedstate.SavedStateRegistryOwner;
 
-class FragmentViewLifecycleOwner implements SavedStateRegistryOwner, ViewModelStoreOwner {
+class FragmentViewLifecycleOwner implements HasDefaultViewModelProviderFactory,
+        SavedStateRegistryOwner, ViewModelStoreOwner {
+    private final Fragment mFragment;
     private final ViewModelStore mViewModelStore;
 
+    private ViewModelProvider.Factory mDefaultFactory;
+
     private LifecycleRegistry mLifecycleRegistry = null;
     private SavedStateRegistryController mSavedStateRegistryController = null;
 
-    FragmentViewLifecycleOwner(@NonNull ViewModelStore viewModelStore) {
+    FragmentViewLifecycleOwner(@NonNull Fragment fragment, @NonNull ViewModelStore viewModelStore) {
+        mFragment = fragment;
         mViewModelStore = viewModelStore;
     }
 
@@ -77,6 +88,44 @@
         mLifecycleRegistry.handleLifecycleEvent(event);
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The {@link Fragment#getArguments() Fragment's arguments} when this is first called will
+     * be used as the defaults to any {@link androidx.lifecycle.SavedStateHandle} passed to a
+     * view model created using this factory.</p>
+     */
+    @NonNull
+    @Override
+    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+        ViewModelProvider.Factory currentFactory =
+                mFragment.getDefaultViewModelProviderFactory();
+
+        if (!currentFactory.equals(mFragment.mDefaultFactory)) {
+            mDefaultFactory = currentFactory;
+            return currentFactory;
+        }
+
+        if (mDefaultFactory == null) {
+            Application application = null;
+            Context appContext = mFragment.requireContext().getApplicationContext();
+            while (appContext instanceof ContextWrapper) {
+                if (appContext instanceof Application) {
+                    application = (Application) appContext;
+                    break;
+                }
+                appContext = ((ContextWrapper) appContext).getBaseContext();
+            }
+
+            mDefaultFactory = new SavedStateViewModelFactory(
+                    application,
+                    this,
+                    mFragment.getArguments());
+        }
+
+        return mDefaultFactory;
+    }
+
     @NonNull
     @Override
     public SavedStateRegistry getSavedStateRegistry() {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4d9b6bc..42c5121 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -59,7 +59,7 @@
 dokkaGradlePlugin = { module = "org.jetbrains.dokka:dokka-android-gradle-plugin", version = "0.9.17-g014" }
 espressoContrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "espresso" }
 espressoCore = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
-espressoIdlingNet = { module = "androidx.test.espresso:espresso-idling-net", version.ref = "espresso" }
+espressoIdlingNet = { module = "androidx.test.espresso.idling:idling-net", version.ref = "espresso" }
 espressoIdlingResource = { module = "androidx.test.espresso:espresso-idling-resource", version.ref = "espresso" }
 espressoIntents = { module = "androidx.test.espresso:espresso-intents", version.ref = "espresso" }
 espressoWeb = { module = "androidx.test.espresso:espresso-web", version.ref = "espresso" }
diff --git a/health/health-services-client/api/api_lint.ignore b/health/health-services-client/api/api_lint.ignore
new file mode 100644
index 0000000..1a6bb40
--- /dev/null
+++ b/health/health-services-client/api/api_lint.ignore
@@ -0,0 +1,9 @@
+// Baseline format: 1.0
+ExecutorRegistration: androidx.health.services.client.ExerciseClient#clearUpdateListener(androidx.health.services.client.ExerciseUpdateListener):
+    Registration methods should have overload that accepts delivery Executor: `clearUpdateListener`
+ExecutorRegistration: androidx.health.services.client.PassiveMonitoringClient#registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType>, android.app.PendingIntent, androidx.health.services.client.PassiveMonitoringCallback):
+    Registration methods should have overload that accepts delivery Executor: `registerDataCallback`
+
+
+MissingGetterMatchingBuilder: androidx.health.services.client.data.ExerciseConfig.Builder#setAutoPauseAndResume(boolean):
+    androidx.health.services.client.data.ExerciseConfig does not declare a `isAutoPauseAndResume()` method matching method androidx.health.services.client.data.ExerciseConfig.Builder.setAutoPauseAndResume(boolean)
diff --git a/health/health-services-client/api/current.txt b/health/health-services-client/api/current.txt
index e6f50d0..6abe37c 100644
--- a/health/health-services-client/api/current.txt
+++ b/health/health-services-client/api/current.txt
@@ -1 +1,869 @@
 // Signature format: 4.0
+package androidx.health.services.client {
+
+  public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExercise(androidx.health.services.client.data.ExerciseGoal exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfo();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLap();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExercise(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExercise(androidx.health.services.client.data.ExerciseConfig configuration);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> capabilities;
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> currentExerciseInfo;
+  }
+
+  public interface ExerciseUpdateListener {
+    method public void onExerciseUpdate(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummary(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Availability availability);
+    method public void onData(java.util.List<androidx.health.services.client.data.DataPoint> data);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> capabilities;
+  }
+
+  public interface PassiveMonitoringCallback {
+    method public void onPassiveActivityState(androidx.health.services.client.data.PassiveActivityState state);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent, androidx.health.services.client.PassiveMonitoringCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerEventCallback(androidx.health.services.client.data.event.Event event, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterDataCallback();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterEventCallback(androidx.health.services.client.data.event.Event event);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> capabilities;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AchievedExerciseGoal implements android.os.Parcelable {
+    ctor public AchievedExerciseGoal(androidx.health.services.client.data.ExerciseGoal goal);
+    method public androidx.health.services.client.data.ExerciseGoal component1();
+    method public androidx.health.services.client.data.AchievedExerciseGoal copy(androidx.health.services.client.data.ExerciseGoal goal);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseGoal getGoal();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseGoal goal;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AchievedExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.AchievedExerciseGoal.Companion Companion;
+  }
+
+  public static final class AchievedExerciseGoal.Companion {
+  }
+
+  public final class AutoExerciseConfig implements android.os.Parcelable {
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent, optional android.os.Bundle exerciseParams);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> component1();
+    method public android.app.PendingIntent? component2();
+    method public android.os.Bundle component3();
+    method public androidx.health.services.client.data.AutoExerciseConfig copy(java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, android.app.PendingIntent? launchIntent, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public android.os.Bundle getExerciseParams();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getExercisesToDetect();
+    method public android.app.PendingIntent? getLaunchIntent();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final android.os.Bundle exerciseParams;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> exercisesToDetect;
+    property public final android.app.PendingIntent? launchIntent;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AutoExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.AutoExerciseConfig.Companion Companion;
+  }
+
+  public static final class AutoExerciseConfig.Companion {
+  }
+
+  public enum Availability {
+    method public static final androidx.health.services.client.data.Availability? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.Availability ACQUIRING;
+    enum_constant public static final androidx.health.services.client.data.Availability AVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNAVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNKNOWN;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+    method public androidx.health.services.client.data.Availability? fromId(int id);
+  }
+
+  public final class Capabilities implements android.os.Parcelable {
+    ctor public Capabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> component1();
+    method public androidx.health.services.client.data.Capabilities copy(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseCapabilities getExerciseCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> getExerciseTypeToExerciseCapabilities();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Capabilities> CREATOR;
+    field public static final androidx.health.services.client.data.Capabilities.Companion Companion;
+  }
+
+  public static final class Capabilities.Companion {
+  }
+
+  public enum ComparisonType {
+    method public static final androidx.health.services.client.data.ComparisonType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+  }
+
+  public static final class ComparisonType.Companion {
+    method public androidx.health.services.client.data.ComparisonType? fromId(int id);
+  }
+
+  public final class DataPoint implements android.os.Parcelable {
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public java.time.Duration component3();
+    method public java.time.Duration component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.DataPoint copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public androidx.health.services.client.data.Value getValue();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final androidx.health.services.client.data.Value value;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataPoint> CREATOR;
+    field public static final androidx.health.services.client.data.DataPoint.Companion Companion;
+  }
+
+  public static final class DataPoint.Companion {
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+  }
+
+  @Keep public final class DataPoints {
+    method public static androidx.health.services.client.data.DataPoint aggregateCalories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateDistance(double distance, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSteps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSwimmingStrokes(long swimmingStrokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint altitude(double meters, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averagePace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averageSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint calories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint distance(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint elevation(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint floors(double floors, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method @Keep public static java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints(android.content.Intent intent);
+    method public static boolean getPermissionsGranted(android.content.Intent intent);
+    method public static androidx.health.services.client.data.DataPoint heartRate(double bpm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, double altitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint maxSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint pace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static void putDataPoints(android.content.Intent intent, java.util.Collection<androidx.health.services.client.data.DataPoint> dataPoints);
+    method public static void putPermissionsGranted(android.content.Intent intent, boolean granted);
+    method public static androidx.health.services.client.data.DataPoint speed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint spo2(double percent, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint steps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint stepsPerMinute(long stepsPerMinute, java.time.Duration startDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint swimmingStrokes(long strokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    field public static final androidx.health.services.client.data.DataPoints INSTANCE;
+    field public static final int LOCATION_DATA_POINT_ALTITUDE_INDEX = 2; // 0x2
+    field public static final int LOCATION_DATA_POINT_LATITUDE_INDEX = 0; // 0x0
+    field public static final int LOCATION_DATA_POINT_LONGITUDE_INDEX = 1; // 0x1
+  }
+
+  public final class DataType implements android.os.Parcelable {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public String component1();
+    method public androidx.health.services.client.data.DataType.TimeType component2();
+    method public int component3();
+    method public androidx.health.services.client.data.DataType copy(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public int describeContents();
+    method public int getFormat();
+    method public String getName();
+    method public androidx.health.services.client.data.DataType.TimeType getTimeType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final int format;
+    property public final String name;
+    property public final androidx.health.services.client.data.DataType.TimeType timeType;
+    field public static final androidx.health.services.client.data.DataType ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType ACTIVE_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_CALORIES_EXPENDED;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLOORS;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_RUNNING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_SWIMMING_STROKE_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_WALKING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_PACE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_SPEED;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataType> CREATOR;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType DISTANCE;
+    field public static final androidx.health.services.client.data.DataType ELEVATION;
+    field public static final androidx.health.services.client.data.DataType FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType FLOORS;
+    field public static final androidx.health.services.client.data.DataType HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType LOCATION;
+    field public static final androidx.health.services.client.data.DataType MAX_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType MAX_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType MAX_PACE;
+    field public static final androidx.health.services.client.data.DataType MAX_SPEED;
+    field public static final androidx.health.services.client.data.DataType MIN_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType PACE;
+    field public static final androidx.health.services.client.data.DataType REP_COUNT;
+    field public static final androidx.health.services.client.data.DataType RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.DataType SPEED;
+    field public static final androidx.health.services.client.data.DataType SPO2;
+    field public static final androidx.health.services.client.data.DataType STEPS;
+    field public static final androidx.health.services.client.data.DataType STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.DataType TOTAL_CALORIES;
+    field public static final androidx.health.services.client.data.DataType VO2;
+    field public static final androidx.health.services.client.data.DataType VO2_MAX;
+    field public static final androidx.health.services.client.data.DataType WALKING_STEPS;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public enum DataType.TimeType {
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+  }
+
+  public final class DataTypeCondition implements android.os.Parcelable {
+    ctor public DataTypeCondition(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public androidx.health.services.client.data.ComparisonType component3();
+    method public androidx.health.services.client.data.DataTypeCondition copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public androidx.health.services.client.data.Value getThreshold();
+    method public boolean isSatisfied(androidx.health.services.client.data.DataPoint dataPoint);
+    method public boolean isThresholdSatisfied(androidx.health.services.client.data.Value value);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final androidx.health.services.client.data.Value threshold;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataTypeCondition> CREATOR;
+    field public static final androidx.health.services.client.data.DataTypeCondition.Companion Companion;
+  }
+
+  public static final class DataTypeCondition.Companion {
+  }
+
+  public final class DataTypes {
+    method public static androidx.health.services.client.data.DataType? getAggregateTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static java.util.Set<androidx.health.services.client.data.DataType> getAggregatedDataTypesFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getAverageTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getMaxTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAggregateType(androidx.health.services.client.data.DataType aggregateType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAverageType(androidx.health.services.client.data.DataType averageType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromMaxType(androidx.health.services.client.data.DataType maxType);
+    method public static boolean isAggregateDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isRawType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalAverageDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalMaxDataType(androidx.health.services.client.data.DataType dataType);
+    field public static final androidx.health.services.client.data.DataTypes INSTANCE;
+  }
+
+  public final class ExerciseCapabilities implements android.os.Parcelable {
+    ctor public ExerciseCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component2();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component3();
+    method public boolean component4();
+    method public boolean component5();
+    method public androidx.health.services.client.data.ExerciseCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    method public boolean getSupportsLaps();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+    property public final boolean supportsLaps;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseCapabilities.Companion Companion;
+  }
+
+  public static final class ExerciseCapabilities.Companion {
+  }
+
+  public final class ExerciseConfig implements android.os.Parcelable {
+    ctor protected ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder();
+    method public androidx.health.services.client.data.ExerciseType component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public boolean component3();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.ExerciseConfig copy(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public boolean getAutoPauseAndResume();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final boolean autoPauseAndResume;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder();
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setAutoPauseAndResume(boolean autoPauseAndResume);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<androidx.health.services.client.data.DataType> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseType(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder();
+  }
+
+  public final class ExerciseGoal implements android.os.Parcelable {
+    ctor protected ExerciseGoal(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, optional androidx.health.services.client.data.Value? period);
+    method public androidx.health.services.client.data.ExerciseGoalType component1();
+    method public androidx.health.services.client.data.DataTypeCondition component2();
+    method public androidx.health.services.client.data.Value? component3();
+    method public androidx.health.services.client.data.ExerciseGoal copy(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.Value? period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public static androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public androidx.health.services.client.data.Value? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final androidx.health.services.client.data.Value? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+  }
+
+  public enum ExerciseGoalType {
+    method public static final androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo implements android.os.Parcelable {
+    ctor public ExerciseInfo(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseTrackedStatus component1();
+    method public androidx.health.services.client.data.ExerciseType component2();
+    method public androidx.health.services.client.data.ExerciseInfo copy(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseTrackedStatus getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseInfo> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseInfo.Companion Companion;
+  }
+
+  public static final class ExerciseInfo.Companion {
+  }
+
+  public final class ExerciseLapSummary implements android.os.Parcelable {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int component1();
+    method public java.time.Instant component2();
+    method public java.time.Instant component3();
+    method public java.time.Duration component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.ExerciseLapSummary copy(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getLapMetrics();
+    method public java.time.Instant getStartTime();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics;
+    property public final java.time.Instant startTime;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseLapSummary> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseLapSummary.Companion Companion;
+  }
+
+  public static final class ExerciseLapSummary.Companion {
+  }
+
+  public enum ExerciseState {
+    method public static final androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public final int getId();
+    method public final boolean isEnded();
+    method public final boolean isPaused();
+    method public final boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public enum ExerciseTrackedStatus {
+    method public static final androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus NO_EXERCISE_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OTHER_APP_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OWNED_EXERCISE_IN_PROGRESS;
+    field public static final androidx.health.services.client.data.ExerciseTrackedStatus.Companion Companion;
+  }
+
+  public static final class ExerciseTrackedStatus.Companion {
+    method public androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+  }
+
+  public enum ExerciseType {
+    method public static final androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_SIT_UP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOXING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DANCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_FRONT_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_LATERAL_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_TWO_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FENCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GOLF;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GYNMASTICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PILATES;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PLANK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SAILING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKIING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SURFING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WALKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_INDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_OUTDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType YOGA;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseUpdate implements android.os.Parcelable {
+    ctor public ExerciseUpdate(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public androidx.health.services.client.data.ExerciseState component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> component4();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> component5();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> component6();
+    method public androidx.health.services.client.data.ExerciseConfig? component7();
+    method public androidx.health.services.client.data.AutoExerciseConfig? component8();
+    method public androidx.health.services.client.data.ExerciseType? component9();
+    method public androidx.health.services.client.data.ExerciseUpdate copy(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public androidx.health.services.client.data.AutoExerciseConfig? getAutoExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseType? getAutoExerciseDetected();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType getExerciseSessionType();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> getLatestAchievedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseType? autoExerciseDetected;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseUpdate> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public enum ExerciseUpdate.ExerciseSessionType {
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType AUTO_EXERCISE_DETECTION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType MANUALLY_STARTED_EXERCISE;
+  }
+
+  public final class MeasureCapabilities implements android.os.Parcelable {
+    ctor public MeasureCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public androidx.health.services.client.data.MeasureCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesMeasure();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MeasureCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.MeasureCapabilities.Companion Companion;
+  }
+
+  public static final class MeasureCapabilities.Companion {
+  }
+
+  public final class MilestoneMarkerSummary implements android.os.Parcelable {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public java.time.Instant component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public androidx.health.services.client.data.AchievedExerciseGoal component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.MilestoneMarkerSummary copy(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public int describeContents();
+    method public androidx.health.services.client.data.AchievedExerciseGoal getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getSummaryMetrics();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.AchievedExerciseGoal achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MilestoneMarkerSummary> CREATOR;
+    field public static final androidx.health.services.client.data.MilestoneMarkerSummary.Companion Companion;
+  }
+
+  public static final class MilestoneMarkerSummary.Companion {
+  }
+
+  public final class PassiveActivityState implements android.os.Parcelable {
+    ctor public PassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> component1();
+    method public androidx.health.services.client.data.UserActivityState component2();
+    method public androidx.health.services.client.data.ExerciseType? component3();
+    method public java.time.Instant component4();
+    method public androidx.health.services.client.data.PassiveActivityState copy(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public int describeContents();
+    method public static androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints();
+    method public androidx.health.services.client.data.ExerciseType? getExerciseType();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    method public void putToIntent(android.content.Intent intent);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<androidx.health.services.client.data.DataPoint> dataPoints;
+    property public final androidx.health.services.client.data.ExerciseType? exerciseType;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveActivityState> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveActivityState.Companion Companion;
+  }
+
+  public static final class PassiveActivityState.Companion {
+    method public androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+  }
+
+  public final class PassiveMonitoringCapabilities implements android.os.Parcelable {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public androidx.health.services.client.data.PassiveMonitoringCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesEvents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesPassiveMonitoring();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveMonitoringCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveMonitoringCapabilities.Companion Companion;
+  }
+
+  public static final class PassiveMonitoringCapabilities.Companion {
+  }
+
+  public enum UserActivityState {
+    method public static final androidx.health.services.client.data.UserActivityState? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_INACTIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+  }
+
+  public static final class UserActivityState.Companion {
+    method public androidx.health.services.client.data.UserActivityState? fromId(int id);
+  }
+
+  public final class Value implements android.os.Parcelable {
+    method public boolean asBoolean();
+    method public double asDouble();
+    method public double[] asDoubleArray();
+    method public long asLong();
+    method public int component1();
+    method public java.util.List<java.lang.Double> component2();
+    method public long component3();
+    method public androidx.health.services.client.data.Value copy(int format, java.util.List<java.lang.Double> doubleList, long longValue);
+    method public int describeContents();
+    method public java.util.List<java.lang.Double> getDoubleList();
+    method public int getFormat();
+    method public long getLongValue();
+    method public boolean isBoolean();
+    method public boolean isDouble();
+    method public boolean isDoubleArray();
+    method public boolean isLong();
+    method public static androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public static androidx.health.services.client.data.Value ofDouble(double value);
+    method public static androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public static androidx.health.services.client.data.Value ofLong(long value);
+    method public static androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<java.lang.Double> doubleList;
+    property public final int format;
+    property public final boolean isBoolean;
+    property public final boolean isDouble;
+    property public final boolean isDoubleArray;
+    property public final boolean isLong;
+    property public final long longValue;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Value> CREATOR;
+    field public static final androidx.health.services.client.data.Value.Companion Companion;
+    field public static final int FORMAT_BOOLEAN = 4; // 0x4
+    field public static final int FORMAT_DOUBLE = 1; // 0x1
+    field public static final int FORMAT_DOUBLE_ARRAY = 3; // 0x3
+    field public static final int FORMAT_LONG = 2; // 0x2
+  }
+
+  public static final class Value.Companion {
+    method public androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public androidx.health.services.client.data.Value ofDouble(double value);
+    method public androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public androidx.health.services.client.data.Value ofLong(long value);
+    method public androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+  }
+
+}
+
+package androidx.health.services.client.data.event {
+
+  public final class Event implements android.os.Parcelable {
+    ctor public Event(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public androidx.health.services.client.data.DataTypeCondition component1();
+    method public androidx.health.services.client.data.event.Event.TriggerType component2();
+    method public androidx.health.services.client.data.event.Event copy(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.event.Event.TriggerType getTriggerType();
+    method public boolean isTriggered(androidx.health.services.client.data.DataPoint dataPoint);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.event.Event.TriggerType triggerType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.event.Event> CREATOR;
+    field public static final androidx.health.services.client.data.event.Event.Companion Companion;
+  }
+
+  public static final class Event.Companion {
+  }
+
+  public enum Event.TriggerType {
+    method public static final androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType ONCE;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType REPEATED;
+    field public static final androidx.health.services.client.data.event.Event.TriggerType.Companion Companion;
+  }
+
+  public static final class Event.TriggerType.Companion {
+    method public androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+  }
+
+}
+
diff --git a/health/health-services-client/api/public_plus_experimental_current.txt b/health/health-services-client/api/public_plus_experimental_current.txt
index e6f50d0..6abe37c 100644
--- a/health/health-services-client/api/public_plus_experimental_current.txt
+++ b/health/health-services-client/api/public_plus_experimental_current.txt
@@ -1 +1,869 @@
 // Signature format: 4.0
+package androidx.health.services.client {
+
+  public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExercise(androidx.health.services.client.data.ExerciseGoal exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfo();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLap();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExercise(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExercise(androidx.health.services.client.data.ExerciseConfig configuration);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> capabilities;
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> currentExerciseInfo;
+  }
+
+  public interface ExerciseUpdateListener {
+    method public void onExerciseUpdate(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummary(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Availability availability);
+    method public void onData(java.util.List<androidx.health.services.client.data.DataPoint> data);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> capabilities;
+  }
+
+  public interface PassiveMonitoringCallback {
+    method public void onPassiveActivityState(androidx.health.services.client.data.PassiveActivityState state);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent, androidx.health.services.client.PassiveMonitoringCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerEventCallback(androidx.health.services.client.data.event.Event event, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterDataCallback();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterEventCallback(androidx.health.services.client.data.event.Event event);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> capabilities;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AchievedExerciseGoal implements android.os.Parcelable {
+    ctor public AchievedExerciseGoal(androidx.health.services.client.data.ExerciseGoal goal);
+    method public androidx.health.services.client.data.ExerciseGoal component1();
+    method public androidx.health.services.client.data.AchievedExerciseGoal copy(androidx.health.services.client.data.ExerciseGoal goal);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseGoal getGoal();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseGoal goal;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AchievedExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.AchievedExerciseGoal.Companion Companion;
+  }
+
+  public static final class AchievedExerciseGoal.Companion {
+  }
+
+  public final class AutoExerciseConfig implements android.os.Parcelable {
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent, optional android.os.Bundle exerciseParams);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> component1();
+    method public android.app.PendingIntent? component2();
+    method public android.os.Bundle component3();
+    method public androidx.health.services.client.data.AutoExerciseConfig copy(java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, android.app.PendingIntent? launchIntent, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public android.os.Bundle getExerciseParams();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getExercisesToDetect();
+    method public android.app.PendingIntent? getLaunchIntent();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final android.os.Bundle exerciseParams;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> exercisesToDetect;
+    property public final android.app.PendingIntent? launchIntent;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AutoExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.AutoExerciseConfig.Companion Companion;
+  }
+
+  public static final class AutoExerciseConfig.Companion {
+  }
+
+  public enum Availability {
+    method public static final androidx.health.services.client.data.Availability? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.Availability ACQUIRING;
+    enum_constant public static final androidx.health.services.client.data.Availability AVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNAVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNKNOWN;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+    method public androidx.health.services.client.data.Availability? fromId(int id);
+  }
+
+  public final class Capabilities implements android.os.Parcelable {
+    ctor public Capabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> component1();
+    method public androidx.health.services.client.data.Capabilities copy(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseCapabilities getExerciseCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> getExerciseTypeToExerciseCapabilities();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Capabilities> CREATOR;
+    field public static final androidx.health.services.client.data.Capabilities.Companion Companion;
+  }
+
+  public static final class Capabilities.Companion {
+  }
+
+  public enum ComparisonType {
+    method public static final androidx.health.services.client.data.ComparisonType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+  }
+
+  public static final class ComparisonType.Companion {
+    method public androidx.health.services.client.data.ComparisonType? fromId(int id);
+  }
+
+  public final class DataPoint implements android.os.Parcelable {
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public java.time.Duration component3();
+    method public java.time.Duration component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.DataPoint copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public androidx.health.services.client.data.Value getValue();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final androidx.health.services.client.data.Value value;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataPoint> CREATOR;
+    field public static final androidx.health.services.client.data.DataPoint.Companion Companion;
+  }
+
+  public static final class DataPoint.Companion {
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+  }
+
+  @Keep public final class DataPoints {
+    method public static androidx.health.services.client.data.DataPoint aggregateCalories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateDistance(double distance, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSteps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSwimmingStrokes(long swimmingStrokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint altitude(double meters, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averagePace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averageSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint calories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint distance(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint elevation(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint floors(double floors, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method @Keep public static java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints(android.content.Intent intent);
+    method public static boolean getPermissionsGranted(android.content.Intent intent);
+    method public static androidx.health.services.client.data.DataPoint heartRate(double bpm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, double altitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint maxSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint pace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static void putDataPoints(android.content.Intent intent, java.util.Collection<androidx.health.services.client.data.DataPoint> dataPoints);
+    method public static void putPermissionsGranted(android.content.Intent intent, boolean granted);
+    method public static androidx.health.services.client.data.DataPoint speed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint spo2(double percent, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint steps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint stepsPerMinute(long stepsPerMinute, java.time.Duration startDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint swimmingStrokes(long strokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    field public static final androidx.health.services.client.data.DataPoints INSTANCE;
+    field public static final int LOCATION_DATA_POINT_ALTITUDE_INDEX = 2; // 0x2
+    field public static final int LOCATION_DATA_POINT_LATITUDE_INDEX = 0; // 0x0
+    field public static final int LOCATION_DATA_POINT_LONGITUDE_INDEX = 1; // 0x1
+  }
+
+  public final class DataType implements android.os.Parcelable {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public String component1();
+    method public androidx.health.services.client.data.DataType.TimeType component2();
+    method public int component3();
+    method public androidx.health.services.client.data.DataType copy(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public int describeContents();
+    method public int getFormat();
+    method public String getName();
+    method public androidx.health.services.client.data.DataType.TimeType getTimeType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final int format;
+    property public final String name;
+    property public final androidx.health.services.client.data.DataType.TimeType timeType;
+    field public static final androidx.health.services.client.data.DataType ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType ACTIVE_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_CALORIES_EXPENDED;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLOORS;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_RUNNING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_SWIMMING_STROKE_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_WALKING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_PACE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_SPEED;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataType> CREATOR;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType DISTANCE;
+    field public static final androidx.health.services.client.data.DataType ELEVATION;
+    field public static final androidx.health.services.client.data.DataType FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType FLOORS;
+    field public static final androidx.health.services.client.data.DataType HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType LOCATION;
+    field public static final androidx.health.services.client.data.DataType MAX_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType MAX_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType MAX_PACE;
+    field public static final androidx.health.services.client.data.DataType MAX_SPEED;
+    field public static final androidx.health.services.client.data.DataType MIN_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType PACE;
+    field public static final androidx.health.services.client.data.DataType REP_COUNT;
+    field public static final androidx.health.services.client.data.DataType RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.DataType SPEED;
+    field public static final androidx.health.services.client.data.DataType SPO2;
+    field public static final androidx.health.services.client.data.DataType STEPS;
+    field public static final androidx.health.services.client.data.DataType STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.DataType TOTAL_CALORIES;
+    field public static final androidx.health.services.client.data.DataType VO2;
+    field public static final androidx.health.services.client.data.DataType VO2_MAX;
+    field public static final androidx.health.services.client.data.DataType WALKING_STEPS;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public enum DataType.TimeType {
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+  }
+
+  public final class DataTypeCondition implements android.os.Parcelable {
+    ctor public DataTypeCondition(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public androidx.health.services.client.data.ComparisonType component3();
+    method public androidx.health.services.client.data.DataTypeCondition copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public androidx.health.services.client.data.Value getThreshold();
+    method public boolean isSatisfied(androidx.health.services.client.data.DataPoint dataPoint);
+    method public boolean isThresholdSatisfied(androidx.health.services.client.data.Value value);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final androidx.health.services.client.data.Value threshold;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataTypeCondition> CREATOR;
+    field public static final androidx.health.services.client.data.DataTypeCondition.Companion Companion;
+  }
+
+  public static final class DataTypeCondition.Companion {
+  }
+
+  public final class DataTypes {
+    method public static androidx.health.services.client.data.DataType? getAggregateTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static java.util.Set<androidx.health.services.client.data.DataType> getAggregatedDataTypesFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getAverageTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getMaxTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAggregateType(androidx.health.services.client.data.DataType aggregateType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAverageType(androidx.health.services.client.data.DataType averageType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromMaxType(androidx.health.services.client.data.DataType maxType);
+    method public static boolean isAggregateDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isRawType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalAverageDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalMaxDataType(androidx.health.services.client.data.DataType dataType);
+    field public static final androidx.health.services.client.data.DataTypes INSTANCE;
+  }
+
+  public final class ExerciseCapabilities implements android.os.Parcelable {
+    ctor public ExerciseCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component2();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component3();
+    method public boolean component4();
+    method public boolean component5();
+    method public androidx.health.services.client.data.ExerciseCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    method public boolean getSupportsLaps();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+    property public final boolean supportsLaps;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseCapabilities.Companion Companion;
+  }
+
+  public static final class ExerciseCapabilities.Companion {
+  }
+
+  public final class ExerciseConfig implements android.os.Parcelable {
+    ctor protected ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder();
+    method public androidx.health.services.client.data.ExerciseType component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public boolean component3();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.ExerciseConfig copy(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public boolean getAutoPauseAndResume();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final boolean autoPauseAndResume;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder();
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setAutoPauseAndResume(boolean autoPauseAndResume);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<androidx.health.services.client.data.DataType> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseType(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder();
+  }
+
+  public final class ExerciseGoal implements android.os.Parcelable {
+    ctor protected ExerciseGoal(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, optional androidx.health.services.client.data.Value? period);
+    method public androidx.health.services.client.data.ExerciseGoalType component1();
+    method public androidx.health.services.client.data.DataTypeCondition component2();
+    method public androidx.health.services.client.data.Value? component3();
+    method public androidx.health.services.client.data.ExerciseGoal copy(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.Value? period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public static androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public androidx.health.services.client.data.Value? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final androidx.health.services.client.data.Value? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+  }
+
+  public enum ExerciseGoalType {
+    method public static final androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo implements android.os.Parcelable {
+    ctor public ExerciseInfo(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseTrackedStatus component1();
+    method public androidx.health.services.client.data.ExerciseType component2();
+    method public androidx.health.services.client.data.ExerciseInfo copy(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseTrackedStatus getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseInfo> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseInfo.Companion Companion;
+  }
+
+  public static final class ExerciseInfo.Companion {
+  }
+
+  public final class ExerciseLapSummary implements android.os.Parcelable {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int component1();
+    method public java.time.Instant component2();
+    method public java.time.Instant component3();
+    method public java.time.Duration component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.ExerciseLapSummary copy(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getLapMetrics();
+    method public java.time.Instant getStartTime();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics;
+    property public final java.time.Instant startTime;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseLapSummary> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseLapSummary.Companion Companion;
+  }
+
+  public static final class ExerciseLapSummary.Companion {
+  }
+
+  public enum ExerciseState {
+    method public static final androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public final int getId();
+    method public final boolean isEnded();
+    method public final boolean isPaused();
+    method public final boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public enum ExerciseTrackedStatus {
+    method public static final androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus NO_EXERCISE_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OTHER_APP_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OWNED_EXERCISE_IN_PROGRESS;
+    field public static final androidx.health.services.client.data.ExerciseTrackedStatus.Companion Companion;
+  }
+
+  public static final class ExerciseTrackedStatus.Companion {
+    method public androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+  }
+
+  public enum ExerciseType {
+    method public static final androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_SIT_UP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOXING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DANCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_FRONT_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_LATERAL_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_TWO_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FENCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GOLF;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GYNMASTICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PILATES;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PLANK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SAILING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKIING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SURFING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WALKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_INDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_OUTDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType YOGA;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseUpdate implements android.os.Parcelable {
+    ctor public ExerciseUpdate(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public androidx.health.services.client.data.ExerciseState component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> component4();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> component5();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> component6();
+    method public androidx.health.services.client.data.ExerciseConfig? component7();
+    method public androidx.health.services.client.data.AutoExerciseConfig? component8();
+    method public androidx.health.services.client.data.ExerciseType? component9();
+    method public androidx.health.services.client.data.ExerciseUpdate copy(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public androidx.health.services.client.data.AutoExerciseConfig? getAutoExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseType? getAutoExerciseDetected();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType getExerciseSessionType();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> getLatestAchievedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseType? autoExerciseDetected;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseUpdate> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public enum ExerciseUpdate.ExerciseSessionType {
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType AUTO_EXERCISE_DETECTION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType MANUALLY_STARTED_EXERCISE;
+  }
+
+  public final class MeasureCapabilities implements android.os.Parcelable {
+    ctor public MeasureCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public androidx.health.services.client.data.MeasureCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesMeasure();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MeasureCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.MeasureCapabilities.Companion Companion;
+  }
+
+  public static final class MeasureCapabilities.Companion {
+  }
+
+  public final class MilestoneMarkerSummary implements android.os.Parcelable {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public java.time.Instant component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public androidx.health.services.client.data.AchievedExerciseGoal component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.MilestoneMarkerSummary copy(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public int describeContents();
+    method public androidx.health.services.client.data.AchievedExerciseGoal getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getSummaryMetrics();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.AchievedExerciseGoal achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MilestoneMarkerSummary> CREATOR;
+    field public static final androidx.health.services.client.data.MilestoneMarkerSummary.Companion Companion;
+  }
+
+  public static final class MilestoneMarkerSummary.Companion {
+  }
+
+  public final class PassiveActivityState implements android.os.Parcelable {
+    ctor public PassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> component1();
+    method public androidx.health.services.client.data.UserActivityState component2();
+    method public androidx.health.services.client.data.ExerciseType? component3();
+    method public java.time.Instant component4();
+    method public androidx.health.services.client.data.PassiveActivityState copy(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public int describeContents();
+    method public static androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints();
+    method public androidx.health.services.client.data.ExerciseType? getExerciseType();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    method public void putToIntent(android.content.Intent intent);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<androidx.health.services.client.data.DataPoint> dataPoints;
+    property public final androidx.health.services.client.data.ExerciseType? exerciseType;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveActivityState> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveActivityState.Companion Companion;
+  }
+
+  public static final class PassiveActivityState.Companion {
+    method public androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+  }
+
+  public final class PassiveMonitoringCapabilities implements android.os.Parcelable {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public androidx.health.services.client.data.PassiveMonitoringCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesEvents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesPassiveMonitoring();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveMonitoringCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveMonitoringCapabilities.Companion Companion;
+  }
+
+  public static final class PassiveMonitoringCapabilities.Companion {
+  }
+
+  public enum UserActivityState {
+    method public static final androidx.health.services.client.data.UserActivityState? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_INACTIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+  }
+
+  public static final class UserActivityState.Companion {
+    method public androidx.health.services.client.data.UserActivityState? fromId(int id);
+  }
+
+  public final class Value implements android.os.Parcelable {
+    method public boolean asBoolean();
+    method public double asDouble();
+    method public double[] asDoubleArray();
+    method public long asLong();
+    method public int component1();
+    method public java.util.List<java.lang.Double> component2();
+    method public long component3();
+    method public androidx.health.services.client.data.Value copy(int format, java.util.List<java.lang.Double> doubleList, long longValue);
+    method public int describeContents();
+    method public java.util.List<java.lang.Double> getDoubleList();
+    method public int getFormat();
+    method public long getLongValue();
+    method public boolean isBoolean();
+    method public boolean isDouble();
+    method public boolean isDoubleArray();
+    method public boolean isLong();
+    method public static androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public static androidx.health.services.client.data.Value ofDouble(double value);
+    method public static androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public static androidx.health.services.client.data.Value ofLong(long value);
+    method public static androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<java.lang.Double> doubleList;
+    property public final int format;
+    property public final boolean isBoolean;
+    property public final boolean isDouble;
+    property public final boolean isDoubleArray;
+    property public final boolean isLong;
+    property public final long longValue;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Value> CREATOR;
+    field public static final androidx.health.services.client.data.Value.Companion Companion;
+    field public static final int FORMAT_BOOLEAN = 4; // 0x4
+    field public static final int FORMAT_DOUBLE = 1; // 0x1
+    field public static final int FORMAT_DOUBLE_ARRAY = 3; // 0x3
+    field public static final int FORMAT_LONG = 2; // 0x2
+  }
+
+  public static final class Value.Companion {
+    method public androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public androidx.health.services.client.data.Value ofDouble(double value);
+    method public androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public androidx.health.services.client.data.Value ofLong(long value);
+    method public androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+  }
+
+}
+
+package androidx.health.services.client.data.event {
+
+  public final class Event implements android.os.Parcelable {
+    ctor public Event(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public androidx.health.services.client.data.DataTypeCondition component1();
+    method public androidx.health.services.client.data.event.Event.TriggerType component2();
+    method public androidx.health.services.client.data.event.Event copy(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.event.Event.TriggerType getTriggerType();
+    method public boolean isTriggered(androidx.health.services.client.data.DataPoint dataPoint);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.event.Event.TriggerType triggerType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.event.Event> CREATOR;
+    field public static final androidx.health.services.client.data.event.Event.Companion Companion;
+  }
+
+  public static final class Event.Companion {
+  }
+
+  public enum Event.TriggerType {
+    method public static final androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType ONCE;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType REPEATED;
+    field public static final androidx.health.services.client.data.event.Event.TriggerType.Companion Companion;
+  }
+
+  public static final class Event.TriggerType.Companion {
+    method public androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+  }
+
+}
+
diff --git a/health/health-services-client/api/restricted_current.txt b/health/health-services-client/api/restricted_current.txt
index e6f50d0..6abe37c 100644
--- a/health/health-services-client/api/restricted_current.txt
+++ b/health/health-services-client/api/restricted_current.txt
@@ -1 +1,869 @@
 // Signature format: 4.0
+package androidx.health.services.client {
+
+  public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExercise(androidx.health.services.client.data.ExerciseGoal exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfo();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLap();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExercise(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExercise();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setUpdateListener(androidx.health.services.client.ExerciseUpdateListener listener, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExercise(androidx.health.services.client.data.ExerciseConfig configuration);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.Capabilities> capabilities;
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> currentExerciseInfo;
+  }
+
+  public interface ExerciseUpdateListener {
+    method public void onExerciseUpdate(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummary(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Availability availability);
+    method public void onData(java.util.List<androidx.health.services.client.data.DataPoint> data);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback, java.util.concurrent.Executor executor);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterCallback(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.MeasureCallback callback);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> capabilities;
+  }
+
+  public interface PassiveMonitoringCallback {
+    method public void onPassiveActivityState(androidx.health.services.client.data.PassiveActivityState state);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilities();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerDataCallback(java.util.Set<androidx.health.services.client.data.DataType> dataTypes, android.app.PendingIntent callbackIntent, androidx.health.services.client.PassiveMonitoringCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> registerEventCallback(androidx.health.services.client.data.event.Event event, android.app.PendingIntent callbackIntent);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterDataCallback();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterEventCallback(androidx.health.services.client.data.event.Event event);
+    property public abstract com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> capabilities;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AchievedExerciseGoal implements android.os.Parcelable {
+    ctor public AchievedExerciseGoal(androidx.health.services.client.data.ExerciseGoal goal);
+    method public androidx.health.services.client.data.ExerciseGoal component1();
+    method public androidx.health.services.client.data.AchievedExerciseGoal copy(androidx.health.services.client.data.ExerciseGoal goal);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseGoal getGoal();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseGoal goal;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AchievedExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.AchievedExerciseGoal.Companion Companion;
+  }
+
+  public static final class AchievedExerciseGoal.Companion {
+  }
+
+  public final class AutoExerciseConfig implements android.os.Parcelable {
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent, optional android.os.Bundle exerciseParams);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, optional android.app.PendingIntent? launchIntent);
+    ctor public AutoExerciseConfig(optional java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> component1();
+    method public android.app.PendingIntent? component2();
+    method public android.os.Bundle component3();
+    method public androidx.health.services.client.data.AutoExerciseConfig copy(java.util.Set<? extends androidx.health.services.client.data.ExerciseType> exercisesToDetect, android.app.PendingIntent? launchIntent, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public android.os.Bundle getExerciseParams();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getExercisesToDetect();
+    method public android.app.PendingIntent? getLaunchIntent();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final android.os.Bundle exerciseParams;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> exercisesToDetect;
+    property public final android.app.PendingIntent? launchIntent;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.AutoExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.AutoExerciseConfig.Companion Companion;
+  }
+
+  public static final class AutoExerciseConfig.Companion {
+  }
+
+  public enum Availability {
+    method public static final androidx.health.services.client.data.Availability? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.Availability ACQUIRING;
+    enum_constant public static final androidx.health.services.client.data.Availability AVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNAVAILABLE;
+    enum_constant public static final androidx.health.services.client.data.Availability UNKNOWN;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+    method public androidx.health.services.client.data.Availability? fromId(int id);
+  }
+
+  public final class Capabilities implements android.os.Parcelable {
+    ctor public Capabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> component1();
+    method public androidx.health.services.client.data.Capabilities copy(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseCapabilities getExerciseCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> getExerciseTypeToExerciseCapabilities();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseCapabilities> exerciseTypeToExerciseCapabilities;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Capabilities> CREATOR;
+    field public static final androidx.health.services.client.data.Capabilities.Companion Companion;
+  }
+
+  public static final class Capabilities.Companion {
+  }
+
+  public enum ComparisonType {
+    method public static final androidx.health.services.client.data.ComparisonType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    enum_constant public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+  }
+
+  public static final class ComparisonType.Companion {
+    method public androidx.health.services.client.data.ComparisonType? fromId(int id);
+  }
+
+  public final class DataPoint implements android.os.Parcelable {
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public java.time.Duration component3();
+    method public java.time.Duration component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.DataPoint copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public static androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public androidx.health.services.client.data.Value getValue();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final androidx.health.services.client.data.Value value;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataPoint> CREATOR;
+    field public static final androidx.health.services.client.data.DataPoint.Companion Companion;
+  }
+
+  public static final class DataPoint.Companion {
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createInterval(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot, optional android.os.Bundle metadata);
+    method public androidx.health.services.client.data.DataPoint createSample(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value value, java.time.Duration durationFromBoot);
+  }
+
+  @Keep public final class DataPoints {
+    method public static androidx.health.services.client.data.DataPoint aggregateCalories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateDistance(double distance, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSteps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint aggregateSwimmingStrokes(long swimmingStrokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint altitude(double meters, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averagePace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint averageSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint calories(double kcalories, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint distance(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint elevation(double meters, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint floors(double floors, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method @Keep public static java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints(android.content.Intent intent);
+    method public static boolean getPermissionsGranted(android.content.Intent intent);
+    method public static androidx.health.services.client.data.DataPoint heartRate(double bpm, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint location(double latitude, double longitude, double altitude, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint maxSpeed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint pace(double millisPerKm, java.time.Duration durationFromBoot);
+    method public static void putDataPoints(android.content.Intent intent, java.util.Collection<androidx.health.services.client.data.DataPoint> dataPoints);
+    method public static void putPermissionsGranted(android.content.Intent intent, boolean granted);
+    method public static androidx.health.services.client.data.DataPoint speed(double metersPerSecond, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint spo2(double percent, java.time.Duration durationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint steps(long steps, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint stepsPerMinute(long stepsPerMinute, java.time.Duration startDurationFromBoot);
+    method public static androidx.health.services.client.data.DataPoint swimmingStrokes(long strokes, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot);
+    field public static final androidx.health.services.client.data.DataPoints INSTANCE;
+    field public static final int LOCATION_DATA_POINT_ALTITUDE_INDEX = 2; // 0x2
+    field public static final int LOCATION_DATA_POINT_LATITUDE_INDEX = 0; // 0x0
+    field public static final int LOCATION_DATA_POINT_LONGITUDE_INDEX = 1; // 0x1
+  }
+
+  public final class DataType implements android.os.Parcelable {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public String component1();
+    method public androidx.health.services.client.data.DataType.TimeType component2();
+    method public int component3();
+    method public androidx.health.services.client.data.DataType copy(String name, androidx.health.services.client.data.DataType.TimeType timeType, int format);
+    method public int describeContents();
+    method public int getFormat();
+    method public String getName();
+    method public androidx.health.services.client.data.DataType.TimeType getTimeType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final int format;
+    property public final String name;
+    property public final androidx.health.services.client.data.DataType.TimeType timeType;
+    field public static final androidx.health.services.client.data.DataType ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType ACTIVE_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_CALORIES_EXPENDED;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_ELEVATION;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_FLOORS;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_RUNNING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_SWIMMING_STROKE_COUNT;
+    field public static final androidx.health.services.client.data.DataType AGGREGATE_WALKING_STEP_COUNT;
+    field public static final androidx.health.services.client.data.DataType ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_PACE;
+    field public static final androidx.health.services.client.data.DataType AVERAGE_SPEED;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataType> CREATOR;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType DECLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType DISTANCE;
+    field public static final androidx.health.services.client.data.DataType ELEVATION;
+    field public static final androidx.health.services.client.data.DataType FLAT_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType FLAT_TIME;
+    field public static final androidx.health.services.client.data.DataType FLOORS;
+    field public static final androidx.health.services.client.data.DataType HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.DataType INCLINE_TIME;
+    field public static final androidx.health.services.client.data.DataType LOCATION;
+    field public static final androidx.health.services.client.data.DataType MAX_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType MAX_HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.DataType MAX_PACE;
+    field public static final androidx.health.services.client.data.DataType MAX_SPEED;
+    field public static final androidx.health.services.client.data.DataType MIN_ALTITUDE;
+    field public static final androidx.health.services.client.data.DataType PACE;
+    field public static final androidx.health.services.client.data.DataType REP_COUNT;
+    field public static final androidx.health.services.client.data.DataType RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.DataType RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.DataType SPEED;
+    field public static final androidx.health.services.client.data.DataType SPO2;
+    field public static final androidx.health.services.client.data.DataType STEPS;
+    field public static final androidx.health.services.client.data.DataType STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DataType SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.DataType TOTAL_CALORIES;
+    field public static final androidx.health.services.client.data.DataType VO2;
+    field public static final androidx.health.services.client.data.DataType VO2_MAX;
+    field public static final androidx.health.services.client.data.DataType WALKING_STEPS;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public enum DataType.TimeType {
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    enum_constant public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+  }
+
+  public final class DataTypeCondition implements android.os.Parcelable {
+    ctor public DataTypeCondition(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.DataType component1();
+    method public androidx.health.services.client.data.Value component2();
+    method public androidx.health.services.client.data.ComparisonType component3();
+    method public androidx.health.services.client.data.DataTypeCondition copy(androidx.health.services.client.data.DataType dataType, androidx.health.services.client.data.Value threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public androidx.health.services.client.data.DataType getDataType();
+    method public androidx.health.services.client.data.Value getThreshold();
+    method public boolean isSatisfied(androidx.health.services.client.data.DataPoint dataPoint);
+    method public boolean isThresholdSatisfied(androidx.health.services.client.data.Value value);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final androidx.health.services.client.data.DataType dataType;
+    property public final androidx.health.services.client.data.Value threshold;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.DataTypeCondition> CREATOR;
+    field public static final androidx.health.services.client.data.DataTypeCondition.Companion Companion;
+  }
+
+  public static final class DataTypeCondition.Companion {
+  }
+
+  public final class DataTypes {
+    method public static androidx.health.services.client.data.DataType? getAggregateTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static java.util.Set<androidx.health.services.client.data.DataType> getAggregatedDataTypesFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getAverageTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getMaxTypeFromRawType(androidx.health.services.client.data.DataType rawType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAggregateType(androidx.health.services.client.data.DataType aggregateType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromAverageType(androidx.health.services.client.data.DataType averageType);
+    method public static androidx.health.services.client.data.DataType? getRawTypeFromMaxType(androidx.health.services.client.data.DataType maxType);
+    method public static boolean isAggregateDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isRawType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalAverageDataType(androidx.health.services.client.data.DataType dataType);
+    method public static boolean isStatisticalMaxDataType(androidx.health.services.client.data.DataType dataType);
+    field public static final androidx.health.services.client.data.DataTypes INSTANCE;
+  }
+
+  public final class ExerciseCapabilities implements android.os.Parcelable {
+    ctor public ExerciseCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component2();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> component3();
+    method public boolean component4();
+    method public boolean component5();
+    method public androidx.health.services.client.data.ExerciseCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.Set<? extends androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume, boolean supportsLaps);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    method public boolean getSupportsLaps();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+    property public final boolean supportsLaps;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseCapabilities.Companion Companion;
+  }
+
+  public static final class ExerciseCapabilities.Companion {
+  }
+
+  public final class ExerciseConfig implements android.os.Parcelable {
+    ctor protected ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder();
+    method public androidx.health.services.client.data.ExerciseType component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public boolean component3();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> component4();
+    method public android.os.Bundle component5();
+    method public androidx.health.services.client.data.ExerciseConfig copy(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<androidx.health.services.client.data.DataType> dataTypes, boolean autoPauseAndResume, java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals, android.os.Bundle exerciseParams);
+    method public int describeContents();
+    method public boolean getAutoPauseAndResume();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final boolean autoPauseAndResume;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseConfig> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder();
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setAutoPauseAndResume(boolean autoPauseAndResume);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<androidx.health.services.client.data.DataType> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<androidx.health.services.client.data.ExerciseGoal> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseType(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder();
+  }
+
+  public final class ExerciseGoal implements android.os.Parcelable {
+    ctor protected ExerciseGoal(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, optional androidx.health.services.client.data.Value? period);
+    method public androidx.health.services.client.data.ExerciseGoalType component1();
+    method public androidx.health.services.client.data.DataTypeCondition component2();
+    method public androidx.health.services.client.data.Value? component3();
+    method public androidx.health.services.client.data.ExerciseGoal copy(androidx.health.services.client.data.ExerciseGoalType exerciseGoalType, androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.Value? period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public static androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public static androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public androidx.health.services.client.data.Value? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final androidx.health.services.client.data.Value? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public androidx.health.services.client.data.ExerciseGoal createMilestone(androidx.health.services.client.data.DataTypeCondition condition, androidx.health.services.client.data.Value period);
+    method public androidx.health.services.client.data.ExerciseGoal createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal goal, androidx.health.services.client.data.Value newThreshold);
+    method public androidx.health.services.client.data.ExerciseGoal createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition condition);
+  }
+
+  public enum ExerciseGoalType {
+    method public static final androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo implements android.os.Parcelable {
+    ctor public ExerciseInfo(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseTrackedStatus component1();
+    method public androidx.health.services.client.data.ExerciseType component2();
+    method public androidx.health.services.client.data.ExerciseInfo copy(androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.ExerciseTrackedStatus getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.ExerciseTrackedStatus exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseInfo> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseInfo.Companion Companion;
+  }
+
+  public static final class ExerciseInfo.Companion {
+  }
+
+  public final class ExerciseLapSummary implements android.os.Parcelable {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int component1();
+    method public java.time.Instant component2();
+    method public java.time.Instant component3();
+    method public java.time.Duration component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.ExerciseLapSummary copy(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getLapMetrics();
+    method public java.time.Instant getStartTime();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> lapMetrics;
+    property public final java.time.Instant startTime;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseLapSummary> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseLapSummary.Companion Companion;
+  }
+
+  public static final class ExerciseLapSummary.Companion {
+  }
+
+  public enum ExerciseState {
+    method public static final androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public final int getId();
+    method public final boolean isEnded();
+    method public final boolean isPaused();
+    method public final boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState TERMINATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_ENDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public enum ExerciseTrackedStatus {
+    method public static final androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus NO_EXERCISE_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OTHER_APP_IN_PROGRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseTrackedStatus OWNED_EXERCISE_IN_PROGRESS;
+    field public static final androidx.health.services.client.data.ExerciseTrackedStatus.Companion Companion;
+  }
+
+  public static final class ExerciseTrackedStatus.Companion {
+    method public androidx.health.services.client.data.ExerciseTrackedStatus? fromId(int id);
+  }
+
+  public enum ExerciseType {
+    method public static final androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BENCH_SIT_UP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BOXING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DANCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_CURL_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_FRONT_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_LATERAL_RAISE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_LEFT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_RIGHT_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType DUMBBELL_TRICEPS_EXTENSION_TWO_ARM;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FENCING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GOLF;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType GYNMASTICS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType HIKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PILATES;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType PLANK;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SAILING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKATING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SKIING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SURFING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WALKING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_INDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType WORKOUT_OUTDOOR;
+    enum_constant public static final androidx.health.services.client.data.ExerciseType YOGA;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseUpdate implements android.os.Parcelable {
+    ctor public ExerciseUpdate(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public androidx.health.services.client.data.ExerciseState component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> component4();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> component5();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> component6();
+    method public androidx.health.services.client.data.ExerciseConfig? component7();
+    method public androidx.health.services.client.data.AutoExerciseConfig? component8();
+    method public androidx.health.services.client.data.ExerciseType? component9();
+    method public androidx.health.services.client.data.ExerciseUpdate copy(androidx.health.services.client.data.ExerciseState state, java.time.Instant startTime, java.time.Duration activeDuration, java.util.Map<androidx.health.services.client.data.DataType,? extends java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics, java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals, java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries, androidx.health.services.client.data.ExerciseConfig? exerciseConfig, androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig, androidx.health.services.client.data.ExerciseType? autoExerciseDetected);
+    method public int describeContents();
+    method public java.time.Duration getActiveDuration();
+    method public androidx.health.services.client.data.AutoExerciseConfig? getAutoExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseType? getAutoExerciseDetected();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType getExerciseSessionType();
+    method public java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> getLatestAchievedGoals();
+    method public java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.time.Duration activeDuration;
+    property public final androidx.health.services.client.data.AutoExerciseConfig? autoExerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseType? autoExerciseDetected;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final java.util.Set<androidx.health.services.client.data.AchievedExerciseGoal> latestAchievedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,java.util.List<androidx.health.services.client.data.DataPoint>> latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseUpdate> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public enum ExerciseUpdate.ExerciseSessionType {
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType AUTO_EXERCISE_DETECTION;
+    enum_constant public static final androidx.health.services.client.data.ExerciseUpdate.ExerciseSessionType MANUALLY_STARTED_EXERCISE;
+  }
+
+  public final class MeasureCapabilities implements android.os.Parcelable {
+    ctor public MeasureCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public androidx.health.services.client.data.MeasureCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesMeasure();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesMeasure;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MeasureCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.MeasureCapabilities.Companion Companion;
+  }
+
+  public static final class MeasureCapabilities.Companion {
+  }
+
+  public final class MilestoneMarkerSummary implements android.os.Parcelable {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public java.time.Instant component1();
+    method public java.time.Instant component2();
+    method public java.time.Duration component3();
+    method public androidx.health.services.client.data.AchievedExerciseGoal component4();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> component5();
+    method public androidx.health.services.client.data.MilestoneMarkerSummary copy(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.AchievedExerciseGoal achievedGoal, java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics);
+    method public int describeContents();
+    method public androidx.health.services.client.data.AchievedExerciseGoal getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> getSummaryMetrics();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.AchievedExerciseGoal achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final java.util.Map<androidx.health.services.client.data.DataType,androidx.health.services.client.data.DataPoint> summaryMetrics;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.MilestoneMarkerSummary> CREATOR;
+    field public static final androidx.health.services.client.data.MilestoneMarkerSummary.Companion Companion;
+  }
+
+  public static final class MilestoneMarkerSummary.Companion {
+  }
+
+  public final class PassiveActivityState implements android.os.Parcelable {
+    ctor public PassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> component1();
+    method public androidx.health.services.client.data.UserActivityState component2();
+    method public androidx.health.services.client.data.ExerciseType? component3();
+    method public java.time.Instant component4();
+    method public androidx.health.services.client.data.PassiveActivityState copy(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseType? exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public int describeContents();
+    method public static androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+    method public java.util.List<androidx.health.services.client.data.DataPoint> getDataPoints();
+    method public androidx.health.services.client.data.ExerciseType? getExerciseType();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    method public void putToIntent(android.content.Intent intent);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<androidx.health.services.client.data.DataPoint> dataPoints;
+    property public final androidx.health.services.client.data.ExerciseType? exerciseType;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveActivityState> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveActivityState.Companion Companion;
+  }
+
+  public static final class PassiveActivityState.Companion {
+    method public androidx.health.services.client.data.PassiveActivityState createActiveExerciseState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, androidx.health.services.client.data.ExerciseType exerciseType, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createInactiveState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createPassiveActivityState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState createUnknownTypeState(java.util.List<androidx.health.services.client.data.DataPoint> dataPoints, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.PassiveActivityState? fromIntent(android.content.Intent intent);
+  }
+
+  public final class PassiveMonitoringCapabilities implements android.os.Parcelable {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public java.util.Set<androidx.health.services.client.data.DataType> component1();
+    method public java.util.Set<androidx.health.services.client.data.DataType> component2();
+    method public androidx.health.services.client.data.PassiveMonitoringCapabilities copy(java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring, java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents);
+    method public int describeContents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesEvents();
+    method public java.util.Set<androidx.health.services.client.data.DataType> getSupportedDataTypesPassiveMonitoring();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesEvents;
+    property public final java.util.Set<androidx.health.services.client.data.DataType> supportedDataTypesPassiveMonitoring;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.PassiveMonitoringCapabilities> CREATOR;
+    field public static final androidx.health.services.client.data.PassiveMonitoringCapabilities.Companion Companion;
+  }
+
+  public static final class PassiveMonitoringCapabilities.Companion {
+  }
+
+  public enum UserActivityState {
+    method public static final androidx.health.services.client.data.UserActivityState? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_INACTIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    enum_constant public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+  }
+
+  public static final class UserActivityState.Companion {
+    method public androidx.health.services.client.data.UserActivityState? fromId(int id);
+  }
+
+  public final class Value implements android.os.Parcelable {
+    method public boolean asBoolean();
+    method public double asDouble();
+    method public double[] asDoubleArray();
+    method public long asLong();
+    method public int component1();
+    method public java.util.List<java.lang.Double> component2();
+    method public long component3();
+    method public androidx.health.services.client.data.Value copy(int format, java.util.List<java.lang.Double> doubleList, long longValue);
+    method public int describeContents();
+    method public java.util.List<java.lang.Double> getDoubleList();
+    method public int getFormat();
+    method public long getLongValue();
+    method public boolean isBoolean();
+    method public boolean isDouble();
+    method public boolean isDoubleArray();
+    method public boolean isLong();
+    method public static androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public static androidx.health.services.client.data.Value ofDouble(double value);
+    method public static androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public static androidx.health.services.client.data.Value ofLong(long value);
+    method public static androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final java.util.List<java.lang.Double> doubleList;
+    property public final int format;
+    property public final boolean isBoolean;
+    property public final boolean isDouble;
+    property public final boolean isDoubleArray;
+    property public final boolean isLong;
+    property public final long longValue;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.Value> CREATOR;
+    field public static final androidx.health.services.client.data.Value.Companion Companion;
+    field public static final int FORMAT_BOOLEAN = 4; // 0x4
+    field public static final int FORMAT_DOUBLE = 1; // 0x1
+    field public static final int FORMAT_DOUBLE_ARRAY = 3; // 0x3
+    field public static final int FORMAT_LONG = 2; // 0x2
+  }
+
+  public static final class Value.Companion {
+    method public androidx.health.services.client.data.Value ofBoolean(boolean value);
+    method public androidx.health.services.client.data.Value ofDouble(double value);
+    method public androidx.health.services.client.data.Value ofDoubleArray(double... doubleArray);
+    method public androidx.health.services.client.data.Value ofLong(long value);
+    method public androidx.health.services.client.data.Value sum(androidx.health.services.client.data.Value first, androidx.health.services.client.data.Value second);
+  }
+
+}
+
+package androidx.health.services.client.data.event {
+
+  public final class Event implements android.os.Parcelable {
+    ctor public Event(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public androidx.health.services.client.data.DataTypeCondition component1();
+    method public androidx.health.services.client.data.event.Event.TriggerType component2();
+    method public androidx.health.services.client.data.event.Event copy(androidx.health.services.client.data.DataTypeCondition dataTypeCondition, androidx.health.services.client.data.event.Event.TriggerType triggerType);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition getDataTypeCondition();
+    method public androidx.health.services.client.data.event.Event.TriggerType getTriggerType();
+    method public boolean isTriggered(androidx.health.services.client.data.DataPoint dataPoint);
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition dataTypeCondition;
+    property public final androidx.health.services.client.data.event.Event.TriggerType triggerType;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.event.Event> CREATOR;
+    field public static final androidx.health.services.client.data.event.Event.Companion Companion;
+  }
+
+  public static final class Event.Companion {
+  }
+
+  public enum Event.TriggerType {
+    method public static final androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+    method public final int getId();
+    property public final int id;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType ONCE;
+    enum_constant public static final androidx.health.services.client.data.event.Event.TriggerType REPEATED;
+    field public static final androidx.health.services.client.data.event.Event.TriggerType.Companion Companion;
+  }
+
+  public static final class Event.TriggerType.Companion {
+    method public androidx.health.services.client.data.event.Event.TriggerType? fromId(int id);
+  }
+
+}
+
diff --git a/health/health-services-client/build.gradle b/health/health-services-client/build.gradle
index cd0be24..248825c 100644
--- a/health/health-services-client/build.gradle
+++ b/health/health-services-client/build.gradle
@@ -26,7 +26,19 @@
 
 dependencies {
     api(KOTLIN_STDLIB)
-    // Add dependencies here
+    api("androidx.annotation:annotation:1.1.0")
+    implementation(GUAVA_LISTENABLE_FUTURE)
+    implementation(GUAVA_ANDROID)
+    implementation("androidx.core:core-ktx:1.5.0-alpha04")
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 26
+    }
+    buildFeatures {
+        aidl = true
+    }
 }
 
 androidx {
diff --git a/health/health-services-client/lint-baseline.xml b/health/health-services-client/lint-baseline.xml
new file mode 100644
index 0000000..11eec21
--- /dev/null
+++ b/health/health-services-client/lint-baseline.xml
@@ -0,0 +1,1291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.2.0-beta06" client="gradle" variant="debug" version="4.2.0-beta06">
+
+    <issue
+        id="BanKeepAnnotation"
+        message="Uses @Keep annotation"
+        errorLine1="@Keep"
+        errorLine2="~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/DataPoints.kt"
+            line="27"
+            column="1"/>
+    </issue>
+
+    <issue
+        id="BanKeepAnnotation"
+        message="Uses @Keep annotation"
+        errorLine1="    @Keep"
+        errorLine2="    ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/DataPoints.kt"
+            line="56"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class AchievedExerciseGoal("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/AchievedExerciseGoal.kt"
+            line="23"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class AutoExerciseConfig"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/AutoExerciseConfig.kt"
+            line="26"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class AutoPauseAndResumeConfigRequest("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.kt"
+            line="27"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class AvailabilityResponse("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/AvailabilityResponse.kt"
+            line="29"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class BackgroundRegistrationRequest("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class BackgroundUnregistrationRequest(val packageName: String) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.kt"
+            line="27"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class Capabilities("
+        errorLine2="                  ~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Capabilities.kt"
+            line="24"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class CapabilitiesRequest(val packageName: String) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/CapabilitiesRequest.kt"
+            line="27"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class CapabilitiesResponse("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/CapabilitiesResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class DataPoint"
+        errorLine2="                  ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/DataPoint.kt"
+            line="31"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class DataPointsResponse(val dataPoints: List&lt;DataPoint>) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/DataPointsResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class DataType("
+        errorLine2="                  ~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/DataType.kt"
+            line="32"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class DataTypeCondition("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/DataTypeCondition.kt"
+            line="23"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class Event("
+        errorLine2="                  ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/event/Event.kt"
+            line="25"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class EventRequest(val packageName: String, val event: Event) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/EventRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseCapabilities("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt"
+            line="23"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseConfig"
+        errorLine2="                  ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseConfig.kt"
+            line="26"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseGoal"
+        errorLine2="                  ~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseGoal.kt"
+            line="26"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseGoalRequest(val packageName: String, val exerciseGoal: ExerciseGoal) :"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/ExerciseGoalRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseInfo("
+        errorLine2="                  ~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseInfo.kt"
+            line="23"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseInfoResponse(val exerciseInfo: ExerciseInfo) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/ExerciseInfoResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseLapSummary("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseLapSummary.kt"
+            line="25"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseLapSummaryResponse(val exerciseLapSummary: ExerciseLapSummary) :"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseUpdate("
+        errorLine2="                  ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseUpdate.kt"
+            line="26"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class ExerciseUpdateResponse(val exerciseUpdate: ExerciseUpdate) : Parcelable {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/ExerciseUpdateResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class MeasureCapabilities("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/MeasureCapabilities.kt"
+            line="25"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class MeasureCapabilitiesResponse("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class MeasureRegistrationRequest("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/MeasureRegistrationRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class MeasureUnregistrationRequest("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class MilestoneMarkerSummary("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/MilestoneMarkerSummary.kt"
+            line="27"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class PassiveActivityState("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/PassiveActivityState.kt"
+            line="34"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class PassiveActivityStateResponse(val passiveActivityState: PassiveActivityState) :"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/PassiveActivityStateResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class PassiveMonitoringCapabilities("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/PassiveMonitoringCapabilities.kt"
+            line="26"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class PassiveMonitoringCapabilitiesResponse("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class StartExerciseRequest("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/request/StartExerciseRequest.kt"
+            line="28"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanParcelableUsage"
+        message="Class implements android.os.Parcelable"
+        errorLine1="public data class Value"
+        errorLine2="                  ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Value.kt"
+            line="24"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="        @Synchronized"
+        errorLine2="        ^">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt"
+            line="55"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="        @Synchronized"
+        errorLine2="        ^">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt"
+            line="63"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="        @Synchronized"
+        errorLine2="        ^">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt"
+            line="63"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="        @Synchronized"
+        errorLine2="        ^">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt"
+            line="86"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    private synchronized void handleRetriableDisconnection(Throwable throwable) {"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="155"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `getExerciseToExerciseCapabilityMap` of class `Companion` requires synthetic accessor"
+        errorLine1="                        getExerciseToExerciseCapabilityMap(parcel)"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Capabilities.kt"
+            line="79"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `createQueueOperation` of class `Client` requires synthetic accessor"
+        errorLine1="                                                createQueueOperation("
+        errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="133"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `writeSupportedDataTypes` of class `Companion` requires synthetic accessor"
+        errorLine1="        writeSupportedDataTypes(supportedGoals, dest, flags)"
+        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt"
+            line="36"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `writeSupportedDataTypes` of class `Companion` requires synthetic accessor"
+        errorLine1="        writeSupportedDataTypes(supportedMilestones, dest, flags)"
+        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt"
+            line="37"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `readSupportedDataTypes` of class `Companion` requires synthetic accessor"
+        errorLine1="                    val supportedGoals = readSupportedDataTypes(source) ?: return null"
+        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt"
+            line="51"
+            column="42"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `readSupportedDataTypes` of class `Companion` requires synthetic accessor"
+        errorLine1="                    val supportedMilestones = readSupportedDataTypes(source) ?: return null"
+        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt"
+            line="52"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` method `initialize` of class `Companion` requires synthetic accessor"
+        errorLine1="        private val IDS = initialize()"
+        errorLine2="                          ~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/ExerciseType.kt"
+            line="114"
+            column="27"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` constructor of class `ExerciseUpdateListenerStub` requires synthetic accessor"
+        errorLine1="            return listeners.getOrPut(listener) { ExerciseUpdateListenerStub(listener, executor) }"
+        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt"
+            line="60"
+            column="51"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` constructor of class `MeasureCallbackStub` requires synthetic accessor"
+        errorLine1="                measureCallbackStub = MeasureCallbackStub(callbackKey, measureCallback)"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt"
+            line="79"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` constructor of class `Value` requires synthetic accessor"
+        errorLine1="                            return Value(format, listOf(), parcel.readLong())"
+        errorLine2="                                   ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Value.kt"
+            line="142"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` constructor of class `Value` requires synthetic accessor"
+        errorLine1="                            return Value(format, listOf(parcel.readDouble()), /* longValue= */ 0)"
+        errorLine2="                                   ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Value.kt"
+            line="144"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="SyntheticAccessor"
+        message="Access to `private` constructor of class `Value` requires synthetic accessor"
+        errorLine1="                            return Value(format, doubleArray.toList(), /* longValue= */ 0)"
+        errorLine2="                                   ~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/data/Value.kt"
+            line="148"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="LambdaLast"
+        message="Functional interface parameters (such as parameter 1, &quot;operation&quot;, in androidx.health.services.client.impl.ipc.Client.executeWithVersionCheck) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
+        errorLine1="            ServiceOperation&lt;R> operation, int minApiVersion) {"
+        errorLine2="                                           ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="115"
+            column="44"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public BaseQueueOperation(ConnectionConfiguration connectionConfiguration) {"
+        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="37"
+            column="31"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void execute(IBinder binder) throws RemoteException {}"
+        errorLine2="                        ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="42"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void setException(Throwable exception) {}"
+        errorLine2="                             ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="45"
+            column="30"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public QueueOperation trackExecution(ExecutionTracker tracker) {"
+        errorLine2="           ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="48"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public QueueOperation trackExecution(ExecutionTracker tracker) {"
+        errorLine2="                                         ~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="48"
+            column="42"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ConnectionConfiguration getConnectionConfiguration() {"
+        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java"
+            line="54"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="        Integer readVersion(IBinder binder) throws RemoteException;"
+        errorLine2="        ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="53"
+            column="9"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="        Integer readVersion(IBinder binder) throws RemoteException;"
+        errorLine2="                            ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="53"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ClientConfiguration clientConfiguration,"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="65"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ConnectionManager connectionManager,"
+        errorLine2="            ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="66"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            VersionGetter versionGetter) {"
+        errorLine2="            ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="67"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(ServiceOperation&lt;R> operation) {"
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="107"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(ServiceOperation&lt;R> operation) {"
+        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="107"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected &lt;R> ListenableFuture&lt;R> executeWithVersionCheck("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="114"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ServiceOperation&lt;R> operation, int minApiVersion) {"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="115"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected &lt;R> ListenableFuture&lt;R> registerListener("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="173"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ListenerKey listenerKey, ServiceOperation&lt;R> registerListenerOperation) {"
+        errorLine2="            ~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="174"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ListenerKey listenerKey, ServiceOperation&lt;R> registerListenerOperation) {"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="174"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected &lt;R> ListenableFuture&lt;R> unregisterListener("
+        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="193"
+            column="19"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ListenerKey listenerKey, ServiceOperation&lt;R> unregisterListenerOperation) {"
+        errorLine2="            ~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="194"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            ListenerKey listenerKey, ServiceOperation&lt;R> unregisterListenerOperation) {"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="194"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    protected Exception getApiVersionCheckFailureException(int currentVersion, int minApiVersion) {"
+        errorLine2="              ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"
+            line="203"
+            column="15"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ClientConfiguration(String apiClientName, String servicePackageName, String bindAction) {"
+        errorLine2="                               ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="34"
+            column="32"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ClientConfiguration(String apiClientName, String servicePackageName, String bindAction) {"
+        errorLine2="                                                     ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="34"
+            column="54"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ClientConfiguration(String apiClientName, String servicePackageName, String bindAction) {"
+        errorLine2="                                                                                ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="34"
+            column="81"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public String getServicePackageName() {"
+        errorLine2="           ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="41"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public String getBindAction() {"
+        errorLine2="           ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="46"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public String getApiClientName() {"
+        errorLine2="           ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java"
+            line="51"
+            column="12"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            String packageName,"
+        errorLine2="            ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java"
+            line="38"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            String clientName,"
+        errorLine2="            ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java"
+            line="39"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            String bindAction,"
+        errorLine2="            ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java"
+            line="40"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="            QueueOperation refreshVersionOperation) {"
+        errorLine2="            ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java"
+            line="41"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ConnectionManager(Context context, Looper looper) {"
+        errorLine2="                             ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="52"
+            column="30"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ConnectionManager(Context context, Looper looper) {"
+        errorLine2="                                              ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="52"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void scheduleForExecution(QueueOperation operation) {"
+        errorLine2="                                     ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="62"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void registerListener(ListenerKey listenerKey, QueueOperation registerOperation) {"
+        errorLine2="                                 ~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="73"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void registerListener(ListenerKey listenerKey, QueueOperation registerOperation) {"
+        errorLine2="                                                          ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="73"
+            column="59"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation) {"
+        errorLine2="                                   ~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="86"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation) {"
+        errorLine2="                                                            ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="86"
+            column="61"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onConnected(ServiceConnection connection) {"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="94"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onDisconnected(ServiceConnection connection, long reconnectDelayMs) {"
+        errorLine2="                               ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="99"
+            column="32"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public boolean handleMessage(Message msg) {"
+        errorLine2="                                 ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java"
+            line="110"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void track(SettableFuture&lt;?> future) {"
+        errorLine2="                      ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java"
+            line="39"
+            column="23"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void cancelPendingFutures(Throwable throwable) {"
+        errorLine2="                                     ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java"
+            line="45"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void track(SettableFuture&lt;?> future);"
+        errorLine2="               ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java"
+            line="33"
+            column="16"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void cancelPendingFutures(Throwable throwable);"
+        errorLine2="                              ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java"
+            line="36"
+            column="31"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public ListenerKey(Object listenerKey) {"
+        errorLine2="                       ~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java"
+            line="32"
+            column="24"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void execute(IBinder binder) throws RemoteException;"
+        errorLine2="                 ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"
+            line="38"
+            column="18"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void setException(Throwable exception);"
+        errorLine2="                      ~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"
+            line="41"
+            column="23"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    QueueOperation trackExecution(ExecutionTracker tracker);"
+        errorLine2="    ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"
+            line="48"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    QueueOperation trackExecution(ExecutionTracker tracker);"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"
+            line="48"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    ConnectionConfiguration getConnectionConfiguration();"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java"
+            line="51"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="        void onConnected(ServiceConnection connection);"
+        errorLine2="                         ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="61"
+            column="26"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="        void onDisconnected(ServiceConnection connection, long reconnectDelayMs);"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="69"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onServiceConnected(ComponentName componentName, IBinder binder) {"
+        errorLine2="                                   ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="287"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onServiceConnected(ComponentName componentName, IBinder binder) {"
+        errorLine2="                                                                ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="287"
+            column="65"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onServiceDisconnected(ComponentName componentName) {"
+        errorLine2="                                      ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="320"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onBindingDied(ComponentName name) {"
+        errorLine2="                              ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="326"
+            column="31"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    public void onNullBinding(ComponentName name) {"
+        errorLine2="                              ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"
+            line="332"
+            column="31"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void execute(IBinder binder, SettableFuture&lt;R> resultFuture) throws RemoteException;"
+        errorLine2="                 ~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java"
+            line="44"
+            column="18"/>
+    </issue>
+
+    <issue
+        id="UnknownNullness"
+        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+        errorLine1="    void execute(IBinder binder, SettableFuture&lt;R> resultFuture) throws RemoteException;"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java"
+            line="44"
+            column="34"/>
+    </issue>
+
+</issues>
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseApiService.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseApiService.aidl
new file mode 100644
index 0000000..6a08a9a
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseApiService.aidl
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+import androidx.health.services.client.impl.IExerciseUpdateListener;
+import androidx.health.services.client.impl.internal.IExerciseInfoCallback;
+import androidx.health.services.client.impl.internal.IStatusCallback;
+import androidx.health.services.client.impl.request.AutoPauseAndResumeConfigRequest;
+import androidx.health.services.client.impl.request.CapabilitiesRequest;
+import androidx.health.services.client.impl.request.ExerciseGoalRequest;
+import androidx.health.services.client.impl.request.StartExerciseRequest;
+import androidx.health.services.client.impl.response.CapabilitiesResponse;
+
+/**
+ * Interface to make ipc calls for health services exercise api.
+ *
+ * The next method added to the interface should use ID: 13
+ * (this id needs to be incremented for each added method)
+ *
+ * @hide
+ */
+interface IExerciseApiService {
+    /**
+     * API version of the AIDL interface. Should be incremented every time a new
+     * method is added.
+     *
+     */
+    const int API_VERSION = 1;
+
+    /**
+     * Handles a given request to start an exercise.
+     */
+    void startExercise(in StartExerciseRequest startExerciseRequest, IStatusCallback statusCallback) = 5;
+
+    /**
+     * Method to pause the active exercise for the calling app.
+     */
+    void pauseExercise(in String packageName, IStatusCallback statusCallback) = 0;
+
+    /**
+     * Method to resume the active exercise for the calling app.
+     */
+    void resumeExercise(in String packageName, IStatusCallback statusCallback) = 1;
+
+    /**
+     * Method to end the active exercise for the calling app.
+     */
+    void endExercise(in String packageName, IStatusCallback statusCallback) = 2;
+
+    /**
+    * Method to end the current lap in the active exercise for the calling app.
+    */
+    void markLap(in String packageName, IStatusCallback statusCallback) = 9;
+
+    /**
+     * Returns version of this AIDL interface.
+     *
+     * <p> Can be used by client to detect version of the API on the service
+     * side. Returned version should be always > 0.
+     */
+    int getApiVersion() = 3;
+
+    /**
+     * Returns the current exercise info.
+     */
+    void getCurrentExerciseInfo(in String packageName, IExerciseInfoCallback exerciseInfoCallback) = 12;
+
+    /**
+     * Sets the listener for the current exercise state.
+     */
+    void setUpdateListener(in String packageName, in IExerciseUpdateListener listener, IStatusCallback statusCallback)  = 6;
+
+    /**
+     * Clears the listener set using {@link #setUpdateListener}.
+     */
+    void clearUpdateListener(in String packageName, in IExerciseUpdateListener listener, IStatusCallback statusCallback) = 7;
+
+    /**
+     * Adds an exercise goal for an active exercise.
+     *
+     * <p>An exercise goal is a one-time goal, such as achieving a target total step count.
+     *
+     * <p>Goals apply to only active exercises owned by the client, and will be invalidated once the
+     * exercise is complete. A goal can be added only after an exercise has been started.
+     */
+    void addGoalToActiveExercise(in ExerciseGoalRequest request, IStatusCallback statusCallback) = 8;
+
+    /**
+     * Sets whether auto-pause should be enabled
+     */
+    void overrideAutoPauseAndResumeForActiveExercise(in AutoPauseAndResumeConfigRequest request, IStatusCallback statusCallback) = 10;
+
+    /**
+     * Method to get capabilities.
+     */
+    CapabilitiesResponse getCapabilities(in CapabilitiesRequest request) = 11;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
new file mode 100644
index 0000000..df6420bd
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IExerciseUpdateListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+import androidx.health.services.client.impl.response.ExerciseLapSummaryResponse;
+import androidx.health.services.client.impl.response.ExerciseUpdateResponse;
+
+/**
+ * Interface to get exercise updates.
+ *
+ * @hide
+ */
+oneway interface IExerciseUpdateListener {
+    /** Called when there is an update of exercise state or metrics. */
+    void onExerciseUpdate(in ExerciseUpdateResponse update) = 0;
+
+    /** Called when a lap has been marked. */
+    void onLapSummary(in ExerciseLapSummaryResponse summaryResponse) = 1;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl
new file mode 100644
index 0000000..ddccc54
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IHealthServicesApiService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+/**
+ * Interface to make ipc calls for health services api.
+ *
+ * @hide
+ */
+interface IHealthServicesApiService {
+    /**
+     * API version of the AIDL interface. Should be incremented every time a new
+     * method is added.
+     */
+    const int API_VERSION = 1;
+
+    /**
+     * Returns version of this AIDL interface.
+     *
+     * <p> Can be used by client to detect version of the API on the service
+     * side. Returned version should be always > 0.
+     */
+    int getApiVersion() = 1;
+}
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureApiService.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureApiService.aidl
new file mode 100644
index 0000000..2710467
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureApiService.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+import androidx.health.services.client.impl.IMeasureCallback;
+import androidx.health.services.client.impl.internal.IStatusCallback;
+import androidx.health.services.client.impl.request.CapabilitiesRequest;
+import androidx.health.services.client.impl.request.MeasureRegistrationRequest;
+import androidx.health.services.client.impl.request.MeasureUnregistrationRequest;
+import androidx.health.services.client.impl.response.MeasureCapabilitiesResponse;
+
+/**
+ * Interface to make ipc calls for health services api.
+ *
+ * @hide
+ */
+interface IMeasureApiService {
+    /**
+     * API version of the AIDL interface. Should be incremented every time a new
+     * method is added.
+     */
+    const int API_VERSION = 1;
+
+    /**
+     * Method to register measure listener.
+     */
+    void registerCallback(in MeasureRegistrationRequest request, in IMeasureCallback callback, in IStatusCallback statusCallback) = 0;
+
+    /**
+     * Method to unregister measure listener.
+     */
+    void unregisterCallback(in MeasureUnregistrationRequest request, in IMeasureCallback callback, in IStatusCallback statusCallback) = 1;
+
+    /**
+     * Returns version of this AIDL interface.
+     *
+     * <p> Can be used by client to detect version of the API on the service
+     * side. Returned version should be always > 0.
+     */
+    int getApiVersion() = 2;
+
+   /** Method to get capabilities. */
+    MeasureCapabilitiesResponse getCapabilities(in CapabilitiesRequest request) = 3;
+}
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureCallback.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureCallback.aidl
new file mode 100644
index 0000000..ff7f983
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IMeasureCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+import androidx.health.services.client.impl.response.AvailabilityResponse;
+import androidx.health.services.client.impl.response.DataPointsResponse;
+
+/**
+ * Interface to get callback for measure api.
+ *
+ * @hide
+ */
+oneway interface IMeasureCallback {
+    void onAvailabilityChanged(in AvailabilityResponse response) = 0;
+
+    void onData(in DataPointsResponse response) = 1;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
new file mode 100644
index 0000000..d6be3f0
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringApiService.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl;
+
+import android.app.PendingIntent;
+import androidx.health.services.client.impl.IPassiveMonitoringCallback;
+import androidx.health.services.client.impl.internal.IStatusCallback;
+import androidx.health.services.client.impl.request.BackgroundRegistrationRequest;
+import androidx.health.services.client.impl.request.CapabilitiesRequest;
+import androidx.health.services.client.impl.request.EventRequest;
+import androidx.health.services.client.impl.response.PassiveMonitoringCapabilitiesResponse;
+
+/** @hide */
+interface IPassiveMonitoringApiService {
+    /**
+     * API version of the AIDL interface. Should be incremented every time a new
+     * method is added.
+     */
+    const int API_VERSION = 1;
+
+    /**
+     * Method to subscribe to an event with corresponding callback intent.
+     */
+    void registerEventCallback(in EventRequest request, in PendingIntent intent, in IStatusCallback statusCallback) = 0;
+
+    /**
+     * Method to subscribe to a set of data types with corresponding callback
+     * intent and an optional callback.
+     *
+     * <p>If a callback is present and is active, updates are provided via the callback. Otherwise,
+     * the provided PendingIntent gets the updates.
+     */
+    void registerDataCallback(in BackgroundRegistrationRequest request, in PendingIntent fallbackIntent, in IPassiveMonitoringCallback callback, in IStatusCallback statusCallback) = 1;
+
+    /**
+     * Method to subscribe to a set of data types with corresponding callback intent.
+     */
+    void unregisterDataCallback(in String packageName, in IStatusCallback statusCallback) = 3;
+
+    /**
+     * Method to subscribe to a set of data types with corresponding callback intent.
+     */
+    void unregisterEventCallback(in EventRequest request, in IStatusCallback statusCallback) = 4;
+
+    /**
+     * Returns version of this AIDL interface.
+     *
+     * <p> Can be used by client to detect version of the API on the service
+     * side. Returned version should be always > 0.
+     */
+    int getApiVersion() = 2;
+
+   /** Method to get capabilities. */
+   PassiveMonitoringCapabilitiesResponse getCapabilities(in CapabilitiesRequest request) = 5;
+}
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
similarity index 61%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
index 2aa2c9c..2eafb48 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/IPassiveMonitoringCallback.aidl
@@ -14,8 +14,16 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl;
 
+import androidx.health.services.client.impl.response.PassiveActivityStateResponse;
+
+/**
+ * Interface to get passive monitoring updates.
+ *
+ * @hide
+ */
+oneway interface IPassiveMonitoringCallback {
+    /** Called when a new passive activity state response is available. */
+    void onPassiveActivityState(in PassiveActivityStateResponse response) = 0;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
new file mode 100644
index 0000000..cfc56ca
--- /dev/null
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IExerciseInfoCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.internal;
+
+import androidx.health.services.client.impl.response.ExerciseInfoResponse;
+
+/**
+ * Callback for an operation that returns an ExerciseInfo on successful
+ * completion.
+ *
+ * @hide
+ */
+oneway interface IExerciseInfoCallback {
+    /**
+     * Method invoked when the operation is a success and exercise info is
+     * successfully obtained.
+     */
+    void onExerciseInfo(in ExerciseInfoResponse response) = 0;
+
+    /**
+     * Method invoked when the operation is a failure.
+     */
+    void onFailure(String message) = 1;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
similarity index 61%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
index 2aa2c9c..2a58b96 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/internal/IStatusCallback.aidl
@@ -14,8 +14,21 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.internal;
 
+/**
+ * Generic callback for an operation that returns a status on completion.
+ *
+ * @hide
+ */
+oneway interface IStatusCallback {
+    /**
+     * Method invoked when the operation is a success.
+     */
+    void onSuccess() = 0;
+
+    /**
+     * Method invoked when the operation is a failure.
+     */
+    void onFailure(String msg) = 1;
+}
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
index 2aa2c9c..3f7984c 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable AutoPauseAndResumeConfigRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.aidl
index 2aa2c9c..7493c72 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable BackgroundRegistrationRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.aidl
index 2aa2c9c..8264c63 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable BackgroundUnregistrationRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
index 2aa2c9c..b71b20a 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/CapabilitiesRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable CapabilitiesRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/EventRequest.aidl
similarity index 86%
rename from health/health-services-client/src/main/androidx/health/package-info.java
rename to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/EventRequest.aidl
index 2aa2c9c..1b59985 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/EventRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable EventRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
index 2aa2c9c..d8a9fbb 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/ExerciseGoalRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable ExerciseGoalRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
index 2aa2c9c..96acaec 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureRegistrationRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable MeasureRegistrationRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
index 2aa2c9c..fb2f060 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable MeasureUnregistrationRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
index 2aa2c9c..dd5e594 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/request/StartExerciseRequest.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.request;
 
+/** @hide */
+parcelable StartExerciseRequest;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseCapabilitiesResponse.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseCapabilitiesResponse.aidl
index 2aa2c9c..2641359 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseCapabilitiesResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable AutoExerciseCapabilitiesResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseDetectionStateResponse.aidl
similarity index 83%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseDetectionStateResponse.aidl
index 2aa2c9c..4b38fe1 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AutoExerciseDetectionStateResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable AutoExerciseDetectionStateResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
index 2aa2c9c..902c1ff 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/AvailabilityResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable AvailabilityResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/CapabilitiesResponse.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/CapabilitiesResponse.aidl
index 2aa2c9c..c48b0d0 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/CapabilitiesResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable CapabilitiesResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
index 2aa2c9c..31ab81c 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/DataPointsResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable DataPointsResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
index 2aa2c9c..8d429af 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseInfoResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable ExerciseInfoResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
index 2aa2c9c..55dd959 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable ExerciseLapSummaryResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
similarity index 85%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
index 2aa2c9c..d10ab6c 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/ExerciseUpdateResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable ExerciseUpdateResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/HeartRateAlertParamsResponse.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/HeartRateAlertParamsResponse.aidl
index 2aa2c9c..6464078 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/HeartRateAlertParamsResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable HeartRateAlertParamsResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
index 2aa2c9c..d9755f1 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable MeasureCapabilitiesResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveActivityStateResponse.aidl
similarity index 84%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveActivityStateResponse.aidl
index 2aa2c9c..5e3b130 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveActivityStateResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable PassiveActivityStateResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
similarity index 83%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
index 2aa2c9c..8a5ab5f 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/aidl/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.aidl
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.impl.response;
 
+/** @hide */
+parcelable PassiveMonitoringCapabilitiesResponse;
\ No newline at end of file
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseClient.kt
new file mode 100644
index 0000000..42a190e
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseClient.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import androidx.health.services.client.data.Capabilities
+import androidx.health.services.client.data.ExerciseConfig
+import androidx.health.services.client.data.ExerciseGoal
+import androidx.health.services.client.data.ExerciseInfo
+import androidx.health.services.client.data.ExerciseUpdate
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.Executor
+
+/** Client which provides a way to subscribe to the health data of a device during an exercise. */
+public interface ExerciseClient {
+    /**
+     * Starts a new exercise.
+     *
+     * Once started, WHS will begin collecting data associated with the exercise.
+     *
+     * Since WHS only allows a single active exercise at a time, this will terminate any active
+     * exercise currently in progress before starting the new one.
+     *
+     * @return a [ListenableFuture] that completes once the exercise has been started.
+     */
+    public fun startExercise(configuration: ExerciseConfig): ListenableFuture<Void>
+
+    /**
+     * Pauses the current exercise, if it is currently started.
+     *
+     * While the exercise is paused active time and cumulative metrics such as distance will not
+     * accumulate. Instantaneous measurements such as speed and heart rate will continue to update
+     * if requested in the [ExerciseConfig].
+     *
+     * If the exercise remains paused for a long period of time WHS will reduce or suspend access to
+     * sensors and GPS in order to conserve battery. Should this happen, access will automatically
+     * resume when the exercise is resumed.
+     *
+     * If the exercise is already paused then this method has no effect. If the exercise has ended
+     * then the returned future will fail.
+     *
+     * @return a [ListenableFuture] that completes once the exercise has been paused.
+     */
+    public fun pauseExercise(): ListenableFuture<Void>
+
+    /**
+     * Resumes the current exercise, if it is currently paused.
+     *
+     * Once resumed active time and cumulative metrics such as distance will resume accumulating.
+     *
+     * If the exercise has been started but is not currently paused this method has no effect. If
+     * the exercise has ended then the returned future will fail.
+     *
+     * @return a [ListenableFuture] that completes once the exercise has been resumed.
+     */
+    public fun resumeExercise(): ListenableFuture<Void>
+
+    /**
+     * Ends the current exercise, if it has been started. If the exercise has ended then this future
+     * will fail.
+     *
+     * No additional metrics will be produced for the exercise and any on device persisted data
+     * about the exercise will be deleted after the summary has been sent back.
+     */
+    public fun endExercise(): ListenableFuture<Void>
+
+    /**
+     * Ends the current lap, calls [ExerciseStateListener.onLapSummary] with data spanning the
+     * marked lap and starts a new lap. If the exercise supports laps this method can be called at
+     * any point after an exercise has been started and before it has been ended regardless of the
+     * exercise status.
+     *
+     * The metrics in the lap summary will start from either the start time of the exercise or the
+     * last time a lap was marked to the time this method is being called.
+     *
+     * If there's no exercise being tracked or if the exercise does not support laps then this
+     * future will fail.
+     */
+    public fun markLap(): ListenableFuture<Void>
+
+    /** Returns the [ExerciseInfo]. */
+    public val currentExerciseInfo: ListenableFuture<ExerciseInfo>
+
+    /**
+     * Sets the listener for the current [ExerciseUpdate].
+     *
+     * This listener won't be called until an exercise is in progress. It will also only receive
+     * updates from exercises tracked in this app.
+     *
+     * If an exercise is in progress, the [ExerciseUpdateListener] is immediately called with the
+     * associated [ExerciseUpdate], and subsequently whenever the state is updated or an event is
+     * triggered.
+     *
+     * Calls to the listener will be executed on the main application thread. To control where to
+     * execute the listener, see the overload taking an [Executor]. To remove the listener use
+     * [clearUpdateListener].
+     */
+    public fun setUpdateListener(listener: ExerciseUpdateListener): ListenableFuture<Void>
+
+    /**
+     * Calls to the listener will be executed using the specified [Executor]. To execute the
+     * listener on the main application thread use the overload without the [Executor].
+     */
+    public fun setUpdateListener(
+        listener: ExerciseUpdateListener,
+        executor: Executor
+    ): ListenableFuture<Void>
+
+    /**
+     * Clears the listener set using [setUpdateListener].
+     *
+     * If the listener wasn't set, the returned [ListenableFuture] will fail.
+     */
+    public fun clearUpdateListener(listener: ExerciseUpdateListener): ListenableFuture<Void>
+
+    /**
+     * Adds an [ExerciseGoal] for an active exercise.
+     *
+     * An [ExerciseGoal] is a one-time goal, such as achieving a target total step count.
+     *
+     * Goals apply to only active exercises owned by the client, and will be invalidated once the
+     * exercise is complete.
+     *
+     * @return a [ListenableFuture] that completes once the exercise goal has been added. This
+     * returned [ListenableFuture] fails if the exercise is not active.
+     */
+    public fun addGoalToActiveExercise(exerciseGoal: ExerciseGoal): ListenableFuture<Void>
+
+    /**
+     * Enables or disables the auto pause/resume for the current exercise.
+     *
+     * @param enabled a boolean to indicate if should be enabled or disabled
+     */
+    public fun overrideAutoPauseAndResumeForActiveExercise(enabled: Boolean): ListenableFuture<Void>
+
+    /** Returns the [Capabilities] of this client for the device. */
+    public val capabilities: ListenableFuture<Capabilities>
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseUpdateListener.kt b/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseUpdateListener.kt
new file mode 100644
index 0000000..d622d43
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/ExerciseUpdateListener.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import androidx.health.services.client.data.ExerciseLapSummary
+import androidx.health.services.client.data.ExerciseState
+import androidx.health.services.client.data.ExerciseUpdate
+
+/** Listener that is called when the state of the current exercise is updated. */
+// TODO(b/179756577): Add onExerciseEnd(ExerciseSummary) method.
+public interface ExerciseUpdateListener {
+    /** Called during an ACTIVE exercise or on any changes in [ExerciseState]. */
+    public fun onExerciseUpdate(update: ExerciseUpdate)
+
+    /** Called during an ACTIVE exercise once a lap has been marked. */
+    public fun onLapSummary(lapSummary: ExerciseLapSummary)
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/HealthServices.kt b/health/health-services-client/src/main/java/androidx/health/services/client/HealthServices.kt
new file mode 100644
index 0000000..8fba5b9
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/HealthServices.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import android.content.Context
+import androidx.health.services.client.impl.ServiceBackedHealthServicesClient
+
+/** Entry point for all Health Services APIs. */
+public object HealthServices {
+    /** Returns an instance of [HealthServicesClient]. */
+    @JvmStatic
+    public fun getClient(context: Context): HealthServicesClient {
+        return ServiceBackedHealthServicesClient(context)
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/HealthServicesClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/HealthServicesClient.kt
new file mode 100644
index 0000000..82c3d41
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/HealthServicesClient.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+/**
+ * Client which provides a way to subscribe to the health data of a device, in the background or in
+ * the foreground.
+ */
+public interface HealthServicesClient {
+    /** Returns a [ExerciseClient]. */
+    public val exerciseClient: ExerciseClient
+
+    /** Returns a [PassiveMonitoringClient]. */
+    public val passiveMonitoringClient: PassiveMonitoringClient
+
+    /** Returns a [MeasureClient]. */
+    public val measureClient: MeasureClient
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/MeasureCallback.kt b/health/health-services-client/src/main/java/androidx/health/services/client/MeasureCallback.kt
new file mode 100644
index 0000000..7706b42
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/MeasureCallback.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import androidx.health.services.client.data.Availability
+import androidx.health.services.client.data.DataPoint
+import androidx.health.services.client.data.DataType
+
+/** Callback for [MeasureClient.registerCallback]. */
+public interface MeasureCallback {
+    /** Called when the availability of a [DataType] changes. */
+    public fun onAvailabilityChanged(dataType: DataType, availability: Availability)
+
+    /** Called when new data is available. Data can be batched in a list of [DataPoint]. */
+    public fun onData(data: List<@JvmSuppressWildcards DataPoint>)
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/MeasureClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/MeasureClient.kt
new file mode 100644
index 0000000..782ae0d
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/MeasureClient.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import androidx.health.services.client.data.DataType
+import androidx.health.services.client.data.MeasureCapabilities
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.Executor
+
+/**
+ * Client which provides a way to make measurements of health data on a device.
+ *
+ * This is optimized for apps to register live callbacks on data which may be sampled at a faster
+ * rate; this is not meant to be used for long-lived subscriptions to data (for this, consider using
+ * [ExerciseClient] or [PassiveMonitoringClient] depending on your use case).
+ *
+ * Existing subscriptions made with the [PassiveMonitoringClient] are also expected to get the data
+ * generated by this client.
+ */
+public interface MeasureClient {
+    /**
+     * Registers the app for live measurement of the specified [DataType].
+     *
+     * The callback will be called on the main application thread. To move calls to an alternative
+     * thread use [registerCallback].
+     *
+     * Even if data is registered for live capture, it can still be sent out in batches depending on
+     * the application processor state.
+     *
+     * Registering a [DataType] for live measurement capture is expected to increase the sample rate
+     * on the associated sensor(s); this is typically used for one-off measurements. Do not use this
+     * method for background capture or workout tracking.
+     *
+     * The callback will continue to be called until the app is killed or [unregisterCallback] is
+     * called.
+     *
+     * If the same [callback] is already registered for the given [DataType], this operation is a
+     * no-op.
+     */
+    public fun registerCallback(
+        dataType: DataType,
+        callback: MeasureCallback
+    ): ListenableFuture<Void>
+
+    /** Same as [registerCallback], except the [callback] is called on the given [Executor]. */
+    public fun registerCallback(
+        dataType: DataType,
+        callback: MeasureCallback,
+        executor: Executor
+    ): ListenableFuture<Void>
+
+    /** Unregisters the given [MeasureCallback] for updates of the given [DataType]. */
+    public fun unregisterCallback(
+        dataType: DataType,
+        callback: MeasureCallback
+    ): ListenableFuture<Void>
+
+    /** Returns the [MeasureCapabilities] of this client for the device. */
+    public val capabilities: ListenableFuture<MeasureCapabilities>
+}
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringCallback.kt
similarity index 65%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringCallback.kt
index 2aa2c9c..2463188 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringCallback.kt
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client
 
+import androidx.health.services.client.data.PassiveActivityState
+
+/** A callback for receiving passive monitoring updates. */
+public interface PassiveMonitoringCallback {
+    /** Called when new state is available. */
+    public fun onPassiveActivityState(state: PassiveActivityState)
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringClient.kt
new file mode 100644
index 0000000..23793f7
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/PassiveMonitoringClient.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client
+
+import android.app.PendingIntent
+import androidx.health.services.client.data.DataType
+import androidx.health.services.client.data.PassiveMonitoringCapabilities
+import androidx.health.services.client.data.event.Event
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * Client which provides a means to passively monitor data without requiring an ongoing workout.
+ *
+ * The lifetimes of registrations made through this client are independent of the lifetime of the
+ * subscribing app. These registrations are therefore suitable for notifying of ongoing measurements
+ * or triggered events, regardless of whether or not the subscribing app is currently running, in
+ * the foreground or engaged in a workout.
+ */
+public interface PassiveMonitoringClient {
+    /**
+     * Subscribes for updates on a set of data types to be periodically delivered to the app.
+     *
+     * Data will be batched. Higher frequency updates are available through [ExerciseClient] or
+     * [MeasureClient].
+     *
+     * The provided [PendingIntent] will be invoked periodically with the collected data.
+     *
+     * Subscribing apps are responsible for ensuring they can receive the [callbackIntent] by e.g.
+     * declaring a suitable [android.content.BroadcastReceiver] in their app manifest.
+     *
+     * This registration is unique per subscribing app. Subsequent registrations will replace the
+     * previous registration, if one had been made.
+     */
+    public fun registerDataCallback(
+        dataTypes: Set<@JvmSuppressWildcards DataType>,
+        callbackIntent: PendingIntent
+    ): ListenableFuture<Void>
+
+    /**
+     * Subscribes an intent callback (the same way as [PassiveMonitoringClient.registerDataCallback]
+     * ) and a [PassiveMonitoringCallback] for updates on a set of data types periodically.
+     *
+     * The provided [callback] will take priority in receiving updates as long the app is alive and
+     * the callback can be successfully notified. Otherwise, updates will be delivered to the
+     * [callbackIntent].
+     *
+     * This registration is unique per subscribing app. Subsequent registrations will replace the
+     * previous registration, if one had been made.
+     */
+    public fun registerDataCallback(
+        dataTypes: Set<@JvmSuppressWildcards DataType>,
+        callbackIntent: PendingIntent,
+        callback: PassiveMonitoringCallback
+    ): ListenableFuture<Void>
+
+    /**
+     * Unregisters the subscription made by [PassiveMonitoringClient.registerDataCallback].
+     *
+     * The associated [PendingIntent] will be called one last time with any remaining buffered data.
+     */
+    public fun unregisterDataCallback(): ListenableFuture<Void>
+
+    /**
+     * Registers for notification of the [event] being triggered.
+     *
+     * The provided [PendingIntent] will be sent whenever [event] is triggered.
+     *
+     * Subscribing apps are responsible for ensuring they can receive the [callbackIntent] by e.g.
+     * declaring a suitable [android.content.BroadcastReceiver] in their app manifest.
+     *
+     * Registration of multiple events is possible except where there already exists an event that
+     * is equal, as per the definition of [Event.equals], in which case the existing registration
+     * for that event will be replaced.
+     */
+    public fun registerEventCallback(
+        event: Event,
+        callbackIntent: PendingIntent
+    ): ListenableFuture<Void>
+
+    /** Unregisters the subscription for the given [Event]. */
+    public fun unregisterEventCallback(event: Event): ListenableFuture<Void>
+
+    /** Returns the [PassiveMonitoringCapabilities] of this client for the device. */
+    public val capabilities: ListenableFuture<PassiveMonitoringCapabilities>
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/AchievedExerciseGoal.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/AchievedExerciseGoal.kt
new file mode 100644
index 0000000..6463d58
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/AchievedExerciseGoal.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** Defines an achieved [ExerciseGoal]. */
+public data class AchievedExerciseGoal(
+    /** [ExerciseGoal] that has been achieved. */
+    // TODO(b/181235444): do we need to deliver the DataPoint to the user again here, given
+    // that they will have already gotten it in the ExerciseState? And, what other data do we need
+    // to
+    // tag along an achieved ExerciseGoal?
+    val goal: ExerciseGoal,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(goal, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<AchievedExerciseGoal> =
+            object : Parcelable.Creator<AchievedExerciseGoal> {
+                override fun createFromParcel(source: Parcel): AchievedExerciseGoal? {
+                    val goal =
+                        source.readParcelable<ExerciseGoal>(ExerciseGoal::class.java.classLoader)
+                            ?: return null
+                    return AchievedExerciseGoal(goal)
+                }
+
+                override fun newArray(size: Int): Array<AchievedExerciseGoal?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/AutoExerciseConfig.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/AutoExerciseConfig.kt
new file mode 100644
index 0000000..710346f
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/AutoExerciseConfig.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.app.PendingIntent
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import java.util.Objects
+
+/** Configs for the automatic exercise detection. */
+public data class AutoExerciseConfig
+@JvmOverloads
+constructor(
+    /**
+     * Set of [ExerciseType] for WHS to detect from. If left empty, all possible types are used].
+     */
+    val exercisesToDetect: Set<ExerciseType> = emptySet(),
+    /**
+     * A [PendingIntent] that WHS will use to post state / data changes to the app if the app has no
+     * active [androidx.health.services.client.ExerciseUpdateListener] registered at the moment. The
+     * launchIntent will be fed with the updated exercise states collected by the automatic exercise
+     * detection for the app to consume as soon as it re-starts.
+     */
+    val launchIntent: PendingIntent? = null,
+
+    /** See [ExerciseConfig.exerciseParams]. */
+    val exerciseParams: Bundle = Bundle(),
+) : Parcelable {
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(exercisesToDetect.size)
+        dest.writeIntArray(exercisesToDetect.map { it.id }.toIntArray())
+        dest.writeParcelable(launchIntent, flags)
+        dest.writeBundle(exerciseParams)
+    }
+
+    // TODO(b/180612514): Bundle doesn't have equals, so we need to override the data class default.
+    override fun equals(other: Any?): Boolean {
+        if (other === this) {
+            return true
+        }
+        if (other is AutoExerciseConfig) {
+            return (
+                launchIntent == other.launchIntent &&
+                    BundlesUtil.equals(exerciseParams, other.exerciseParams) &&
+                    exercisesToDetect == other.exercisesToDetect
+                )
+        }
+        return false
+    }
+
+    // TODO(b/180612514): Bundle doesn't have hashCode, so we need to override the data class
+    // default.
+    override fun hashCode(): Int {
+        return Objects.hash(launchIntent, BundlesUtil.hashCode(exerciseParams), exercisesToDetect)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<AutoExerciseConfig> =
+            object : Parcelable.Creator<AutoExerciseConfig> {
+                override fun createFromParcel(source: Parcel): AutoExerciseConfig? {
+                    val exercisesIntArray = IntArray(source.readInt())
+                    source.readIntArray(exercisesIntArray)
+                    val launchIntent =
+                        source.readParcelable<PendingIntent>(PendingIntent::class.java.classLoader)
+                    val exerciseParams =
+                        source.readBundle(AutoExerciseConfig::class.java.classLoader) ?: return null
+
+                    return AutoExerciseConfig(
+                        exercisesIntArray.map { ExerciseType.fromId(it) }.toSet(),
+                        launchIntent,
+                        exerciseParams
+                    )
+                }
+
+                override fun newArray(size: Int): Array<AutoExerciseConfig?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/java/androidx/health/services/client/data/Availability.kt
similarity index 63%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/java/androidx/health/services/client/data/Availability.kt
index 2aa2c9c..71a56d8 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/Availability.kt
@@ -14,8 +14,16 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.data
 
+/** Availability of a [DataType]. */
+public enum class Availability(public val id: Int) {
+    UNKNOWN(0),
+    AVAILABLE(1),
+    ACQUIRING(2),
+    UNAVAILABLE(3);
+
+    public companion object {
+        @JvmStatic public fun fromId(id: Int): Availability? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/BundlesUtil.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/BundlesUtil.kt
new file mode 100644
index 0000000..f20e608
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/BundlesUtil.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Bundle
+import java.util.Objects
+
+/** Utility methods for working with Bundles. */
+internal object BundlesUtil {
+
+    /**
+     * Compares two Bundles recursively and returns `true` if they are equal.
+     *
+     * Equality in this case means that both bundles contain the same set of keys and their
+     * corresponding values are all equal (using the [Object.equals] method).
+     */
+    @JvmStatic
+    fun equals(a: Bundle?, b: Bundle?): Boolean {
+        if (a == b) {
+            return true
+        } else if (a == null || b == null) {
+            return false
+        } else if (a.size() != b.size()) {
+            return false
+        }
+        for (key in a.keySet()) {
+            val aValue = a[key]
+            val bValue = b[key]
+            if (aValue is Bundle && bValue is Bundle) {
+                if (!equals(aValue as Bundle?, bValue as Bundle?)) {
+                    return false
+                }
+            } else if (aValue == null) {
+                if (bValue != null || !b.containsKey(key)) {
+                    return false
+                }
+            } else if (!Objects.deepEquals(aValue, bValue)) {
+                return false
+            }
+        }
+        return true
+    }
+
+    /** Calculates a hashCode for a Bundle, examining all keys and values. */
+    @JvmStatic
+    fun hashCode(b: Bundle?): Int {
+        if (b == null) {
+            return 0
+        }
+        val keySet = b.keySet()
+        val hashCodes = IntArray(keySet.size * 2)
+        var i = 0
+        for (key in keySet) {
+            hashCodes[i++] = Objects.hashCode(key)
+            val value = b[key]
+            val valueHashCode: Int =
+                if (value is Bundle) {
+                    hashCode(value as Bundle?)
+                } else {
+                    Objects.hashCode(value)
+                }
+            hashCodes[i++] = valueHashCode
+        }
+        return hashCodes.contentHashCode()
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/Capabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/Capabilities.kt
new file mode 100644
index 0000000..3c19682
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/Capabilities.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseType.Companion.fromId
+
+/** A place holder class that represents the capabilities of WHS client on the device. */
+public data class Capabilities(
+    /** Mapping for each supported [ExerciseType] to its [ExerciseCapabilities] on this device. */
+    val exerciseTypeToExerciseCapabilities: Map<ExerciseType, ExerciseCapabilities>,
+) : Parcelable {
+
+    override fun describeContents(): Int {
+        return 0
+    }
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        writeExerciseTypeToExerciseCapabilities(dest, flags)
+    }
+
+    /** Set of supported [ExerciseType] s on this device. */
+    public val supportedExerciseTypes: Set<ExerciseType>
+        get() = exerciseTypeToExerciseCapabilities.keys
+
+    /**
+     * Returns the supported [ExerciseCapabilities] for a requested [ExerciseType].
+     *
+     * @throws IllegalArgumentException if the supplied [exercise] isn't supported
+     */
+    public fun getExerciseCapabilities(exercise: ExerciseType): ExerciseCapabilities {
+        return exerciseTypeToExerciseCapabilities[exercise]
+            ?: throw IllegalArgumentException(
+                String.format("%s exercise type is not supported", exercise)
+            )
+    }
+
+    /** Returns the set of [ExerciseType] s that support auto pause and resume on this device. */
+    public val autoPauseAndResumeEnabledExercises: Set<ExerciseType>
+        get() {
+            return exerciseTypeToExerciseCapabilities
+                .entries
+                .filter { it.value.supportsAutoPauseAndResume }
+                .map { it.key }
+                .toSet()
+        }
+
+    private fun writeExerciseTypeToExerciseCapabilities(dest: Parcel, flags: Int) {
+        dest.writeInt(exerciseTypeToExerciseCapabilities.size)
+        for ((key1, value) in exerciseTypeToExerciseCapabilities) {
+            val key = key1.id
+            dest.writeInt(key)
+            dest.writeParcelable(value, flags)
+        }
+    }
+
+    public companion object {
+
+        @JvmField
+        public val CREATOR: Parcelable.Creator<Capabilities> =
+            object : Parcelable.Creator<Capabilities> {
+                override fun createFromParcel(parcel: Parcel): Capabilities {
+                    val exerciseTypeToExerciseCapabilitiesFromParcel =
+                        getExerciseToExerciseCapabilityMap(parcel)
+                    return Capabilities(
+                        exerciseTypeToExerciseCapabilitiesFromParcel,
+                    )
+                }
+
+                override fun newArray(size: Int): Array<Capabilities?> = arrayOfNulls(size)
+            }
+
+        private fun readDataTypeSet(parcel: Parcel): Set<DataType> {
+            return parcel.createTypedArray(DataType.CREATOR)!!.toSet()
+        }
+
+        private fun writeDataTypeSet(out: Parcel, flags: Int, dataTypes: Set<DataType>) {
+            out.writeTypedArray(dataTypes.toTypedArray(), flags)
+        }
+
+        private fun getExerciseToExerciseCapabilityMap(
+            parcel: Parcel
+        ): Map<ExerciseType, ExerciseCapabilities> {
+            val map = HashMap<ExerciseType, ExerciseCapabilities>()
+            val mapSize = parcel.readInt()
+            for (i in 0 until mapSize) {
+                val key = fromId(parcel.readInt())
+                val value =
+                    parcel.readParcelable<Parcelable>(
+                        ExerciseCapabilities::class.java.classLoader
+                    ) as
+                        ExerciseCapabilities
+                map[key] = value
+            }
+            return map
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ComparisonType.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ComparisonType.kt
new file mode 100644
index 0000000..37e2288
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ComparisonType.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+/** For determining when a threshold has been met or exceeded in a [MetricCondition]. */
+public enum class ComparisonType(public val id: Int) {
+    // TODO(b/175064823): investigate adding EQUAL comparison type
+    GREATER_THAN(1),
+    GREATER_THAN_OR_EQUAL(2),
+    LESS_THAN(3),
+    LESS_THAN_OR_EQUAL(4);
+
+    public companion object {
+        @JvmStatic
+        public fun fromId(id: Int): ComparisonType? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoint.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoint.kt
new file mode 100644
index 0000000..5e52737
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoint.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import java.time.Duration
+import java.time.Instant
+import java.util.Objects
+
+/**
+ * A data point containing a [value] of type [dataType] from either a single point in time:
+ * [DataType.TimeType.SAMPLE], or a range in time: [DataType.TimeType.INTERVAL].
+ */
+@Suppress("DataClassPrivateConstructor")
+public data class DataPoint
+internal constructor(
+    val dataType: DataType,
+    val value: Value,
+
+    /**
+     * Elapsed start time of this [DataPoint].
+     *
+     * This represents the time at which this [DataPoint] originated, as a [Duration] since boot
+     * time. This is not exposed as a timestamp as the clock may drift between when the data is
+     * generated and when it is read out. Use [getStartInstant] to get the start time of this
+     * [DataPoint] as an [Instant].
+     */
+    val startDurationFromBoot: Duration,
+
+    /**
+     * Elapsed end time of this [DataPoint].
+     *
+     * This represents the time at which this [DataPoint] ends, as a [Duration] since boot time.
+     * This is not exposed as a timestamp as the clock may drift between when the data is generated
+     * and when it is read out. Use [getStartInstant] to get the start time of this [DataPoint] as
+     * an [Instant].
+     *
+     * For instantaneous data points, this is equal to [startDurationFromBoot].
+     */
+    val endDurationFromBoot: Duration = startDurationFromBoot,
+
+    /** Returns any provided metadata of this [DataPoint]. */
+    val metadata: Bundle = Bundle(),
+) : Parcelable {
+
+    init {
+        require(dataType.format == value.format) {
+            "DataType and Value format must match, but got ${dataType.format} and ${value.format}"
+        }
+    }
+
+    /**
+     * Returns the start [Instant] of this [DataPoint], knowing the time at which the system booted.
+     *
+     * @param bootInstant the [Instant] at which the system booted, this can be computed by
+     * `Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime()) `
+     */
+    public fun getStartInstant(bootInstant: Instant): Instant {
+        return bootInstant.plus(startDurationFromBoot)
+    }
+
+    /**
+     * Returns the end [Instant] of this [DataPoint], knowing the time at which the system booted.
+     *
+     * @param bootInstant the [Instant] at which the system booted, this can be computed by
+     * `Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())`
+     */
+    public fun getEndInstant(bootInstant: Instant): Instant {
+        return bootInstant.plus(endDurationFromBoot)
+    }
+
+    // TODO(b/180612514): Bundle doesn't have equals, so we need to override the data class default.
+    override fun equals(other: Any?): Boolean {
+        if (other === this) {
+            return true
+        }
+        if (other is DataPoint) {
+            return dataType == other.dataType &&
+                value == other.value &&
+                startDurationFromBoot == other.startDurationFromBoot &&
+                endDurationFromBoot == other.endDurationFromBoot &&
+                BundlesUtil.equals(metadata, other.metadata)
+        }
+        return false
+    }
+
+    // TODO(b/180612514): Bundle doesn't have hashCode, so we need to override the data class
+    // default.
+    override fun hashCode(): Int {
+        return Objects.hash(
+            dataType,
+            value,
+            startDurationFromBoot,
+            endDurationFromBoot,
+            BundlesUtil.hashCode(metadata)
+        )
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(dataType, flags)
+        dest.writeParcelable(value, flags)
+        dest.writeLong(startDurationFromBoot.toNanos())
+        dest.writeLong(endDurationFromBoot.toNanos())
+        dest.writeBundle(metadata)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<DataPoint> =
+            object : Parcelable.Creator<DataPoint> {
+                override fun createFromParcel(parcel: Parcel): DataPoint? {
+                    val dataType: DataType =
+                        parcel.readParcelable(DataType::class.java.classLoader) ?: return null
+                    val value: Value =
+                        parcel.readParcelable(Value::class.java.classLoader) ?: return null
+                    val startDurationFromBoot = Duration.ofNanos(parcel.readLong())
+                    val endDurationFromBoot = Duration.ofNanos(parcel.readLong())
+                    val metadata: Bundle? = parcel.readBundle(Bundle::class.java.classLoader)
+
+                    return when (dataType.timeType) {
+                        DataType.TimeType.INTERVAL ->
+                            createInterval(
+                                dataType,
+                                value,
+                                startDurationFromBoot,
+                                endDurationFromBoot,
+                                metadata ?: Bundle()
+                            )
+                        DataType.TimeType.SAMPLE -> {
+                            require(endDurationFromBoot.compareTo(startDurationFromBoot) == 0) {
+                                "DataType [$dataType] has SAMPLE type, but" +
+                                    " start[$startDurationFromBoot]/end[$endDurationFromBoot]" +
+                                    " duration from boot are not the same"
+                            }
+                            createSample(
+                                dataType,
+                                value,
+                                startDurationFromBoot,
+                                metadata ?: Bundle()
+                            )
+                        }
+                    }
+                }
+
+                override fun newArray(size: Int): Array<DataPoint?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        /**
+         * Returns a [DataPoint] representing the [value] of type [dataType] from
+         * [startDurationFromBoot] to [endDurationFromBoot].
+         *
+         * @throws IllegalArgumentException if the [DataType.TimeType] of the associated [DataType]
+         * is not [DataType.TimeType.INTERVAL], or if data is malformed
+         */
+        @JvmStatic
+        @JvmOverloads
+        public fun createInterval(
+            dataType: DataType,
+            value: Value,
+            startDurationFromBoot: Duration,
+            endDurationFromBoot: Duration,
+            metadata: Bundle = Bundle()
+        ): DataPoint {
+            require(DataType.TimeType.INTERVAL == dataType.timeType) {
+                "DataType $dataType must be of interval type to be created with an interval"
+            }
+
+            require(endDurationFromBoot >= startDurationFromBoot) {
+                "End timestamp mustn't be earlier than start timestamp, but got" +
+                    " $startDurationFromBoot and $endDurationFromBoot"
+            }
+
+            return DataPoint(dataType, value, startDurationFromBoot, endDurationFromBoot, metadata)
+        }
+
+        /**
+         * Returns a [DataPoint] representing the [value] of type [dataType] at [durationFromBoot].
+         *
+         * @throws IllegalArgumentException if the [DataType.TimeType] of the associated [DataType]
+         * is not [DataType.TimeType.SAMPLE], or if data is malformed
+         */
+        @JvmStatic
+        @JvmOverloads
+        public fun createSample(
+            dataType: DataType,
+            value: Value,
+            durationFromBoot: Duration,
+            metadata: Bundle = Bundle()
+        ): DataPoint {
+            require(DataType.TimeType.SAMPLE == dataType.timeType) {
+                "DataType $dataType must be of sample type to be created with a single timestamp"
+            }
+
+            return DataPoint(
+                dataType,
+                value,
+                durationFromBoot,
+                endDurationFromBoot = durationFromBoot,
+                metadata
+            )
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoints.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoints.kt
new file mode 100644
index 0000000..1168035
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataPoints.kt
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.content.Intent
+import androidx.annotation.Keep
+import java.time.Duration
+import java.util.ArrayList
+
+/** Helper class to facilitate working with [DataPoint] s. */
+// TODO(b/177504986): Remove all @Keep annotations once we figure out why this class gets stripped
+// away by proguard.
+@Keep
+public object DataPoints {
+    /**
+     * When using [DataType.LOCATION], the value is represented as `double[]`. The `double` value at
+     * this index represents the latitude.
+     */
+    public const val LOCATION_DATA_POINT_LATITUDE_INDEX: Int = 0
+
+    /**
+     * When using [DataType.LOCATION], the value is represented as `double[]`. The `double` value at
+     * this index represents the longitude.
+     */
+    public const val LOCATION_DATA_POINT_LONGITUDE_INDEX: Int = 1
+
+    /**
+     * When using [DataType.LOCATION], the value is represented as `double[]`. The `double` value at
+     * this index represents the altitude. This is an optional index and there is no guarantee that
+     * this index will be present.
+     */
+    public const val LOCATION_DATA_POINT_ALTITUDE_INDEX: Int = 2
+
+    /** Name of intent extra containing the data points set on pending intent. */
+    private const val EXTRA_DATA_POINTS: String = "whs.data_points_list"
+
+    /** Name of intent extra containing whether permissions are granted or not. */
+    private const val EXTRA_PERMISSIONS_GRANTED: String = "whs.data_points_has_permissions"
+
+    /** Retrieves the [DataPoint] s that are contained in the given [Intent], if any. */
+    @JvmStatic
+    @Keep
+    public fun getDataPoints(intent: Intent): List<DataPoint> =
+        intent.getParcelableArrayListExtra(EXTRA_DATA_POINTS) ?: listOf()
+
+    /** Puts the given [DataPoint] s in the given [Intent]. */
+    @JvmStatic
+    public fun putDataPoints(intent: Intent, dataPoints: Collection<DataPoint>) {
+        val copy = ArrayList(dataPoints)
+        intent.putParcelableArrayListExtra(EXTRA_DATA_POINTS, copy)
+    }
+
+    /** Sets whether [DataPoint] permissions are `granted` in the given [Intent]. */
+    @JvmStatic
+    public fun putPermissionsGranted(intent: Intent, granted: Boolean) {
+        intent.putExtra(EXTRA_PERMISSIONS_GRANTED, granted)
+    }
+
+    /** Retrieves whether permissions are granted in this [Intent]. */
+    @JvmStatic
+    public fun getPermissionsGranted(intent: Intent): Boolean =
+        intent.getBooleanExtra(EXTRA_PERMISSIONS_GRANTED, true)
+
+    /** Creates a new [DataPoint] of type [DataType.STEPS] with the given `steps`. */
+    @JvmStatic
+    public fun steps(
+        steps: Long,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.STEPS,
+            Value.ofLong(steps),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.STEPS_PER_MINUTE] with the given
+     * `stepsPerMinute`.
+     */
+    @JvmStatic
+    public fun stepsPerMinute(stepsPerMinute: Long, startDurationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(
+            DataType.STEPS_PER_MINUTE,
+            Value.ofLong(stepsPerMinute),
+            startDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.DISTANCE] with the given `meters`. */
+    @JvmStatic
+    public fun distance(
+        meters: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.DISTANCE,
+            Value.ofDouble(meters),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.ELEVATION] with the given `meters`. */
+    @JvmStatic
+    public fun elevation(
+        meters: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.ELEVATION,
+            Value.ofDouble(meters),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.ALTITUDE] with the given `meters`. */
+    @JvmStatic
+    public fun altitude(meters: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.ALTITUDE, Value.ofDouble(meters), durationFromBoot)
+
+    /** Creates a new [DataPoint] of type [DataType.FLOORS] with the given `floors`. */
+    @JvmStatic
+    public fun floors(
+        floors: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.FLOORS,
+            Value.ofDouble(floors),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.TOTAL_CALORIES] with the given `kcalories`. */
+    @JvmStatic
+    public fun calories(
+        kcalories: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.TOTAL_CALORIES,
+            Value.ofDouble(kcalories),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.SWIMMING_STROKES] with the given `kcalories`. */
+    @JvmStatic
+    public fun swimmingStrokes(
+        strokes: Long,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.SWIMMING_STROKES,
+            Value.ofLong(strokes),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.LOCATION] with the given `latitude` and
+     * `longitude`.
+     */
+    @JvmStatic
+    public fun location(
+        latitude: Double,
+        longitude: Double,
+        durationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createSample(
+            DataType.LOCATION,
+            Value.ofDoubleArray(latitude, longitude),
+            durationFromBoot
+        )
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.LOCATION] with the given `latitude`, `longitude`
+     * and `altitude`.
+     */
+    @JvmStatic
+    public fun location(
+        latitude: Double,
+        longitude: Double,
+        altitude: Double,
+        durationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createSample(
+            DataType.LOCATION,
+            Value.ofDoubleArray(latitude, longitude, altitude),
+            durationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.SPEED] with the given `metersPerSecond`. */
+    @JvmStatic
+    public fun speed(metersPerSecond: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.SPEED, Value.ofDouble(metersPerSecond), durationFromBoot)
+
+    /** Creates a new [DataPoint] of type [DataType.PACE] with the given `millisPerKm`. */
+    @JvmStatic
+    public fun pace(millisPerKm: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.PACE, Value.ofDouble(millisPerKm), durationFromBoot)
+
+    /** Creates a new [DataPoint] of type [DataType.HEART_RATE_BPM] with the given `bpm`. */
+    @JvmStatic
+    public fun heartRate(bpm: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.HEART_RATE_BPM, Value.ofDouble(bpm), durationFromBoot)
+
+    /** Creates a new [DataPoint] of type [DataType.SPO2] with the given `percent`. */
+    @JvmStatic
+    public fun spo2(percent: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.SPO2, Value.ofDouble(percent), durationFromBoot)
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.AGGREGATE_DISTANCE] with the given `distance`.
+     */
+    @JvmStatic
+    public fun aggregateDistance(
+        distance: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.AGGREGATE_DISTANCE,
+            Value.ofDouble(distance),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.AGGREGATE_STEP_COUNT] with the given `steps`. */
+    @JvmStatic
+    public fun aggregateSteps(
+        steps: Long,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.AGGREGATE_STEP_COUNT,
+            Value.ofLong(steps),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.AGGREGATE_CALORIES_EXPENDED] with the given
+     * `kcalories`.
+     */
+    @JvmStatic
+    public fun aggregateCalories(
+        kcalories: Double,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.AGGREGATE_CALORIES_EXPENDED,
+            Value.ofDouble(kcalories),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.AGGREGATE_SWIMMING_STROKE_COUNT] with the given
+     * `swimmingStrokes`.
+     */
+    @JvmStatic
+    public fun aggregateSwimmingStrokes(
+        swimmingStrokes: Long,
+        startDurationFromBoot: Duration,
+        endDurationFromBoot: Duration
+    ): DataPoint =
+        DataPoint.createInterval(
+            DataType.AGGREGATE_SWIMMING_STROKE_COUNT,
+            Value.ofLong(swimmingStrokes),
+            startDurationFromBoot,
+            endDurationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.AVERAGE_PACE] with the given `millisPerKm`. */
+    @JvmStatic
+    public fun averagePace(millisPerKm: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(DataType.AVERAGE_PACE, Value.ofDouble(millisPerKm), durationFromBoot)
+
+    /**
+     * Creates a new [DataPoint] of type [DataType.AVERAGE_SPEED] with the given `metersPerSecond`.
+     */
+    @JvmStatic
+    public fun averageSpeed(metersPerSecond: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(
+            DataType.AVERAGE_SPEED,
+            Value.ofDouble(metersPerSecond),
+            durationFromBoot
+        )
+
+    /** Creates a new [DataPoint] of type [DataType.MAX_SPEED] with the given `metersPerSecond`. */
+    @JvmStatic
+    public fun maxSpeed(metersPerSecond: Double, durationFromBoot: Duration): DataPoint =
+        DataPoint.createSample(
+            DataType.MAX_SPEED,
+            Value.ofDouble(metersPerSecond),
+            durationFromBoot
+        )
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/DataType.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataType.kt
new file mode 100644
index 0000000..d3a0ac6
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataType.kt
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * A data type is a representation of health data managed by Health Services.
+ *
+ * A [DataType] specifies the format of the values inside a [DataPoint]. WHS defines data types for
+ * instantaneous observations [TimeType.SAMPLE](e.g. heart rate) and data types for change between
+ * readings [TimeType.INTERVAL](e.g. distance).
+ *
+ * Note: the data type defines only the representation and format of the data, and not how it's
+ * being collected, the sensor being used, or the parameters of the collection.
+ */
+public data class DataType(
+    /** Returns the name of this [DataType], e.g. `"Steps"`. */
+    val name: String,
+    /** Returns the [TimeType] of this [DataType]. */
+    val timeType: TimeType,
+    /** Returns the expected format for a [Value] of this [DataType]. */
+    val format: Int,
+) : Parcelable {
+
+    /**
+     * Whether the `DataType` corresponds to a measurement spanning an interval, or a sample at a
+     * single point in time.
+     */
+    public enum class TimeType {
+        INTERVAL,
+        SAMPLE
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        with(dest) {
+            writeString(name)
+            writeString(timeType.name)
+            writeInt(format)
+        }
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<DataType> =
+            object : Parcelable.Creator<DataType> {
+                override fun createFromParcel(parcel: Parcel): DataType? {
+                    return DataType(
+                        parcel.readString() ?: return null,
+                        TimeType.valueOf(parcel.readString() ?: return null),
+                        parcel.readInt()
+                    )
+                }
+
+                override fun newArray(size: Int): Array<DataType?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        /** Current altitude expressed in meters in `double` format. */
+        @JvmField
+        public val ALTITUDE: DataType = DataType("Altitude", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** A distance delta between each reading expressed in meters in `double` format. */
+        @JvmField
+        public val DISTANCE: DataType = DataType("Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * A duration delta during an exercise over which the user was traveling down a decline,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val DECLINE_TIME: DataType =
+            DataType("Decline Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * A distance delta traveled over declining ground between each reading expressed in meters
+         * in `double` format.
+         */
+        @JvmField
+        public val DECLINE_DISTANCE: DataType =
+            DataType("Decline Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * A duration delta during an exercise over which the user was traveling across flat ground,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val FLAT_TIME: DataType = DataType("Flat Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * A distance delta traveled over flat ground between each reading expressed in meters in
+         * `double` format.
+         */
+        @JvmField
+        public val FLAT_DISTANCE: DataType =
+            DataType("Flat Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * A duration delta during an exercise over which the user was traveling up an incline,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val INCLINE_TIME: DataType =
+            DataType("Incline Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * A distance delta traveled over inclining ground between each reading expressed in meters
+         * in `double` format.
+         */
+        @JvmField
+        public val INCLINE_DISTANCE: DataType =
+            DataType("Incline Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** An elevation delta between each reading expressed in meters in `double` format. */
+        @JvmField
+        public val ELEVATION: DataType =
+            DataType("Elevation", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** Absolute elevation between each reading expressed in meters in `double` format. */
+        @JvmField
+        public val ABSOLUTE_ELEVATION: DataType =
+            DataType("Absolute Elevation", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** Number of floors climbed between each reading in `double` format */
+        @JvmField
+        public val FLOORS: DataType = DataType("Floors", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** Current heart rate, in beats per minute in `double` format. */
+        @JvmField
+        public val HEART_RATE_BPM: DataType =
+            DataType("HeartRate", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /**
+         * Current latitude, longitude and optionally, altitude in `double[]` format. Latitude at
+         * index [DataPoints.LOCATION_DATA_POINT_LATITUDE_INDEX], longitude at index
+         * [DataPoints.LOCATION_DATA_POINT_LONGITUDE_INDEX] and if available, altitude at index
+         * [DataPoints.LOCATION_DATA_POINT_ALTITUDE_INDEX]
+         */
+        @JvmField
+        public val LOCATION: DataType =
+            DataType("Location", TimeType.SAMPLE, Value.FORMAT_DOUBLE_ARRAY)
+
+        /** Current speed over time. In meters/second in `double` format. */
+        @JvmField
+        public val SPEED: DataType = DataType("Speed", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** Percentage of oxygen in the blood in `double` format. Valid range `0f` - `100f`. */
+        @JvmField public val SPO2: DataType = DataType("SpO2", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** Rate of oxygen consumption in `double` format. Valid range `0f` - `100f`. */
+        @JvmField public val VO2: DataType = DataType("VO2", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /**
+         * Maximum rate of oxygen consumption measured during incremental exercise in `double`
+         * format. Valid range `0f` - `100f`.
+         */
+        @JvmField
+        public val VO2_MAX: DataType = DataType("VO2 Max", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** Delta of steps between each reading in `long` format. */
+        @JvmField
+        public val STEPS: DataType = DataType("Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** Delta of walking steps between each reading in `long` format. */
+        @JvmField
+        public val WALKING_STEPS: DataType =
+            DataType("Walking Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** Delta of running steps between each reading in `long` format. */
+        @JvmField
+        public val RUNNING_STEPS: DataType =
+            DataType("Running Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** Current step rate in steps/minute in `long` format. */
+        @JvmField
+        public val STEPS_PER_MINUTE: DataType =
+            DataType("Step per minute", TimeType.SAMPLE, Value.FORMAT_LONG)
+
+        /** Delta of strokes between each reading of swimming strokes in `long` format. */
+        @JvmField
+        public val SWIMMING_STROKES: DataType =
+            DataType("Swimming Strokes", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * Delta of total calories (including basal rate and activity) between each reading in
+         * `double` format.
+         */
+        @JvmField
+        public val TOTAL_CALORIES: DataType =
+            DataType("Calories", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** Current pace. In millisec/km in `double` format. */
+        @JvmField public val PACE: DataType = DataType("Pace", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The aggregate distance over a period of time expressed in meters in `double` format. */
+        @JvmField
+        public val AGGREGATE_DISTANCE: DataType =
+            DataType("Aggregate Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * The aggregate flat distance over a period of time expressed in meters in `double` format.
+         */
+        @JvmField
+        public val AGGREGATE_FLAT_DISTANCE: DataType =
+            DataType("Aggregate Flat Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * The aggregate incline distance over a period of time expressed in meters in `double`
+         * format.
+         */
+        @JvmField
+        public val AGGREGATE_INCLINE_DISTANCE: DataType =
+            DataType("Aggregate Incline Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * The aggregate incline distance over a period of time expressed in meters in `double`
+         * format.
+         */
+        @JvmField
+        public val AGGREGATE_DECLINE_DISTANCE: DataType =
+            DataType("Aggregate Decline Distance", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /**
+         * The aggregate duration for an exercise when the user was traveling on flat ground,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val AGGREGATE_FLAT_TIME: DataType =
+            DataType("Aggregate Flat Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * The aggregate duration for an exercise when the user was traveling up an incline,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val AGGREGATE_INCLINE_TIME: DataType =
+            DataType("Aggregate Incline Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * The aggregate duration for an exercise when the user was traveling down a decline,
+         * expressed in seconds in `long` format.
+         */
+        @JvmField
+        public val AGGREGATE_DECLINE_TIME: DataType =
+            DataType("Aggregate Decline Time", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /**
+         * The aggregate total calories (including basal rate and activity) expended over a period
+         * of time in `double` format.
+         */
+        @JvmField
+        public val AGGREGATE_CALORIES_EXPENDED: DataType =
+            DataType("Aggregate Calories", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** The aggregate step count over a period of time in `long` format. */
+        @JvmField
+        public val AGGREGATE_STEP_COUNT: DataType =
+            DataType("Aggregate Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** The aggregate walking step count over a period of time in `long` format. */
+        @JvmField
+        public val AGGREGATE_WALKING_STEP_COUNT: DataType =
+            DataType("Aggregate Walking Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** The aggregate running step count over a period of time in `long` format. */
+        @JvmField
+        public val AGGREGATE_RUNNING_STEP_COUNT: DataType =
+            DataType("Aggregate Running Steps", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** The aggregate swimming stroke count over a period of time in `long` format. */
+        @JvmField
+        public val AGGREGATE_SWIMMING_STROKE_COUNT: DataType =
+            DataType("Aggregate Swimming Strokes", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** The aggregate elevation over a period of time in meters in `double` format. */
+        @JvmField
+        public val AGGREGATE_ELEVATION: DataType =
+            DataType("Aggregate Elevation", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** The number of floors climbed over a period of time in `double` format */
+        @JvmField
+        public val AGGREGATE_FLOORS: DataType =
+            DataType("Aggregate Floors", TimeType.INTERVAL, Value.FORMAT_DOUBLE)
+
+        /** The average pace over a period of time in millisec/km in `double` format. */
+        @JvmField
+        public val AVERAGE_PACE: DataType =
+            DataType("Average Pace", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The average speed over a period of time in meters/second in `double` format. */
+        @JvmField
+        public val AVERAGE_SPEED: DataType =
+            DataType("Average Speed", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The average heart rate over a period of time in beats/minute in `double` format. */
+        @JvmField
+        public val AVERAGE_HEART_RATE_BPM: DataType =
+            DataType("Average Heart Rate BPM", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The maximum altitude over a period of time in meters in `double` format. */
+        @JvmField
+        public val MAX_ALTITUDE: DataType =
+            DataType("Max Altitude", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The minimum altitude over a period of time in meters in `double` format. */
+        @JvmField
+        public val MIN_ALTITUDE: DataType =
+            DataType("Min Altitude", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The maximum pace over a period of time in millisec/km in `double` format. */
+        @JvmField
+        public val MAX_PACE: DataType = DataType("Max Pace", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The maximum speed over a period of time in meters/second in `double` format. */
+        @JvmField
+        public val MAX_SPEED: DataType = DataType("Max Speed", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /** The maximum instantaneous heart rate in beats/minute in `double` format. */
+        @JvmField
+        public val MAX_HEART_RATE_BPM: DataType =
+            DataType("Max Heart Rate", TimeType.SAMPLE, Value.FORMAT_DOUBLE)
+
+        /**
+         * The duration during which the user was resting during an Exercise in seconds in `long`
+         * format.
+         */
+        @JvmField
+        public val RESTING_EXERCISE_DURATION: DataType =
+            DataType("Resting Exercise Duration", TimeType.SAMPLE, Value.FORMAT_LONG)
+
+        /** The duration of the time the Exercise was ACTIVE in seconds in `long` format. */
+        @JvmField
+        public val ACTIVE_EXERCISE_DURATION: DataType =
+            DataType("Active Exercise Duration", TimeType.SAMPLE, Value.FORMAT_LONG)
+
+        /** Count of swimming laps ins `long` format. */
+        @JvmField
+        public val SWIMMING_LAP_COUNT: DataType =
+            DataType("Swim Lap Count", TimeType.INTERVAL, Value.FORMAT_LONG)
+
+        /** The current rep count of the exercise in `long` format. */
+        @JvmField
+        public val REP_COUNT: DataType = DataType("Rep Count", TimeType.INTERVAL, Value.FORMAT_LONG)
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypeCondition.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypeCondition.kt
new file mode 100644
index 0000000..152c9df
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypeCondition.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** A condition which is considered met when a data type value passes a defined threshold. */
+public data class DataTypeCondition(
+    val dataType: DataType,
+    val threshold: Value,
+    val comparisonType: ComparisonType,
+) : Parcelable {
+    init {
+        require(dataType.format == threshold.format) {
+            "provided data type must have sample time type."
+        }
+    }
+
+    /** Checks whether or not the condition is satisfied by a given [DataPoint]. */
+    public fun isSatisfied(dataPoint: DataPoint): Boolean {
+        require(dataType == dataPoint.dataType) {
+            "attempted to evaluate data type condition with incorrect data type. Expected " +
+                "${dataType.name} but was ${dataPoint.dataType.name}"
+        }
+        return isThresholdSatisfied(dataPoint.value)
+    }
+
+    /** Checks whether or not the value of the condition is satisfied by a given [Value]. */
+    public fun isThresholdSatisfied(value: Value): Boolean {
+        val comparison = Value.compare(value, threshold)
+        return when (comparisonType) {
+            ComparisonType.LESS_THAN -> comparison < 0
+            ComparisonType.GREATER_THAN -> comparison > 0
+            ComparisonType.LESS_THAN_OR_EQUAL -> comparison <= 0
+            ComparisonType.GREATER_THAN_OR_EQUAL -> comparison >= 0
+        }
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(dataType, flags)
+        dest.writeParcelable(threshold, flags)
+        dest.writeInt(comparisonType.id)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<DataTypeCondition> =
+            object : Parcelable.Creator<DataTypeCondition> {
+                override fun createFromParcel(source: Parcel): DataTypeCondition? {
+                    val dataType =
+                        source.readParcelable<DataType>(DataType::class.java.classLoader)
+                            ?: return null
+                    val threshold =
+                        source.readParcelable<Value>(Value::class.java.classLoader) ?: return null
+                    val comparisonType = ComparisonType.fromId(source.readInt()) ?: return null
+                    return DataTypeCondition(dataType, threshold, comparisonType)
+                }
+
+                override fun newArray(size: Int): Array<DataTypeCondition?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypes.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypes.kt
new file mode 100644
index 0000000..b821de8
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/DataTypes.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+/** Helper class to facilitate working with [DataTypes] [DataType]. */
+public object DataTypes {
+    private val AGGREGATE_TYPE_TO_RAW_TYPE =
+        DataTypeBiMap(
+            DataType.AGGREGATE_DISTANCE to DataType.DISTANCE,
+            DataType.AGGREGATE_CALORIES_EXPENDED to DataType.TOTAL_CALORIES,
+            DataType.AGGREGATE_STEP_COUNT to DataType.STEPS,
+            DataType.AGGREGATE_ELEVATION to DataType.ELEVATION,
+            DataType.AGGREGATE_FLOORS to DataType.FLOORS,
+            DataType.AGGREGATE_SWIMMING_STROKE_COUNT to DataType.SWIMMING_STROKES
+        )
+
+    private val MAX_TYPE_TO_RAW_TYPE =
+        DataTypeBiMap(
+            DataType.MAX_HEART_RATE_BPM to DataType.HEART_RATE_BPM,
+            DataType.MAX_PACE to DataType.PACE,
+            DataType.MAX_SPEED to DataType.SPEED
+        )
+
+    private val AVERAGE_TYPE_TO_RAW_TYPE =
+        DataTypeBiMap(
+            DataType.AVERAGE_HEART_RATE_BPM to DataType.HEART_RATE_BPM,
+            DataType.AVERAGE_PACE to DataType.PACE,
+            DataType.AVERAGE_SPEED to DataType.SPEED
+        )
+
+    /** Check if a [DataType] represents aggregate value of a collection of non-aggregate data. */
+    @JvmStatic
+    public fun isAggregateDataType(dataType: DataType): Boolean =
+        AGGREGATE_TYPE_TO_RAW_TYPE.map.containsKey(dataType)
+
+    /** Check if a [DataType] represents the maximum value of a collection of non-aggregate data. */
+    @JvmStatic
+    public fun isStatisticalMaxDataType(dataType: DataType): Boolean =
+        MAX_TYPE_TO_RAW_TYPE.map.containsKey(dataType)
+
+    /** Check if a [DataType] represents the average value of a collection of non-aggregate data. */
+    @JvmStatic
+    public fun isStatisticalAverageDataType(dataType: DataType): Boolean =
+        AVERAGE_TYPE_TO_RAW_TYPE.map.containsKey(dataType)
+
+    /**
+     * Check if a [DataType] represents raw data value, i.e., neither aggregate value nor
+     * statistical value.
+     */
+    @JvmStatic
+    public fun isRawType(dataType: DataType): Boolean =
+        !isAggregateDataType(dataType) &&
+            !isStatisticalMaxDataType(dataType) &&
+            !isStatisticalAverageDataType(dataType)
+
+    /** Get the aggregate [DataType] from a raw [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getAggregateTypeFromRawType(rawType: DataType): DataType? =
+        AGGREGATE_TYPE_TO_RAW_TYPE.inverse[rawType]
+
+    /** Get the raw [DataType] from an aggregate [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getRawTypeFromAggregateType(aggregateType: DataType): DataType? =
+        AGGREGATE_TYPE_TO_RAW_TYPE.map[aggregateType]
+
+    /** Get the max [DataType] from a raw [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getMaxTypeFromRawType(rawType: DataType): DataType? =
+        MAX_TYPE_TO_RAW_TYPE.inverse[rawType]
+
+    /** Get the raw [DataType] from a max [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getRawTypeFromMaxType(maxType: DataType): DataType? =
+        MAX_TYPE_TO_RAW_TYPE.map[maxType]
+
+    /** Get the average [DataType] from a raw [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getAverageTypeFromRawType(rawType: DataType): DataType? =
+        AVERAGE_TYPE_TO_RAW_TYPE.inverse[rawType]
+
+    /** Get the raw [DataType] from an average [DataType], or null if it doesn't exist. */
+    @JvmStatic
+    public fun getRawTypeFromAverageType(averageType: DataType): DataType? =
+        AVERAGE_TYPE_TO_RAW_TYPE.map[averageType]
+
+    /** Get the aggregate, average, and max [DataType] from a raw [DataType] if they exist. */
+    @JvmStatic
+    public fun getAggregatedDataTypesFromRawType(rawType: DataType): Set<DataType> {
+        val allDataTypes = HashSet<DataType>()
+
+        getAggregateTypeFromRawType(rawType)?.let { allDataTypes.add(it) }
+        getMaxTypeFromRawType(rawType)?.let { allDataTypes.add(it) }
+        getAverageTypeFromRawType(rawType)?.let { allDataTypes.add(it) }
+
+        return allDataTypes
+    }
+
+    private class DataTypeBiMap(vararg pairs: Pair<DataType, DataType>) {
+        val map = mapOf(*pairs)
+        val inverse = pairs.map { it.second to it.first }.toMap()
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt
new file mode 100644
index 0000000..6564f06
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseCapabilities.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** Provides exercise specific capabilities data. */
+public data class ExerciseCapabilities(
+    val supportedDataTypes: Set<DataType>,
+    val supportedGoals: Map<DataType, Set<ComparisonType>>,
+    val supportedMilestones: Map<DataType, Set<ComparisonType>>,
+    val supportsAutoPauseAndResume: Boolean,
+    val supportsLaps: Boolean,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(supportedDataTypes.size)
+        dest.writeTypedArray(supportedDataTypes.toTypedArray(), flags)
+
+        writeSupportedDataTypes(supportedGoals, dest, flags)
+        writeSupportedDataTypes(supportedMilestones, dest, flags)
+
+        dest.writeInt(if (supportsAutoPauseAndResume) 1 else 0)
+        dest.writeInt(if (supportsLaps) 1 else 0)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseCapabilities> =
+            object : Parcelable.Creator<ExerciseCapabilities> {
+                override fun createFromParcel(source: Parcel): ExerciseCapabilities? {
+                    val supportedDataTypesArray = Array<DataType?>(source.readInt()) { null }
+                    source.readTypedArray(supportedDataTypesArray, DataType.CREATOR)
+
+                    val supportedGoals = readSupportedDataTypes(source) ?: return null
+                    val supportedMilestones = readSupportedDataTypes(source) ?: return null
+                    val supportsAutoPauseAndResume = source.readInt() == 1
+                    val supportsLaps = source.readInt() == 1
+
+                    return ExerciseCapabilities(
+                        supportedDataTypesArray.filterNotNull().toSet(),
+                        supportedGoals,
+                        supportedMilestones,
+                        supportsAutoPauseAndResume,
+                        supportsLaps
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseCapabilities?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        private fun writeSupportedDataTypes(
+            supportedDataTypes: Map<DataType, Set<ComparisonType>>,
+            dest: Parcel,
+            flags: Int
+        ) {
+            dest.writeInt(supportedDataTypes.size)
+            for ((dataType, comparisonTypeSet) in supportedDataTypes) {
+                dest.writeParcelable(dataType, flags)
+                dest.writeInt(comparisonTypeSet.size)
+                dest.writeIntArray(comparisonTypeSet.map { it.id }.toIntArray())
+            }
+        }
+
+        private fun readSupportedDataTypes(source: Parcel): Map<DataType, Set<ComparisonType>>? {
+            val supportedDataTypes = HashMap<DataType, Set<ComparisonType>>()
+
+            val numSupportedDataTypes = source.readInt()
+            repeat(numSupportedDataTypes) {
+                val dataType: DataType =
+                    source.readParcelable(DataType::class.java.classLoader) ?: return null
+
+                val comparisonTypeIntArray = IntArray(source.readInt())
+                source.readIntArray(comparisonTypeIntArray)
+                val comparisonTypeSet =
+                    comparisonTypeIntArray.map { ComparisonType.fromId(it) }.filterNotNull().toSet()
+
+                supportedDataTypes[dataType] = comparisonTypeSet
+            }
+
+            return supportedDataTypes
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseConfig.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseConfig.kt
new file mode 100644
index 0000000..9531eea
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseConfig.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import java.util.Objects
+
+/** Defines configuration for an exercise tracked using WHS. */
+@Suppress("DataClassPrivateConstructor")
+public data class ExerciseConfig
+protected constructor(
+    /**
+     * [ExerciseType] the user is performing for this exercise.
+     *
+     * This information can be used to tune sensors, e.g. the calories estimate can take the MET
+     * value into account.
+     */
+    val exerciseType: ExerciseType,
+    val dataTypes: Set<DataType>,
+    val autoPauseAndResume: Boolean,
+    val exerciseGoals: List<ExerciseGoal>,
+    val exerciseParams: Bundle,
+) : Parcelable {
+    init {
+        require(dataTypes.isNotEmpty()) { "Must specify the desired data types." }
+        require(exerciseType != ExerciseType.UNKNOWN) { "Must specify a valid exercise type." }
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(exerciseType.id)
+        dest.writeInt(dataTypes.size)
+        dest.writeTypedArray(dataTypes.toTypedArray(), flags)
+        dest.writeInt(if (autoPauseAndResume) 1 else 0)
+        dest.writeInt(exerciseGoals.size)
+        dest.writeTypedArray(exerciseGoals.toTypedArray(), flags)
+        dest.writeBundle(exerciseParams)
+    }
+
+    /** Builder for [ExerciseConfig] instances. */
+    public class Builder {
+        private var exerciseType: ExerciseType? = null
+        private var dataTypes: Set<DataType>? = null
+        private var autoPauseAndResume: Boolean = false
+        private var exerciseGoals: List<ExerciseGoal> = emptyList()
+        private var exerciseParams: Bundle = Bundle.EMPTY
+
+        /**
+         * Sets the active [ExerciseType] the user is performing for this exercise.
+         *
+         * Provide this parameter when tracking a workout to provide more accurate data. This
+         * information can be used to tune sensors, e.g. the calories estimate can take the MET
+         * value into account.
+         */
+        public fun setExerciseType(exerciseType: ExerciseType): Builder {
+            this.exerciseType = exerciseType
+            return this
+        }
+
+        /**
+         * Sets the requested [DataType] s that should be tracked during this exercise. If not
+         * explicitly called, a default set of [DataType] will be chosen based on the [ ].
+         */
+        public fun setDataTypes(dataTypes: Set<DataType>): Builder {
+            this.dataTypes = dataTypes.toSet()
+            return this
+        }
+
+        /**
+         * Sets whether auto pause and auto resume are enabled for this exercise. If not set,
+         * they're disabled by default.
+         */
+        public fun setAutoPauseAndResume(autoPauseAndResume: Boolean): Builder {
+            this.autoPauseAndResume = autoPauseAndResume
+            return this
+        }
+
+        /**
+         * Sets [ExerciseGoal] s specified for this exercise.
+         *
+         * This is useful to have goals specified before the start of an exercise.
+         */
+        public fun setExerciseGoals(exerciseGoals: List<ExerciseGoal>): Builder {
+            this.exerciseGoals = exerciseGoals.toList()
+            return this
+        }
+
+        /**
+         * Sets additional parameters for current exercise. Supported keys can be found in
+         * [ExerciseConfig].
+         */
+        // TODO(b/180612514) expose keys on a per-OEM basis.
+        public fun setExerciseParams(exerciseParams: Bundle): Builder {
+            this.exerciseParams = exerciseParams
+            return this
+        }
+
+        /** Returns the built `ExerciseConfig`. */
+        public fun build(): ExerciseConfig {
+            return ExerciseConfig(
+                checkNotNull(exerciseType) { "No exercise type specified" },
+                checkNotNull(dataTypes) { "No data types specified" },
+                autoPauseAndResume,
+                exerciseGoals,
+                exerciseParams
+            )
+        }
+    }
+
+    // TODO(b/180612514): Bundle doesn't have equals, so we need to override the data class default.
+    override fun equals(other: Any?): Boolean {
+        if (other === this) {
+            return true
+        }
+        if (other is ExerciseConfig) {
+            return exerciseType == other.exerciseType &&
+                dataTypes == other.dataTypes &&
+                autoPauseAndResume == other.autoPauseAndResume &&
+                exerciseGoals == other.exerciseGoals &&
+                BundlesUtil.equals(exerciseParams, other.exerciseParams)
+        }
+        return false
+    }
+
+    // TODO(b/180612514): Bundle doesn't have hashCode, so we need to override the data class
+    // default.
+    override fun hashCode(): Int {
+        return Objects.hash(
+            exerciseType,
+            dataTypes,
+            autoPauseAndResume,
+            exerciseGoals,
+            BundlesUtil.hashCode(exerciseParams)
+        )
+    }
+
+    public companion object {
+        @JvmStatic public fun builder(): Builder = Builder()
+
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseConfig> =
+            object : Parcelable.Creator<ExerciseConfig> {
+                override fun createFromParcel(source: Parcel): ExerciseConfig? {
+                    val exerciseType = ExerciseType.fromId(source.readInt())
+
+                    val dataTypesArray = Array<DataType?>(source.readInt()) { null }
+                    source.readTypedArray(dataTypesArray, DataType.CREATOR)
+
+                    val autoPauseAndResume = source.readInt() == 1
+
+                    val exerciseGoals = Array<ExerciseGoal?>(source.readInt()) { null }
+                    source.readTypedArray(exerciseGoals, ExerciseGoal.CREATOR)
+
+                    val exerciseParams =
+                        source.readBundle(ExerciseConfig::class.java.classLoader) ?: Bundle()
+
+                    return ExerciseConfig(
+                        exerciseType,
+                        dataTypesArray.filterNotNull().toSet(),
+                        autoPauseAndResume,
+                        exerciseGoals.filterNotNull().toList(),
+                        exerciseParams
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseConfig?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoal.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoal.kt
new file mode 100644
index 0000000..39c2ab1
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoal.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+import java.util.Objects
+
+// TODO(yeabkal): as we support more types of goals, we may want to rename the class.
+/** Defines a goal for an exercise. */
+@Suppress("DataClassPrivateConstructor")
+public data class ExerciseGoal
+protected constructor(
+    val exerciseGoalType: ExerciseGoalType,
+    val dataTypeCondition: DataTypeCondition,
+    // TODO(yeabkal): shall we rename to "getMilestonePeriod"? Currently "getPeriod" is used to be
+    // flexible in case we support other kinds of goals. Recheck when design is fully locked.
+    val period: Value? = null,
+) : Parcelable {
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(exerciseGoalType.id)
+        dest.writeParcelable(dataTypeCondition, flags)
+        dest.writeParcelable(period, flags)
+    }
+
+    // TODO(yeabkal): try to unify equality logic across goal types.
+    // TODO(b/186899729): We need a better way to match on achieved goals.
+    override fun equals(other: Any?): Boolean {
+        if (other === this) {
+            return true
+        }
+        if (other !is ExerciseGoal) {
+            return false
+        }
+
+        if (this.exerciseGoalType != other.exerciseGoalType) {
+            return false
+        }
+
+        return when (exerciseGoalType) {
+            ExerciseGoalType.ONE_TIME_GOAL -> dataTypeCondition == other.dataTypeCondition
+            // The threshold of a milestone is not included in the equality calculation to let apps
+            // easily map back an achieved milestone to the milestone they requested for tracking.
+            ExerciseGoalType.MILESTONE ->
+                dataTypeCondition.dataType == other.dataTypeCondition.dataType &&
+                    dataTypeCondition.comparisonType == other.dataTypeCondition.comparisonType &&
+                    period == other.period
+        }
+    }
+
+    override fun hashCode(): Int {
+        return if (exerciseGoalType == ExerciseGoalType.ONE_TIME_GOAL) {
+            Objects.hash(exerciseGoalType, dataTypeCondition)
+        } else {
+            Objects.hash(
+                exerciseGoalType,
+                dataTypeCondition.dataType,
+                dataTypeCondition.comparisonType,
+                period
+            )
+        }
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseGoal> =
+            object : Parcelable.Creator<ExerciseGoal> {
+                override fun createFromParcel(source: Parcel): ExerciseGoal? {
+                    val exerciseGoalType = ExerciseGoalType.fromId(source.readInt()) ?: return null
+                    val dataTypeCondition: DataTypeCondition =
+                        source.readParcelable(DataTypeCondition::class.java.classLoader)
+                            ?: return null
+                    val period: Value? = source.readParcelable(Value::class.java.classLoader)
+
+                    return ExerciseGoal(exerciseGoalType, dataTypeCondition, period)
+                }
+
+                override fun newArray(size: Int): Array<ExerciseGoal?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        /**
+         * Creates an [ExerciseGoal] that is achieved once when the given [DataTypeCondition] is
+         * satisfied.
+         */
+        @JvmStatic
+        public fun createOneTimeGoal(condition: DataTypeCondition): ExerciseGoal {
+            return ExerciseGoal(ExerciseGoalType.ONE_TIME_GOAL, condition)
+        }
+
+        /**
+         * Creates an [ExerciseGoal] that is achieved multiple times with its threshold being
+         * updated by a `period` value each time it is achieved. For instance, a milestone could be
+         * one for every 2km. This goal will there be triggered at distances = 2km, 4km, 6km, ...
+         */
+        @JvmStatic
+        public fun createMilestone(condition: DataTypeCondition, period: Value): ExerciseGoal {
+            require(period.format == condition.threshold.format) {
+                "The condition's threshold and the period should have the same types of values."
+            }
+            return ExerciseGoal(ExerciseGoalType.MILESTONE, condition, period)
+        }
+
+        /** Creates a new goal that is the same as a given goal but with a new threshold value. */
+        @JvmStatic
+        public fun createMilestoneGoalWithUpdatedThreshold(
+            goal: ExerciseGoal,
+            newThreshold: Value
+        ): ExerciseGoal {
+            require(ExerciseGoalType.MILESTONE == goal.exerciseGoalType) {
+                "The goal to update should be of MILESTONE type."
+            }
+            require(goal.period != null) { "The milestone goal's period should not be null." }
+            val (dataType, oldThreshold, comparisonType) = goal.dataTypeCondition
+            require(oldThreshold.format == newThreshold.format) {
+                "The old and new thresholds should have the same types of values."
+            }
+            return ExerciseGoal(
+                ExerciseGoalType.MILESTONE,
+                DataTypeCondition(dataType, newThreshold, comparisonType),
+                goal.period
+            )
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoalType.kt
similarity index 65%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoalType.kt
index 2aa2c9c..0790057 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseGoalType.kt
@@ -14,8 +14,15 @@
  * limitations under the License.
  */
 
-/**
- * Insert package level documentation here
- */
-package androidx.health.services.client;
+package androidx.health.services.client.data
 
+/** Exercise goal types. */
+public enum class ExerciseGoalType(public val id: Int) {
+    ONE_TIME_GOAL(1),
+    MILESTONE(2);
+
+    public companion object {
+        @JvmStatic
+        public fun fromId(id: Int): ExerciseGoalType? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseInfo.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseInfo.kt
new file mode 100644
index 0000000..7c43643
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseInfo.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** High-level info about the exercise. */
+public data class ExerciseInfo(
+    /** Returns the [ExerciseTrackedStatus]. */
+    val exerciseTrackedStatus: ExerciseTrackedStatus,
+
+    /**
+     * Returns the [ExerciseType] of the active exercise, or [ExerciseType.UNKNOWN] if there is no
+     * active exercise.
+     */
+    val exerciseType: ExerciseType,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(exerciseTrackedStatus.id)
+        dest.writeInt(exerciseType.id)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseInfo> =
+            object : Parcelable.Creator<ExerciseInfo> {
+                override fun createFromParcel(source: Parcel): ExerciseInfo? {
+                    return ExerciseInfo(
+                        ExerciseTrackedStatus.fromId(source.readInt()) ?: return null,
+                        ExerciseType.fromId(source.readInt())
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseInfo?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseLapSummary.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseLapSummary.kt
new file mode 100644
index 0000000..cd17ab1
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseLapSummary.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+import java.time.Duration
+import java.time.Instant
+
+/** Describes a completed exercise lap. */
+public data class ExerciseLapSummary(
+    /** Returns the lap count of this summary. Lap count starts at 1 for the first lap. */
+    val lapCount: Int,
+
+    /** Returns the time at which the lap has started. */
+    val startTime: Instant,
+
+    /** Returns the time at which the lap has ended. */
+    val endTime: Instant,
+
+    /**
+     * Returns the total elapsed time for which the exercise has been active during this lap, i.e.
+     * started but not paused.
+     */
+    val activeDuration: Duration,
+
+    /**
+     * Returns the [DataPoint] s for each metric keyed by [DataType] tracked between [startTime] and
+     * [endTime] i.e. during the duration of this lap. This will only contain aggregated [DataType]
+     * s calculated over the duration of the lap.
+     */
+    val lapMetrics: Map<DataType, DataPoint>,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(lapCount)
+        dest.writeLong(startTime.toEpochMilli())
+        dest.writeLong(endTime.toEpochMilli())
+        dest.writeLong(activeDuration.toMillis())
+
+        dest.writeInt(lapMetrics.size)
+        for ((dataType, dataPoint) in lapMetrics) {
+            dest.writeParcelable(dataType, flags)
+            dest.writeParcelable(dataPoint, flags)
+        }
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseLapSummary> =
+            object : Parcelable.Creator<ExerciseLapSummary> {
+                override fun createFromParcel(source: Parcel): ExerciseLapSummary? {
+                    val lapCount = source.readInt()
+                    val startTime = Instant.ofEpochMilli(source.readLong())
+                    val endTime = Instant.ofEpochMilli(source.readLong())
+                    val activeDuration = Duration.ofMillis(source.readLong())
+
+                    val lapMetrics = HashMap<DataType, DataPoint>()
+                    val numMetrics = source.readInt()
+                    repeat(numMetrics) {
+                        val dataType: DataType =
+                            source.readParcelable(DataType::class.java.classLoader) ?: return null
+                        lapMetrics[dataType] =
+                            source.readParcelable(DataPoint::class.java.classLoader) ?: return null
+                    }
+
+                    return ExerciseLapSummary(
+                        lapCount,
+                        startTime,
+                        endTime,
+                        activeDuration,
+                        lapMetrics
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseLapSummary?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseState.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseState.kt
new file mode 100644
index 0000000..964e271
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseState.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+/** Enumerates the state of an exercise. */
+public enum class ExerciseState(public val id: Int) {
+    /**
+     * The exercise is actively being started, but we don't yet have sensor stability or GPS fix.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_STARTING(1),
+
+    /**
+     * The exercise is actively in-progress.
+     *
+     * Used in both of the manually started exercise and the automatic exercise detection. It's also
+     * the state when the automatic exercise detection has detected an exercise and the exercise is
+     * actively in-progress.
+     */
+    ACTIVE(2),
+
+    /**
+     * The session is being paused by the user. Sensors are actively being flushed.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_PAUSING(3),
+
+    /**
+     * The session has been paused by the user. Sensors have completed flushing.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_PAUSED(4),
+
+    /**
+     * The session is being paused by auto-pause. Sensors are actively being flushed.
+     *
+     * Used only in the manually started exercise.
+     */
+    AUTO_PAUSING(5),
+
+    /**
+     * The session has been automatically paused. Sensors have completed flushing.
+     *
+     * Used only in the manually started exercise.
+     */
+    AUTO_PAUSED(6),
+
+    /**
+     * The session is being resumed by the user.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_RESUMING(7),
+
+    /**
+     * The session is being automatically resumed.
+     *
+     * Used only in the manually started exercise.
+     */
+    AUTO_RESUMING(8),
+
+    /**
+     * The exercise is being ended by the user. Sensors are actively being flushed.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_ENDING(9),
+
+    /**
+     * The exercise has been ended by the user. No new metrics will be exported and a final summary
+     * should be provided to the client.
+     *
+     * Used only in the manually started exercise.
+     */
+    USER_ENDED(10),
+
+    /**
+     * The exercise is being automatically ended due to a lack of exercise updates being received by
+     * the user. Sensors are actively being flushed.
+     *
+     * Used only in the manually started exercise.
+     */
+    AUTO_ENDING(11),
+
+    /**
+     * The exercise has been automatically ended due to a lack of exercise updates being received by
+     * the user. No new metrics will be exported and a final summary should be provided to the
+     * client.
+     *
+     * Used only in the manually started exercise.
+     */
+    AUTO_ENDED(12),
+
+    /**
+     * The exercise is being ended because it has been superseded by a new exercise being started by
+     * another client. Sensors are actively being flushed.
+     *
+     * Used in both of the manually started exercise and the automatic exercise detection.
+     */
+    TERMINATING(13),
+
+    /**
+     * The exercise has been ended because it was superseded by a new exercise being started by
+     * another client. No new metrics will be exported and a final summary should be provided to the
+     * client.
+     *
+     * Used in both of the manually started exercise and the automatic exercise detection.
+     */
+    TERMINATED(14);
+
+    /**
+     * Returns true if this [ExerciseState] corresponds to one of the paused states and false
+     * otherwise. This method returns false if the exercise has ended, to check whether it has ended
+     * call [isEnded].
+     */
+    public val isPaused: Boolean
+        get() = PAUSED_STATES.contains(this)
+
+    /**
+     * Returns true if this [ExerciseState] corresponds to one of the resuming states and false
+     * otherwise. This method returns false if the exercise has ended, to check whether it has ended
+     * call [isEnded].
+     */
+    public val isResuming: Boolean
+        get() = RESUMING_STATES.contains(this)
+
+    /**
+     * Returns true if this [ExerciseState] corresponds to one of the ended states and false
+     * otherwise. This method returns false if the exercise has been paused, to check whether it is
+     * currently paused call [isPaused].
+     */
+    public val isEnded: Boolean
+        get() = ENDED_STATES.contains(this)
+
+    public companion object {
+        private val RESUMING_STATES = setOf(USER_RESUMING, AUTO_RESUMING)
+        private val PAUSED_STATES = setOf(USER_PAUSED, AUTO_PAUSED)
+        private val ENDED_STATES = setOf(USER_ENDED, AUTO_ENDED, TERMINATED)
+
+        @JvmStatic public fun fromId(id: Int): ExerciseState? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTrackedStatus.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTrackedStatus.kt
new file mode 100644
index 0000000..2a1279b
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTrackedStatus.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+/** Status representing if an exercise is being tracked and which app owns the exercise. */
+public enum class ExerciseTrackedStatus(public val id: Int) {
+    OTHER_APP_IN_PROGRESS(1),
+    OWNED_EXERCISE_IN_PROGRESS(2),
+    NO_EXERCISE_IN_PROGRESS(3);
+
+    public companion object {
+        @JvmStatic
+        public fun fromId(id: Int): ExerciseTrackedStatus? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseType.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseType.kt
new file mode 100644
index 0000000..d385c67
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseType.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+// TODO(b/185276729): Keep track of values separately to maintain alphabetical order
+// once values are locked in
+/** Exercise type used to configure sensors and algorithms. */
+public enum class ExerciseType(
+    /** Returns a unique identifier of for the [ExerciseType], as an `int`. */
+    public val id: Int
+) {
+    /** The current exercise type of the user is unknown or not set. */
+    UNKNOWN(0),
+    BACK_EXTENSION(1),
+    BADMINTON(2),
+    BARBELL_SHOULDER_PRESS(3),
+    BASEBALL(4),
+    BASKETBALL(5),
+    BENCH_PRESS(6),
+    BENCH_SIT_UP(7),
+    BIKING(8),
+    BIKING_STATIONARY(9),
+    BOOT_CAMP(10),
+    BOXING(11),
+    BURPEE(12),
+
+    /** (E.g., push ups, sit ups, pull-ups, jumping jacks). */
+    CALISTHENICS(13),
+    CRICKET(14),
+    CRUNCH(15),
+    DANCING(16),
+    DEADLIFT(17),
+    DUMBBELL_CURL_RIGHT_ARM(18),
+    DUMBBELL_CURL_LEFT_ARM(19),
+    DUMBBELL_FRONT_RAISE(20),
+    DUMBBELL_LATERAL_RAISE(21),
+    DUMBBELL_TRICEPS_EXTENSION_LEFT_ARM(22),
+    DUMBBELL_TRICEPS_EXTENSION_RIGHT_ARM(23),
+    DUMBBELL_TRICEPS_EXTENSION_TWO_ARM(24),
+    ELLIPTICAL(25),
+    EXERCISE_CLASS(26),
+    FENCING(27),
+    FRISBEE_DISC(28),
+    FOOTBALL_AMERICAN(29),
+    FOOTBALL_AUSTRALIAN(30),
+    GOLF(31),
+    GUIDED_BREATHING(32),
+    GYNMASTICS(33),
+    HANDBALL(34),
+    HIGH_INTENSITY_INTERVAL_TRAINING(35),
+    HIKING(36),
+    ICE_HOCKEY(37),
+    ICE_SKATING(38),
+    JUMP_ROPE(39),
+    JUMPING_JACK(40),
+    LAT_PULL_DOWN(41),
+    LUNGE(42),
+    MARTIAL_ARTS(43),
+    MEDITATION(44),
+    PADDLING(45),
+    PARA_GLIDING(46),
+    PILATES(47),
+    PLANK(48),
+    RACQUETBALL(49),
+    ROCK_CLIMBING(50),
+    ROLLER_HOCKEY(51),
+    ROWING(52),
+    ROWING_MACHINE(53),
+    RUNNING(54),
+    RUNNING_TREADMILL(55),
+    RUGBY(56),
+    SAILING(57),
+    SCUBA_DIVING(58),
+    SKATING(59),
+    SKIING(60),
+    SNOWBOARDING(61),
+    SNOWSHOEING(62),
+    SOCCER(63),
+    SOFTBALL(64),
+    SQUASH(65),
+    SQUAT(66),
+    STAIR_CLIMBING(67),
+    STAIR_CLIMBING_MACHINE(68),
+    STRENGTH_TRAINING(69),
+    STRETCHING(70),
+    SURFING(71),
+    SWIMMING_OPEN_WATER(72),
+    SWIMMING_POOL(73),
+    TABLE_TENNIS(74),
+    TENNIS(75),
+    VOLLEYBALL(76),
+    WALKING(77),
+    WATER_POLO(78),
+    WEIGHTLIFTING(79),
+    WORKOUT_INDOOR(80),
+    WORKOUT_OUTDOOR(81),
+    YOGA(82);
+
+    public companion object {
+        private val IDS = initialize()
+        private fun initialize(): Map<Int, ExerciseType> {
+            val map = mutableMapOf<Int, ExerciseType>()
+            for (exerciseType in values()) {
+                map.put(exerciseType.id, exerciseType)
+            }
+            return map
+        }
+
+        /**
+         * Returns the [ExerciseType] based on its unique `id`.
+         *
+         * If the `id` doesn't map to an particular [ExerciseType], then [ExerciseType.UNKNOWN] is
+         * returned by default.
+         */
+        @JvmStatic
+        public fun fromId(id: Int): ExerciseType {
+            val exerciseType = IDS[id]
+            return exerciseType ?: UNKNOWN
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseUpdate.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseUpdate.kt
new file mode 100644
index 0000000..915d490a
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseUpdate.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+import java.time.Duration
+import java.time.Instant
+
+// TODO(b/179756269): add aggregated metrics.
+/** Contains the latest updated state and metrics for the current exercise. */
+public data class ExerciseUpdate(
+    /** Returns the current status of the exercise. */
+    val state: ExerciseState,
+
+    /** Returns the time at which the exercise was started. */
+    val startTime: Instant,
+
+    /**
+     * Returns the total elapsed time for which the exercise has been active, i.e. started but not
+     * paused.
+     */
+    val activeDuration: Duration,
+
+    /**
+     * Returns the list of latest [DataPoint] for each metric keyed by data type name. This allows a
+     * client to easily query for the "current" values of each metric since last call. There will
+     * only be one value for an Aggregated DataType.
+     */
+    val latestMetrics: Map<DataType, List<DataPoint>>,
+
+    /**
+     * Returns the latest `#ONE_TIME_GOAL` [ExerciseGoal] s that have been achieved. `#MILESTONE`
+     * [ExerciseGoal] s will be returned via `#getLatestMilestoneMarkerSummaries` below.
+     */
+    val latestAchievedGoals: Set<AchievedExerciseGoal>,
+
+    /** Returns the latest [MilestoneMarkerSummary] s. */
+    val latestMilestoneMarkerSummaries: Set<MilestoneMarkerSummary>,
+
+    /**
+     * Returns the [ExerciseConfig] used by the exercise when the [ExerciseUpdate] was dispatched,
+     * or `null` if there isn't any manually started exercise.
+     */
+    val exerciseConfig: ExerciseConfig?,
+
+    /**
+     * Returns the [AutoExerciseConfig] associated for the automatic exercise detection or `null` if
+     * the automatic exercise detection is stopped.
+     */
+    val autoExerciseConfig: AutoExerciseConfig?,
+
+    /**
+     * Returns the [ExerciseType] instance detected by the automatic exercise detection, otherwise
+     * [ExerciseType.UNKNOWN].
+     *
+     * It's only relevant when the automatic exercise detection is on.
+     */
+    val autoExerciseDetected: ExerciseType?,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(state.id)
+        dest.writeLong(startTime.toEpochMilli())
+        dest.writeLong(activeDuration.toMillis())
+
+        dest.writeInt(latestMetrics.size)
+        for ((dataType, dataPoints) in latestMetrics) {
+            dest.writeParcelable(dataType, flags)
+            dest.writeInt(dataPoints.size)
+            dest.writeTypedArray(dataPoints.toTypedArray(), flags)
+        }
+
+        dest.writeInt(latestAchievedGoals.size)
+        dest.writeTypedArray(latestAchievedGoals.toTypedArray(), flags)
+
+        dest.writeInt(latestMilestoneMarkerSummaries.size)
+        dest.writeTypedArray(latestMilestoneMarkerSummaries.toTypedArray(), flags)
+
+        dest.writeParcelable(exerciseConfig, flags)
+        dest.writeParcelable(autoExerciseConfig, flags)
+        dest.writeInt(autoExerciseDetected?.id ?: -1)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseUpdate> =
+            object : Parcelable.Creator<ExerciseUpdate> {
+                override fun createFromParcel(source: Parcel): ExerciseUpdate? {
+                    val exerciseState = ExerciseState.fromId(source.readInt()) ?: return null
+                    val startTime = Instant.ofEpochMilli(source.readLong())
+                    val activeDuration = Duration.ofMillis(source.readLong())
+
+                    val numMetrics = source.readInt()
+                    val latestMetrics = HashMap<DataType, List<DataPoint>>()
+                    repeat(numMetrics) {
+                        val dataType: DataType =
+                            source.readParcelable(DataType::class.java.classLoader) ?: return null
+                        val dataPointsArray = Array<DataPoint?>(source.readInt()) { null }
+                        source.readTypedArray(dataPointsArray, DataPoint.CREATOR)
+                        latestMetrics[dataType] = dataPointsArray.filterNotNull().toList()
+                    }
+
+                    val latestAchievedGoalsArray =
+                        Array<AchievedExerciseGoal?>(source.readInt()) { null }
+                    source.readTypedArray(latestAchievedGoalsArray, AchievedExerciseGoal.CREATOR)
+
+                    val latestMilestoneMarkerSummariesArray =
+                        Array<MilestoneMarkerSummary?>(source.readInt()) { null }
+                    source.readTypedArray(
+                        latestMilestoneMarkerSummariesArray,
+                        MilestoneMarkerSummary.CREATOR
+                    )
+
+                    val exerciseConfig: ExerciseConfig? =
+                        source.readParcelable(ExerciseConfig::class.java.classLoader)
+                    val autoExerciseConfig: AutoExerciseConfig? =
+                        source.readParcelable(AutoExerciseConfig::class.java.classLoader)
+                    val autoExerciseDetectedId = source.readInt()
+                    val autoExerciseDetected =
+                        if (autoExerciseDetectedId == -1) null
+                        else ExerciseType.fromId(autoExerciseDetectedId)
+
+                    return ExerciseUpdate(
+                        exerciseState,
+                        startTime,
+                        activeDuration,
+                        latestMetrics,
+                        latestAchievedGoalsArray.filterNotNull().toSet(),
+                        latestMilestoneMarkerSummariesArray.filterNotNull().toSet(),
+                        exerciseConfig,
+                        autoExerciseConfig,
+                        autoExerciseDetected
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseUpdate?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+
+    /** Supported Exercise session types. */
+    public enum class ExerciseSessionType {
+        /**
+         * The exercise is a manually started exercise session.
+         *
+         * [ExerciseUpdate.getExerciseConfig] returns non-null config with this type.
+         */
+        MANUALLY_STARTED_EXERCISE,
+
+        /**
+         * The exercise is an automatic exercise detection session.
+         *
+         * [ExerciseUpdate.getAutoExerciseConfig] returns non-null config with this type.
+         */
+        AUTO_EXERCISE_DETECTION,
+    }
+
+    /** Returns the current [ExerciseSessionType] WHS is carrying out. */
+    public fun getExerciseSessionType(): ExerciseSessionType {
+        return if (autoExerciseConfig != null) {
+            ExerciseSessionType.AUTO_EXERCISE_DETECTION
+        } else {
+            ExerciseSessionType.MANUALLY_STARTED_EXERCISE
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/MeasureCapabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/MeasureCapabilities.kt
new file mode 100644
index 0000000..bffc1ec
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/MeasureCapabilities.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * A place holder class that represents the capabilities of the WHS measuring client on the device.
+ */
+public data class MeasureCapabilities(
+    /**
+     * Set of supported [DataType] s for measure capture on this device.
+     *
+     * Some data types are not available for measurement; this is typically used to measure health
+     * data (e.g. HR).
+     */
+    val supportedDataTypesMeasure: Set<DataType>,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeTypedList(supportedDataTypesMeasure.toList())
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<MeasureCapabilities> =
+            object : Parcelable.Creator<MeasureCapabilities> {
+                override fun createFromParcel(source: Parcel): MeasureCapabilities? {
+                    val measureDataTypes = ArrayList<DataType>()
+                    source.readTypedList(measureDataTypes, DataType.CREATOR)
+                    return MeasureCapabilities(
+                        measureDataTypes.toSet(),
+                    )
+                }
+
+                override fun newArray(size: Int): Array<MeasureCapabilities?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/MilestoneMarkerSummary.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/MilestoneMarkerSummary.kt
new file mode 100644
index 0000000..98a340c
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/MilestoneMarkerSummary.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+import java.time.Duration
+import java.time.Instant
+
+/**
+ * The summary of metrics and state from the previously achieved milestone marker [ExerciseGoal].
+ */
+public data class MilestoneMarkerSummary(
+    /** Returns the time at which this milestone marker started being tracked. */
+    val startTime: Instant,
+
+    /** Returns the time at which this milestone marker was reached. */
+    val endTime: Instant,
+
+    /**
+     * Returns the total elapsed time for which the exercise was active during this milestone, i.e.
+     * started but not paused.
+     */
+    val activeDuration: Duration,
+
+    /** The [AchievedExerciseGoal] that triggered this milestone summary. */
+    val achievedGoal: AchievedExerciseGoal,
+
+    /**
+     * Returns the [DataPoint] for each aggregated metric keyed by [DataType] tracked between
+     * [startTime] and [endTime] i.e. during the duration of this milestone.
+     */
+    val summaryMetrics: Map<DataType, DataPoint>,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeLong(startTime.toEpochMilli())
+        dest.writeLong(endTime.toEpochMilli())
+        dest.writeLong(activeDuration.toMillis())
+        dest.writeParcelable(achievedGoal, flags)
+
+        dest.writeInt(summaryMetrics.size)
+        for ((dataType, dataPoint) in summaryMetrics) {
+            dest.writeParcelable(dataType, flags)
+            dest.writeParcelable(dataPoint, flags)
+        }
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<MilestoneMarkerSummary> =
+            object : Parcelable.Creator<MilestoneMarkerSummary> {
+                override fun createFromParcel(source: Parcel): MilestoneMarkerSummary? {
+                    val startTime = Instant.ofEpochMilli(source.readLong())
+                    val endTime = Instant.ofEpochMilli(source.readLong())
+                    val activeDuration = Duration.ofMillis(source.readLong())
+                    val achievedGoal: AchievedExerciseGoal =
+                        source.readParcelable(AchievedExerciseGoal::class.java.classLoader)
+                            ?: return null
+
+                    val summaryMetrics = HashMap<DataType, DataPoint>()
+                    repeat(source.readInt()) {
+                        val dataType: DataType =
+                            source.readParcelable(DataType::class.java.classLoader) ?: return null
+                        val dataPoint: DataPoint =
+                            source.readParcelable(DataPoint::class.java.classLoader) ?: return null
+                        summaryMetrics[dataType] = dataPoint
+                    }
+
+                    return MilestoneMarkerSummary(
+                        startTime = startTime,
+                        endTime = endTime,
+                        activeDuration = activeDuration,
+                        achievedGoal = achievedGoal,
+                        summaryMetrics = summaryMetrics
+                    )
+                }
+
+                override fun newArray(size: Int): Array<MilestoneMarkerSummary?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveActivityState.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveActivityState.kt
new file mode 100644
index 0000000..0013973
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveActivityState.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.content.Intent
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.UserActivityState.USER_ACTIVITY_EXERCISE
+import androidx.health.services.client.data.UserActivityState.USER_ACTIVITY_INACTIVE
+import androidx.health.services.client.data.UserActivityState.USER_ACTIVITY_PASSIVE
+import androidx.health.services.client.data.UserActivityState.USER_ACTIVITY_UNKNOWN
+import java.time.Instant
+
+/**
+ * Represents state from Passive tracking.
+ *
+ * Provides [DataPoint] s associated with the Passive tracking, in addition to data related to the
+ * user's [UserActivityState].
+ */
+public data class PassiveActivityState(
+    /** List of [DataPoint] s from Passive tracking. */
+    val dataPoints: List<DataPoint>,
+
+    /** The [UserActivityState] of the user from Passive tracking. */
+    val userActivityState: UserActivityState,
+
+    /**
+     * The [ExerciseType] of the user for a [UserActivityState.USER_ACTIVITY_EXERCISE] state, and
+     * `null` for other [UserActivityState] s.
+     */
+    val exerciseType: ExerciseType?,
+
+    /** The time at which the current state took effect. */
+    val stateChangeTime: Instant,
+) : Parcelable {
+
+    /**
+     * Puts the state as an extra into a given [Intent]. The state can then be obtained from the
+     * intent via [PassiveActivityState.fromIntent].
+     */
+    public fun putToIntent(intent: Intent) {
+        intent.putExtra(EXTRA_KEY, this)
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeInt(dataPoints.size)
+        dest.writeTypedArray(dataPoints.toTypedArray(), flags)
+
+        dest.writeInt(userActivityState.id)
+        dest.writeInt(exerciseType?.id ?: -1)
+        dest.writeLong(stateChangeTime.toEpochMilli())
+    }
+
+    public companion object {
+        private const val EXTRA_KEY = "whs.passive_activity_state"
+
+        @JvmField
+        public val CREATOR: Parcelable.Creator<PassiveActivityState> =
+            object : Parcelable.Creator<PassiveActivityState> {
+                override fun createFromParcel(source: Parcel): PassiveActivityState? {
+                    val dataPointsArray: Array<DataPoint?> = arrayOfNulls(source.readInt())
+                    source.readTypedArray(dataPointsArray, DataPoint.CREATOR)
+
+                    val activityState = UserActivityState.fromId(source.readInt()) ?: return null
+                    val exerciseTypeId = source.readInt()
+                    val exerciseType =
+                        if (exerciseTypeId == -1) null else ExerciseType.fromId(exerciseTypeId)
+                    val time = Instant.ofEpochMilli(source.readLong())
+
+                    return PassiveActivityState(
+                        dataPointsArray.filterNotNull().toList(),
+                        activityState,
+                        exerciseType,
+                        time
+                    )
+                }
+
+                override fun newArray(size: Int): Array<PassiveActivityState?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        /** Creates a [PassiveActivityState] for [USER_ACTIVITY_UNKNOWN]. */
+        @JvmStatic
+        public fun createUnknownTypeState(
+            dataPoints: List<DataPoint>,
+            stateChangeTime: Instant
+        ): PassiveActivityState =
+            PassiveActivityState(
+                dataPoints,
+                USER_ACTIVITY_UNKNOWN,
+                exerciseType = null,
+                stateChangeTime
+            )
+
+        /** Creates a [PassiveActivityState] for [USER_ACTIVITY_EXERCISE]. */
+        @JvmStatic
+        public fun createActiveExerciseState(
+            dataPoints: List<DataPoint>,
+            exerciseType: ExerciseType,
+            stateChangeTime: Instant
+        ): PassiveActivityState =
+            PassiveActivityState(dataPoints, USER_ACTIVITY_EXERCISE, exerciseType, stateChangeTime)
+
+        /** Creates a [PassiveActivityState] for [USER_ACTIVITY_PASSIVE]. */
+        @JvmStatic
+        public fun createPassiveActivityState(
+            dataPoints: List<DataPoint>,
+            stateChangeTime: Instant
+        ): PassiveActivityState =
+            PassiveActivityState(
+                dataPoints,
+                USER_ACTIVITY_PASSIVE,
+                exerciseType = null,
+                stateChangeTime
+            )
+
+        /**
+         * Creates a [PassiveActivityState] from an [Intent]. Returns null if no
+         * [PassiveActivityState] is stored in the given intent.
+         */
+        @JvmStatic
+        public fun fromIntent(intent: Intent): PassiveActivityState? =
+            intent.getParcelableExtra(EXTRA_KEY)
+
+        /** Creates a [PassiveActivityState] for [USER_ACTIVITY_INACTIVE]. */
+        @JvmStatic
+        public fun createInactiveState(
+            dataPoints: List<DataPoint>,
+            stateChangeTime: Instant
+        ): PassiveActivityState =
+            PassiveActivityState(
+                dataPoints,
+                USER_ACTIVITY_INACTIVE,
+                exerciseType = null,
+                stateChangeTime
+            )
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveMonitoringCapabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveMonitoringCapabilities.kt
new file mode 100644
index 0000000..b715fda
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/PassiveMonitoringCapabilities.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * A place holder class that represents the capabilities of the WHS passive monitoring client on the
+ * device.
+ */
+public data class PassiveMonitoringCapabilities(
+
+    /**
+     * Set of supported [DataType] s for background capture on this device.
+     *
+     * Some data types are only available during exercise (e.g. location) or for measurements.
+     */
+    val supportedDataTypesPassiveMonitoring: Set<DataType>,
+
+    /** Set of supported [DataType] s for event callbacks on this device. */
+    val supportedDataTypesEvents: Set<DataType>,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeTypedList(supportedDataTypesPassiveMonitoring.toList())
+        dest.writeTypedList(supportedDataTypesEvents.toList())
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<PassiveMonitoringCapabilities> =
+            object : Parcelable.Creator<PassiveMonitoringCapabilities> {
+                override fun createFromParcel(source: Parcel): PassiveMonitoringCapabilities? {
+                    val passiveMonitoringDataTypes = ArrayList<DataType>()
+                    source.readTypedList(passiveMonitoringDataTypes, DataType.CREATOR)
+                    val eventDataTypes = ArrayList<DataType>()
+                    source.readTypedList(eventDataTypes, DataType.CREATOR)
+                    return PassiveMonitoringCapabilities(
+                        passiveMonitoringDataTypes.toSet(),
+                        eventDataTypes.toSet()
+                    )
+                }
+
+                override fun newArray(size: Int): Array<PassiveMonitoringCapabilities?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/UserActivityState.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/UserActivityState.kt
new file mode 100644
index 0000000..5ba779e
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/UserActivityState.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+/** Types of user activity states. */
+public enum class UserActivityState(public val id: Int) {
+    USER_ACTIVITY_UNKNOWN(0),
+    USER_ACTIVITY_EXERCISE(1),
+    USER_ACTIVITY_PASSIVE(2),
+    USER_ACTIVITY_INACTIVE(3);
+
+    public companion object {
+        @JvmStatic
+        public fun fromId(id: Int): UserActivityState? = values().firstOrNull { it.id == id }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/Value.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/Value.kt
new file mode 100644
index 0000000..5ae780d
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/Value.kt
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** A [Parcelable] wrapper that can hold a value of a specified type. */
+@Suppress("DataClassPrivateConstructor")
+public data class Value
+private constructor(
+    // TODO(b/175054913): Investigate using a AutoOneOf instead.
+    val format: Int,
+    val doubleList: List<Double>,
+    val longValue: Long,
+) : Parcelable {
+
+    /**
+     * Returns this [Value] represented as an `long`.
+     *
+     * @throws IllegalStateException if [isLong] is `false`
+     */
+    public fun asLong(): Long {
+        check(isLong) { "Attempted to read value as long, but value is not of type long" }
+        return longValue
+    }
+
+    /**
+     * Returns this [Value] represented as an `boolean`.
+     *
+     * @throws IllegalStateException if [isBoolean] is `false`
+     */
+    public fun asBoolean(): Boolean {
+        check(isBoolean) { "Attempted to read value as boolean, but value is not of type boolean" }
+        return longValue != 0L
+    }
+
+    /**
+     * Returns this [Value] represented as a `double`.
+     *
+     * @throws IllegalStateException if [isDouble] is `false`
+     */
+    public fun asDouble(): Double {
+        check(isDouble) { "Attempted to read value as double, but value is not of type double" }
+        return doubleList[0]
+    }
+
+    /**
+     * Returns this [Value] represented as a `double[]`.
+     *
+     * @throws IllegalStateException if [isDoubleArray] is `false`
+     */
+    public fun asDoubleArray(): DoubleArray {
+        check(isDoubleArray) {
+            "Attempted to read value as double array, but value is not correct type"
+        }
+        return doubleList.toDoubleArray()
+    }
+
+    /** Whether or not this [Value] can be represented as an `long`. */
+    public val isLong: Boolean
+        get() = format == FORMAT_LONG
+
+    /** Whether or not this [Value] can be represented as an `boolean`. */
+    public val isBoolean: Boolean
+        get() = format == FORMAT_BOOLEAN
+
+    /** Whether or not this [Value] can be represented as a `double`. */
+    public val isDouble: Boolean
+        get() = format == FORMAT_DOUBLE
+
+    /** Whether or not this [Value] can be represented as a `double[]`. */
+    public val isDoubleArray: Boolean
+        get() = format == FORMAT_DOUBLE_ARRAY
+
+    override fun describeContents(): Int {
+        return 0
+    }
+
+    /**
+     * Writes the value of this object to [dest].
+     *
+     * @throws IllegalStateException if [format] is invalid
+     */
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        val format = format
+        dest.writeInt(format)
+        when (format) {
+            FORMAT_BOOLEAN, FORMAT_LONG -> {
+                dest.writeLong(longValue)
+                return
+            }
+            FORMAT_DOUBLE -> {
+                dest.writeDouble(asDouble())
+                return
+            }
+            FORMAT_DOUBLE_ARRAY -> {
+                val doubleArray = asDoubleArray()
+                dest.writeInt(doubleArray.size)
+                dest.writeDoubleArray(doubleArray)
+                return
+            }
+            else -> {}
+        }
+        throw IllegalStateException(String.format("Unexpected format: %s", format))
+    }
+
+    public companion object {
+        /** The format used for a [Value] represented as a `double`. */
+        public const val FORMAT_DOUBLE: Int = 1
+
+        /** The format used for a [Value] represented as an `long`. */
+        public const val FORMAT_LONG: Int = 2
+
+        /** The format used for a [Value] represented as an `boolean`. */
+        public const val FORMAT_BOOLEAN: Int = 4
+
+        /** The format used for a [Value] represented as a `double[]`. */
+        public const val FORMAT_DOUBLE_ARRAY: Int = 3
+
+        @JvmField
+        public val CREATOR: Parcelable.Creator<Value> =
+            object : Parcelable.Creator<Value> {
+                override fun createFromParcel(parcel: Parcel): Value {
+                    val format = parcel.readInt()
+                    when (format) {
+                        FORMAT_BOOLEAN, FORMAT_LONG ->
+                            return Value(format, listOf(), parcel.readLong())
+                        FORMAT_DOUBLE ->
+                            return Value(format, listOf(parcel.readDouble()), /* longValue= */ 0)
+                        FORMAT_DOUBLE_ARRAY -> {
+                            val doubleArray = DoubleArray(parcel.readInt())
+                            parcel.readDoubleArray(doubleArray)
+                            return Value(format, doubleArray.toList(), /* longValue= */ 0)
+                        }
+                        else -> {}
+                    }
+                    throw IllegalStateException(String.format("Unexpected format: %s", format))
+                }
+
+                override fun newArray(size: Int): Array<Value?> {
+                    return arrayOfNulls(size)
+                }
+            }
+
+        /** Creates a [Value] that represents a `long`. */
+        @JvmStatic
+        public fun ofLong(value: Long): Value {
+            return Value(FORMAT_LONG, listOf(), value)
+        }
+
+        /** Creates a [Value] that represents an `boolean`. */
+        @JvmStatic
+        public fun ofBoolean(value: Boolean): Value {
+            return Value(FORMAT_BOOLEAN, listOf(), if (value) 1 else 0)
+        }
+
+        /** Creates a [Value] that represents a `double`. */
+        @JvmStatic
+        public fun ofDouble(value: Double): Value {
+            return Value(FORMAT_DOUBLE, listOf(value), longValue = 0)
+        }
+
+        /** Creates a [Value] that represents a `double[]`. */
+        @JvmStatic
+        public fun ofDoubleArray(vararg doubleArray: Double): Value {
+            return Value(FORMAT_DOUBLE_ARRAY, doubleArray.toList(), longValue = 0)
+        }
+
+        /**
+         * Compares two [Value] s based on their representation.
+         *
+         * @throws IllegalStateException if `first` and `second` do not share the same format or are
+         * represented as a `double[]`
+         */
+        internal fun compare(first: Value, second: Value): Int {
+            check(first.format == second.format) {
+                "Attempted to compare Values with different formats"
+            }
+            when (first.format) {
+                FORMAT_LONG -> return first.longValue.compareTo(second.longValue)
+                FORMAT_BOOLEAN -> return first.asBoolean().compareTo(second.asBoolean())
+                FORMAT_DOUBLE -> return first.doubleList[0].compareTo(second.doubleList[0])
+                FORMAT_DOUBLE_ARRAY ->
+                    throw IllegalStateException(
+                        "Attempted to compare Values with invalid format (double array)"
+                    )
+                else -> {}
+            }
+            throw IllegalStateException(String.format("Unexpected format: %s", first.format))
+        }
+
+        /**
+         * Adds two [Value] s based on their representation.
+         *
+         * @throws IllegalStateException if `first` and `second` do not share the same format or are
+         * represented as a `double[]` or `boolean`
+         */
+        @JvmStatic
+        public fun sum(first: Value, second: Value): Value {
+            require(first.format == second.format) {
+                "Attempted to add Values with different formats"
+            }
+            when (first.format) {
+                FORMAT_LONG -> return ofLong(first.asLong() + second.asLong())
+                FORMAT_DOUBLE -> return ofDouble(first.asDouble() + second.asDouble())
+                FORMAT_BOOLEAN ->
+                    throw IllegalStateException(
+                        "Attempted to add Values with invalid format (boolean)"
+                    )
+                FORMAT_DOUBLE_ARRAY ->
+                    throw IllegalStateException(
+                        "Attempted to add Values with invalid format (double array)"
+                    )
+                else -> {}
+            }
+            throw IllegalStateException(String.format("Unexpected format: %s", first.format))
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/event/Event.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/event/Event.kt
new file mode 100644
index 0000000..5e28beb
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/event/Event.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data.event
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.DataPoint
+import androidx.health.services.client.data.DataTypeCondition
+
+/** Defines an event that will be triggered when the specified condition is met. */
+public data class Event(
+    /** [DataTypeCondition] which must be met for the event to be triggered. */
+    val dataTypeCondition: DataTypeCondition,
+    val triggerType: TriggerType,
+) : Parcelable {
+
+    /** Whether or not repeated events should be triggered. */
+    public enum class TriggerType(public val id: Int) {
+        /** The event will trigger the first time the specified conditions are met. */
+        ONCE(1),
+
+        /** The event will trigger each time the specified conditions *become* met. */
+        REPEATED(2);
+
+        public companion object {
+            @JvmStatic
+            public fun fromId(id: Int): TriggerType? = values().firstOrNull { it.id == id }
+        }
+    }
+
+    /**
+     * Does the provided [DataPoint] satisfy the event condition.
+     *
+     * @throws IllegalArgumentException if the provided data point is not of the same data type as
+     * the condition itself.
+     */
+    public fun isTriggered(dataPoint: DataPoint): Boolean {
+        return dataTypeCondition.isSatisfied(dataPoint)
+    }
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(dataTypeCondition, flags)
+        dest.writeInt(triggerType.id)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<Event> =
+            object : Parcelable.Creator<Event> {
+                override fun createFromParcel(source: Parcel): Event? {
+                    return Event(
+                        source.readParcelable(DataTypeCondition::class.java.classLoader)
+                            ?: return null,
+                        TriggerType.fromId(source.readInt()) ?: return null
+                    )
+                }
+
+                override fun newArray(size: Int): Array<Event?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseIpcClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseIpcClient.kt
new file mode 100644
index 0000000..7ab0e8a
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseIpcClient.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.os.IBinder
+import androidx.health.services.client.impl.ipc.Client
+import androidx.health.services.client.impl.ipc.Client.VersionGetter
+import androidx.health.services.client.impl.ipc.ClientConfiguration
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import androidx.health.services.client.impl.ipc.internal.ListenerKey
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * An IPC Client that connects to and communicates with the WHS Service to make Exercise API calls.
+ *
+ * @hide
+ */
+public class ExerciseIpcClient internal constructor(connectionManager: ConnectionManager) :
+    Client(
+        CLIENT_CONFIGURATION,
+        connectionManager,
+        VersionGetter { binder: IBinder -> getServiceInterface(binder).apiVersion }
+    ) {
+
+    public override fun <T> execute(operation: ServiceOperation<T>): ListenableFuture<T> {
+        return super.execute(operation)
+    }
+
+    public override fun <T> registerListener(
+        listenerKey: ListenerKey,
+        registerListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.registerListener(listenerKey, registerListenerOperation)
+    }
+
+    public override fun <T> unregisterListener(
+        listenerKey: ListenerKey,
+        unregisterListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.unregisterListener(listenerKey, unregisterListenerOperation)
+    }
+
+    public companion object {
+        public const val SERVICE_BIND_ACTION: String =
+            "com.google.android.wearable.healthservices.ExerciseClient"
+        private const val CLIENT = "HealthServicesExerciseClient"
+        private const val SERVICE_PACKAGE_NAME = "com.google.android.wearable.healthservices"
+        private val CLIENT_CONFIGURATION =
+            ClientConfiguration(CLIENT, SERVICE_PACKAGE_NAME, SERVICE_BIND_ACTION)
+
+        @JvmStatic
+        internal fun getServiceInterface(binder: IBinder): IExerciseApiService {
+            return IExerciseApiService.Stub.asInterface(binder)
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt
new file mode 100644
index 0000000..d48bee2
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ExerciseUpdateListenerStub.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import androidx.annotation.GuardedBy
+import androidx.health.services.client.ExerciseUpdateListener
+import androidx.health.services.client.impl.ipc.internal.ListenerKey
+import androidx.health.services.client.impl.response.ExerciseLapSummaryResponse
+import androidx.health.services.client.impl.response.ExerciseUpdateResponse
+import java.util.HashMap
+import java.util.concurrent.Executor
+
+/**
+ * A stub implementation for IExerciseUpdateListener.
+ *
+ * @hide
+ */
+public class ExerciseUpdateListenerStub
+private constructor(private val listener: ExerciseUpdateListener, private val executor: Executor) :
+    IExerciseUpdateListener.Stub() {
+
+    public val listenerKey: ListenerKey = ListenerKey(listener)
+
+    override fun onExerciseUpdate(response: ExerciseUpdateResponse) {
+        executor.execute { listener.onExerciseUpdate(response.exerciseUpdate) }
+    }
+
+    override fun onLapSummary(response: ExerciseLapSummaryResponse) {
+        executor.execute { listener.onLapSummary(response.exerciseLapSummary) }
+    }
+
+    /**
+     * A class that stores unique active instances of [ExerciseUpdateListener] to ensure same binder
+     * object is passed by framework to service side of the IPC.
+     */
+    public class ExerciseUpdateListenerCache private constructor() {
+        @GuardedBy("this")
+        private val listeners: MutableMap<ExerciseUpdateListener, ExerciseUpdateListenerStub> =
+            HashMap()
+
+        @Synchronized
+        public fun getOrCreate(
+            listener: ExerciseUpdateListener,
+            executor: Executor
+        ): ExerciseUpdateListenerStub {
+            return listeners.getOrPut(listener) { ExerciseUpdateListenerStub(listener, executor) }
+        }
+
+        @Synchronized
+        public fun remove(
+            exerciseUpdateListener: ExerciseUpdateListener
+        ): ExerciseUpdateListenerStub? {
+            return listeners.remove(exerciseUpdateListener)
+        }
+
+        public companion object {
+            @JvmField
+            public val INSTANCE: ExerciseUpdateListenerCache = ExerciseUpdateListenerCache()
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/HealthServicesIpcClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/HealthServicesIpcClient.kt
new file mode 100644
index 0000000..f46fda7
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/HealthServicesIpcClient.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.os.IBinder
+import androidx.health.services.client.impl.ipc.Client
+import androidx.health.services.client.impl.ipc.Client.VersionGetter
+import androidx.health.services.client.impl.ipc.ClientConfiguration
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import androidx.health.services.client.impl.ipc.internal.ListenerKey
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * An IPC Client that connects to and communicates with the WHS Service.
+ *
+ * @hide
+ */
+public class HealthServicesIpcClient internal constructor(connectionManager: ConnectionManager) :
+    Client(
+        CLIENT_CONFIGURATION,
+        connectionManager,
+        VersionGetter { binder -> getServiceInterface(binder).apiVersion }
+    ) {
+
+    public override fun <T> execute(operation: ServiceOperation<T>): ListenableFuture<T> {
+        return super.execute(operation)
+    }
+
+    public override fun <T> registerListener(
+        listenerKey: ListenerKey,
+        registerListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.registerListener(listenerKey, registerListenerOperation)
+    }
+
+    public override fun <T> unregisterListener(
+        listenerKey: ListenerKey,
+        unregisterListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.unregisterListener(listenerKey, unregisterListenerOperation)
+    }
+
+    public companion object {
+        private const val CLIENT = "HealthServicesClient"
+        private const val SERVICE_PACKAGE_NAME = "com.google.android.wearable.healthservices"
+        public const val SERVICE_BIND_ACTION: String =
+            "com.google.android.wearable.healthservices.HealthServicesClient"
+        private val CLIENT_CONFIGURATION =
+            ClientConfiguration(CLIENT, SERVICE_PACKAGE_NAME, SERVICE_BIND_ACTION)
+
+        @JvmStatic
+        internal fun getServiceInterface(binder: IBinder): IHealthServicesApiService {
+            return IHealthServicesApiService.Stub.asInterface(binder)
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt
new file mode 100644
index 0000000..476c6f6
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import androidx.annotation.GuardedBy
+import androidx.annotation.VisibleForTesting
+import androidx.health.services.client.MeasureCallback
+import androidx.health.services.client.data.DataType
+import androidx.health.services.client.impl.ipc.internal.ListenerKey
+import androidx.health.services.client.impl.response.AvailabilityResponse
+import androidx.health.services.client.impl.response.DataPointsResponse
+import com.google.common.util.concurrent.MoreExecutors
+import java.util.HashMap
+import java.util.concurrent.Executor
+
+/**
+ * A stub implementation for IMeasureCallback.
+ *
+ * @hide
+ */
+public class MeasureCallbackStub
+private constructor(callbackKey: MeasureCallbackKey, private val callback: MeasureCallback) :
+    IMeasureCallback.Stub() {
+
+    public val listenerKey: ListenerKey = ListenerKey(callbackKey)
+
+    @get:VisibleForTesting
+    public var executor: Executor = MoreExecutors.directExecutor()
+        private set
+
+    override fun onAvailabilityChanged(response: AvailabilityResponse) {
+        executor.execute {
+            callback.onAvailabilityChanged(response.dataType, response.availability)
+        }
+    }
+
+    override fun onData(response: DataPointsResponse) {
+        executor.execute { callback.onData(response.dataPoints) }
+    }
+
+    /**
+     * Its important to use the same stub for registration and un-registration, to ensure same
+     * binder object is passed by framework to service side of the IPC.
+     */
+    public class MeasureCallbackCache private constructor() {
+        @GuardedBy("this")
+        private val listeners: MutableMap<MeasureCallbackKey, MeasureCallbackStub> = HashMap()
+
+        @Synchronized
+        public fun getOrCreate(
+            dataType: DataType,
+            measureCallback: MeasureCallback,
+            executor: Executor
+        ): MeasureCallbackStub {
+            val callbackKey = MeasureCallbackKey(dataType, measureCallback)
+
+            // If a measure callback happens for the same datatype with same callback, pass the same
+            // stub instance, but update the executor, as executor might have changed. Its ok to
+            // register
+            // the callback once again, as on our service implementation re-registering for same
+            // datatype
+            // with  same callback is a no-op.
+            var measureCallbackStub = listeners[callbackKey]
+            if (measureCallbackStub == null) {
+                measureCallbackStub = MeasureCallbackStub(callbackKey, measureCallback)
+                listeners[callbackKey] = measureCallbackStub
+            }
+            measureCallbackStub.executor = executor
+            return measureCallbackStub
+        }
+
+        @Synchronized
+        public fun remove(
+            dataType: DataType,
+            measureCallback: MeasureCallback
+        ): MeasureCallbackStub? {
+            val callbackKey = MeasureCallbackKey(dataType, measureCallback)
+            return listeners.remove(callbackKey)
+        }
+
+        public companion object {
+            @JvmField public val INSTANCE: MeasureCallbackCache = MeasureCallbackCache()
+        }
+    }
+
+    private data class MeasureCallbackKey(
+        private val dataType: DataType,
+        private val measureCallback: MeasureCallback
+    )
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureIpcClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureIpcClient.kt
new file mode 100644
index 0000000..e816a0a
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/MeasureIpcClient.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.os.IBinder
+import androidx.health.services.client.impl.ipc.Client
+import androidx.health.services.client.impl.ipc.Client.VersionGetter
+import androidx.health.services.client.impl.ipc.ClientConfiguration
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import androidx.health.services.client.impl.ipc.internal.ListenerKey
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * An IPC Client that connects to and communicates with the WHS Service to make Measure API calls.
+ *
+ * @hide
+ */
+public class MeasureIpcClient internal constructor(connectionManager: ConnectionManager) :
+    Client(
+        CLIENT_CONFIGURATION,
+        connectionManager,
+        VersionGetter { binder -> getServiceInterface(binder).apiVersion }
+    ) {
+
+    public override fun <T> execute(operation: ServiceOperation<T>): ListenableFuture<T> {
+        return super.execute(operation)
+    }
+
+    public override fun <T> registerListener(
+        listenerKey: ListenerKey,
+        registerListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.registerListener(listenerKey, registerListenerOperation)
+    }
+
+    public override fun <T> unregisterListener(
+        listenerKey: ListenerKey,
+        unregisterListenerOperation: ServiceOperation<T>
+    ): ListenableFuture<T> {
+        return super.unregisterListener(listenerKey, unregisterListenerOperation)
+    }
+
+    public companion object {
+        public const val SERVICE_BIND_ACTION: String =
+            "com.google.android.wearable.healthservices.MeasureClient"
+        public const val CLIENT: String = "HealthServicesMeasureClient"
+        public const val SERVICE_PACKAGE_NAME: String = "com.google.android.wearable.healthservices"
+        private val CLIENT_CONFIGURATION =
+            ClientConfiguration(CLIENT, SERVICE_PACKAGE_NAME, SERVICE_BIND_ACTION)
+
+        @JvmStatic
+        internal fun getServiceInterface(binder: IBinder): IMeasureApiService {
+            return IMeasureApiService.Stub.asInterface(binder)
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt
new file mode 100644
index 0000000..700f1af
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import androidx.health.services.client.PassiveMonitoringCallback
+import androidx.health.services.client.impl.response.PassiveActivityStateResponse
+
+/**
+ * A stub implementation for IPassiveMonitoringCallback.
+ *
+ * @hide
+ */
+internal class PassiveMonitoringCallbackStub
+internal constructor(private val callback: PassiveMonitoringCallback) :
+    IPassiveMonitoringCallback.Stub() {
+
+    override fun onPassiveActivityState(response: PassiveActivityStateResponse) {
+        callback.onPassiveActivityState(response.passiveActivityState)
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringIpcClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringIpcClient.kt
new file mode 100644
index 0000000..acbe468
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/PassiveMonitoringIpcClient.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.os.IBinder
+import androidx.health.services.client.impl.ipc.Client
+import androidx.health.services.client.impl.ipc.Client.VersionGetter
+import androidx.health.services.client.impl.ipc.ClientConfiguration
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * An IPC Client that connects to and communicates with the WHS Service to make passive monitoring
+ * API calls.
+ *
+ * @hide
+ */
+public class PassiveMonitoringIpcClient(connectionManager: ConnectionManager) :
+    Client(
+        CLIENT_CONFIGURATION,
+        connectionManager,
+        VersionGetter { binder -> getServiceInterface(binder).apiVersion }
+    ) {
+
+    public override fun <T> execute(operation: ServiceOperation<T>): ListenableFuture<T> {
+        return super.execute(operation)
+    }
+
+    public companion object {
+        public const val SERVICE_BIND_ACTION: String =
+            "com.google.android.wearable.healthservices.PassiveMonitoringClient"
+        private const val CLIENT = "HealthServicesPassiveMonitoringClient"
+        private const val SERVICE_PACKAGE_NAME = "com.google.android.wearable.healthservices"
+        private val CLIENT_CONFIGURATION =
+            ClientConfiguration(CLIENT, SERVICE_PACKAGE_NAME, SERVICE_BIND_ACTION)
+
+        @JvmStatic
+        internal fun getServiceInterface(binder: IBinder): IPassiveMonitoringApiService {
+            return IPassiveMonitoringApiService.Stub.asInterface(binder)
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt
new file mode 100644
index 0000000..adff9c2
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.content.Context
+import androidx.core.content.ContextCompat
+import androidx.health.services.client.ExerciseClient
+import androidx.health.services.client.ExerciseUpdateListener
+import androidx.health.services.client.data.Capabilities
+import androidx.health.services.client.data.ExerciseConfig
+import androidx.health.services.client.data.ExerciseGoal
+import androidx.health.services.client.data.ExerciseInfo
+import androidx.health.services.client.impl.ExerciseIpcClient.Companion.getServiceInterface
+import androidx.health.services.client.impl.internal.ExerciseInfoCallback
+import androidx.health.services.client.impl.internal.StatusCallback
+import androidx.health.services.client.impl.internal.WhsConnectionManager
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import androidx.health.services.client.impl.request.AutoPauseAndResumeConfigRequest
+import androidx.health.services.client.impl.request.CapabilitiesRequest
+import androidx.health.services.client.impl.request.ExerciseGoalRequest
+import androidx.health.services.client.impl.request.StartExerciseRequest
+import androidx.health.services.client.impl.response.CapabilitiesResponse
+import com.google.common.util.concurrent.Futures
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.Executor
+
+/**
+ * [ExerciseClient] API implementation that receives data from the WHS Service.
+ *
+ * @hide
+ */
+internal class ServiceBackedExerciseClient
+private constructor(private val context: Context, connectionManager: ConnectionManager) :
+    ExerciseClient {
+
+    private val ipcClient: ExerciseIpcClient = ExerciseIpcClient(connectionManager)
+
+    override fun startExercise(configuration: ExerciseConfig): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .startExercise(
+                        StartExerciseRequest(context.packageName, configuration),
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun pauseExercise(): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .pauseExercise(context.packageName, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun resumeExercise(): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .resumeExercise(context.packageName, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun endExercise(): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .endExercise(context.packageName, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun markLap(): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .markLap(context.packageName, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override val currentExerciseInfo: ListenableFuture<ExerciseInfo>
+        get() {
+            val serviceOperation =
+                ServiceOperation<ExerciseInfo> { binder, resultFuture ->
+                    getServiceInterface(binder)
+                        .getCurrentExerciseInfo(
+                            context.packageName,
+                            ExerciseInfoCallback(resultFuture)
+                        )
+                }
+            return ipcClient.execute(serviceOperation)
+        }
+
+    override fun setUpdateListener(listener: ExerciseUpdateListener): ListenableFuture<Void> {
+        return setUpdateListener(listener, ContextCompat.getMainExecutor(context))
+    }
+
+    override fun setUpdateListener(
+        listener: ExerciseUpdateListener,
+        executor: Executor
+    ): ListenableFuture<Void> {
+        val listenerStub =
+            ExerciseUpdateListenerStub.ExerciseUpdateListenerCache.INSTANCE.getOrCreate(
+                listener,
+                executor
+            )
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .setUpdateListener(
+                        context.packageName,
+                        listenerStub,
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.registerListener(listenerStub.listenerKey, serviceOperation)
+    }
+
+    override fun clearUpdateListener(listener: ExerciseUpdateListener): ListenableFuture<Void> {
+        val listenerStub =
+            ExerciseUpdateListenerStub.ExerciseUpdateListenerCache.INSTANCE.remove(listener)
+                ?: return Futures.immediateFailedFuture(
+                    IllegalArgumentException("Given listener was not added.")
+                )
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .clearUpdateListener(
+                        context.packageName,
+                        listenerStub,
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.unregisterListener(listenerStub.listenerKey, serviceOperation)
+    }
+
+    override fun addGoalToActiveExercise(exerciseGoal: ExerciseGoal): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .addGoalToActiveExercise(
+                        ExerciseGoalRequest(context.packageName, exerciseGoal),
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun overrideAutoPauseAndResumeForActiveExercise(
+        enabled: Boolean
+    ): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .overrideAutoPauseAndResumeForActiveExercise(
+                        AutoPauseAndResumeConfigRequest(context.packageName, enabled),
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override val capabilities: ListenableFuture<Capabilities>
+        get() {
+            val request = CapabilitiesRequest(context.packageName)
+            val serviceOperation =
+                ServiceOperation<CapabilitiesResponse> { binder, resultFuture ->
+                    resultFuture.set(getServiceInterface(binder).getCapabilities(request))
+                }
+            return Futures.transform(
+                ipcClient.execute(serviceOperation),
+                { response -> response?.capabilities },
+                ContextCompat.getMainExecutor(context)
+            )
+        }
+
+    internal companion object {
+        @JvmStatic
+        fun getClient(context: Context): ServiceBackedExerciseClient {
+            return ServiceBackedExerciseClient(context, WhsConnectionManager.getInstance(context))
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedHealthServicesClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedHealthServicesClient.kt
new file mode 100644
index 0000000..ef052fb
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedHealthServicesClient.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.content.Context
+import androidx.health.services.client.ExerciseClient
+import androidx.health.services.client.HealthServicesClient
+import androidx.health.services.client.MeasureClient
+import androidx.health.services.client.PassiveMonitoringClient
+import androidx.health.services.client.impl.internal.WhsConnectionManager
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+
+/**
+ * A [HealthServicesClient] implementation.
+ *
+ * @hide
+ */
+public class ServiceBackedHealthServicesClient
+internal constructor(context: Context, connectionManager: ConnectionManager) :
+    HealthServicesClient {
+
+    private val applicationContext: Context = context.applicationContext
+    private val ipcClient: HealthServicesIpcClient = HealthServicesIpcClient(connectionManager)
+
+    public constructor(context: Context) : this(context, WhsConnectionManager.getInstance(context))
+
+    override val exerciseClient: ExerciseClient
+        get() = ServiceBackedExerciseClient.getClient(applicationContext)
+    override val passiveMonitoringClient: PassiveMonitoringClient
+        get() = ServiceBackedPassiveMonitoringClient(applicationContext)
+    override val measureClient: MeasureClient
+        get() = ServiceBackedMeasureClient.getClient(applicationContext)
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt
new file mode 100644
index 0000000..51e21ed
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.content.Context
+import androidx.annotation.VisibleForTesting
+import androidx.core.content.ContextCompat
+import androidx.health.services.client.MeasureCallback
+import androidx.health.services.client.MeasureClient
+import androidx.health.services.client.data.DataType
+import androidx.health.services.client.data.MeasureCapabilities
+import androidx.health.services.client.impl.MeasureCallbackStub.MeasureCallbackCache
+import androidx.health.services.client.impl.MeasureIpcClient.Companion.getServiceInterface
+import androidx.health.services.client.impl.internal.StatusCallback
+import androidx.health.services.client.impl.internal.WhsConnectionManager
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+import androidx.health.services.client.impl.request.CapabilitiesRequest
+import androidx.health.services.client.impl.request.MeasureRegistrationRequest
+import androidx.health.services.client.impl.request.MeasureUnregistrationRequest
+import androidx.health.services.client.impl.response.MeasureCapabilitiesResponse
+import com.google.common.util.concurrent.Futures
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.Executor
+
+/**
+ * [MeasureClient] that interacts with WHS via IPC.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class ServiceBackedMeasureClient(
+    private val context: Context,
+    connectionManager: ConnectionManager
+) : MeasureClient {
+
+    private val ipcClient: MeasureIpcClient = MeasureIpcClient(connectionManager)
+
+    override fun registerCallback(
+        dataType: DataType,
+        callback: MeasureCallback
+    ): ListenableFuture<Void> {
+        return registerCallback(dataType, callback, ContextCompat.getMainExecutor(context))
+    }
+
+    override fun registerCallback(
+        dataType: DataType,
+        callback: MeasureCallback,
+        executor: Executor
+    ): ListenableFuture<Void> {
+        val request = MeasureRegistrationRequest(context.packageName, dataType)
+        val callbackStub = MeasureCallbackCache.INSTANCE.getOrCreate(dataType, callback, executor)
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .registerCallback(request, callbackStub, StatusCallback(resultFuture))
+            }
+        return ipcClient.registerListener(callbackStub.listenerKey, serviceOperation)
+    }
+
+    override fun unregisterCallback(
+        dataType: DataType,
+        callback: MeasureCallback
+    ): ListenableFuture<Void> {
+        val callbackStub =
+            MeasureCallbackCache.INSTANCE.remove(dataType, callback)
+                ?: return Futures.immediateFailedFuture(
+                    IllegalArgumentException("Given callback was not registered.")
+                )
+        val request = MeasureUnregistrationRequest(context.packageName, dataType)
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .unregisterCallback(request, callbackStub, StatusCallback(resultFuture))
+            }
+        return ipcClient.unregisterListener(callbackStub.listenerKey, serviceOperation)
+    }
+
+    override val capabilities: ListenableFuture<MeasureCapabilities>
+        get() {
+            val request = CapabilitiesRequest(context.packageName)
+            val serviceOperation =
+                ServiceOperation<MeasureCapabilitiesResponse> { binder, resultFuture ->
+                    resultFuture.set(getServiceInterface(binder).getCapabilities(request))
+                }
+            return Futures.transform(
+                ipcClient.execute(serviceOperation),
+                { response -> response?.measureCapabilities },
+                ContextCompat.getMainExecutor(context)
+            )
+        }
+
+    internal companion object {
+        @JvmStatic
+        fun getClient(context: Context): ServiceBackedMeasureClient {
+            return ServiceBackedMeasureClient(context, WhsConnectionManager.getInstance(context))
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClient.kt
new file mode 100644
index 0000000..f156c38
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClient.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl
+
+import android.app.PendingIntent
+import android.content.Context
+import androidx.core.content.ContextCompat
+import androidx.health.services.client.PassiveMonitoringCallback
+import androidx.health.services.client.PassiveMonitoringClient
+import androidx.health.services.client.data.DataType
+import androidx.health.services.client.data.PassiveMonitoringCapabilities
+import androidx.health.services.client.data.event.Event
+import androidx.health.services.client.impl.PassiveMonitoringIpcClient.Companion.getServiceInterface
+import androidx.health.services.client.impl.internal.StatusCallback
+import androidx.health.services.client.impl.internal.WhsConnectionManager
+import androidx.health.services.client.impl.ipc.ServiceOperation
+import androidx.health.services.client.impl.request.BackgroundRegistrationRequest
+import androidx.health.services.client.impl.request.CapabilitiesRequest
+import androidx.health.services.client.impl.request.EventRequest
+import androidx.health.services.client.impl.response.PassiveMonitoringCapabilitiesResponse
+import com.google.common.util.concurrent.Futures
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * Passive monitoring client that interacts with WHS via IPC.
+ *
+ * @hide
+ */
+internal class ServiceBackedPassiveMonitoringClient(private val applicationContext: Context) :
+    PassiveMonitoringClient {
+
+    private val ipcClient: PassiveMonitoringIpcClient =
+        PassiveMonitoringIpcClient(WhsConnectionManager.getInstance(applicationContext))
+
+    override fun registerDataCallback(
+        dataTypes: Set<DataType>,
+        callbackIntent: PendingIntent
+    ): ListenableFuture<Void> {
+        return registerDataCallbackInternal(dataTypes, callbackIntent, callback = null)
+    }
+
+    override fun registerDataCallback(
+        dataTypes: Set<DataType>,
+        callbackIntent: PendingIntent,
+        callback: PassiveMonitoringCallback
+    ): ListenableFuture<Void> {
+        return registerDataCallbackInternal(dataTypes, callbackIntent, callback)
+    }
+
+    override fun unregisterDataCallback(): ListenableFuture<Void> {
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .unregisterDataCallback(
+                        applicationContext.packageName,
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun registerEventCallback(
+        event: Event,
+        callbackIntent: PendingIntent
+    ): ListenableFuture<Void> {
+        val request = EventRequest(applicationContext.packageName, event)
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .registerEventCallback(request, callbackIntent, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override fun unregisterEventCallback(event: Event): ListenableFuture<Void> {
+        val request = EventRequest(applicationContext.packageName, event)
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .unregisterEventCallback(request, StatusCallback(resultFuture))
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+
+    override val capabilities: ListenableFuture<PassiveMonitoringCapabilities>
+        get() {
+            val request = CapabilitiesRequest(applicationContext.packageName)
+            val serviceOperation =
+                ServiceOperation<PassiveMonitoringCapabilitiesResponse> { binder, resultFuture ->
+                    resultFuture.set(getServiceInterface(binder).getCapabilities(request))
+                }
+            return Futures.transform(
+                ipcClient.execute(serviceOperation),
+                { response -> response?.passiveMonitoringCapabilities },
+                ContextCompat.getMainExecutor(applicationContext)
+            )
+        }
+
+    private fun registerDataCallbackInternal(
+        dataTypes: Set<DataType>,
+        callbackIntent: PendingIntent,
+        callback: PassiveMonitoringCallback?
+    ): ListenableFuture<Void> {
+        val request = BackgroundRegistrationRequest(applicationContext.packageName, dataTypes)
+        val serviceOperation =
+            ServiceOperation<Void> { binder, resultFuture ->
+                getServiceInterface(binder)
+                    .registerDataCallback(
+                        request,
+                        callbackIntent,
+                        callback?.let { PassiveMonitoringCallbackStub(it) },
+                        StatusCallback(resultFuture)
+                    )
+            }
+        return ipcClient.execute(serviceOperation)
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/ExerciseInfoCallback.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/ExerciseInfoCallback.kt
new file mode 100644
index 0000000..078cc154
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/ExerciseInfoCallback.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.internal
+
+import android.os.RemoteException
+import androidx.health.services.client.data.ExerciseInfo
+import androidx.health.services.client.impl.response.ExerciseInfoResponse
+import com.google.common.util.concurrent.SettableFuture
+
+/**
+ * A callback for ipc invocations dealing with [ExerciseInfo].
+ *
+ * @hide
+ */
+public class ExerciseInfoCallback(private val resultFuture: SettableFuture<ExerciseInfo>) :
+    IExerciseInfoCallback.Stub() {
+
+    @Throws(RemoteException::class)
+    override fun onExerciseInfo(response: ExerciseInfoResponse) {
+        resultFuture.set(response.exerciseInfo)
+    }
+
+    @Throws(RemoteException::class)
+    override fun onFailure(message: String) {
+        resultFuture.setException(Exception(message))
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/StatusCallback.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/StatusCallback.kt
new file mode 100644
index 0000000..89789e6
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/StatusCallback.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.internal
+
+import android.os.RemoteException
+import com.google.common.util.concurrent.SettableFuture
+
+/**
+ * A generic callback for ipc invocations.
+ *
+ * @hide
+ */
+public class StatusCallback(private val resultFuture: SettableFuture<Void>) :
+    IStatusCallback.Stub() {
+
+    @Throws(RemoteException::class)
+    override fun onSuccess() {
+        resultFuture.set(null)
+    }
+
+    @Throws(RemoteException::class)
+    override fun onFailure(msg: String) {
+        resultFuture.setException(Exception(msg))
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/WhsConnectionManager.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/WhsConnectionManager.kt
new file mode 100644
index 0000000..eb701b6
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/internal/WhsConnectionManager.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.internal
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.HandlerThread
+import android.os.Looper
+import android.os.Process
+import androidx.annotation.GuardedBy
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager
+
+/**
+ * Utility to return an instance of connection manager.
+ *
+ * @hide
+ */
+public object WhsConnectionManager {
+
+    private val lock = Any()
+
+    // Suppress StaticFieldLeak; we're only storing application Context.
+    @SuppressLint("StaticFieldLeak")
+    @GuardedBy("lock")
+    private lateinit var instance: ConnectionManager
+
+    @JvmStatic
+    public fun getInstance(context: Context): ConnectionManager {
+        synchronized(lock) {
+            if (!::instance.isInitialized) {
+                val looper = startHandlerThread()
+                instance = ConnectionManager(context.applicationContext, looper)
+            }
+
+            return instance
+        }
+    }
+
+    private fun startHandlerThread(): Looper {
+        val handlerThread =
+            HandlerThread(
+                "WhsConnectionManager",
+                Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE
+            )
+        handlerThread.start()
+        return handlerThread.looper
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java
new file mode 100644
index 0000000..134ffa3
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ApiVersionException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Exception that is thrown when API version requirements are not met.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class ApiVersionException extends ExecutionException {
+
+    private final int mRemoteVersion;
+    private final int mMinVersion;
+
+    public ApiVersionException(int remoteVersion, int minVersion) {
+        super(
+                "Version requirements for calling the method was not met, remoteVersion: "
+                        + remoteVersion
+                        + ", minVersion: "
+                        + minVersion);
+        this.mRemoteVersion = remoteVersion;
+        this.mMinVersion = minVersion;
+    }
+
+    public int getRemoteVersion() {
+        return mRemoteVersion;
+    }
+
+    public int getMinVersion() {
+        return mMinVersion;
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java
new file mode 100644
index 0000000..b417620
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/Client.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.annotation.VisibleForTesting;
+import androidx.health.services.client.impl.ipc.internal.BaseQueueOperation;
+import androidx.health.services.client.impl.ipc.internal.ConnectionConfiguration;
+import androidx.health.services.client.impl.ipc.internal.ConnectionManager;
+import androidx.health.services.client.impl.ipc.internal.ExecutionTracker;
+import androidx.health.services.client.impl.ipc.internal.ListenerKey;
+import androidx.health.services.client.impl.ipc.internal.QueueOperation;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * SDK client for establishing connection to a cross process service.
+ *
+ * <p>Extend this class to create a new client. Each client should represent one connection to AIDL
+ * interface. For user instruction see: go/wear-dd-wcs-sdk
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public abstract class Client {
+
+    /** Interface abstracting extraction of the API version from the binder. */
+    public interface VersionGetter {
+        /** Returns the API version. */
+        Integer readVersion(IBinder binder) throws RemoteException;
+    }
+
+    private static final int UNKNOWN_VERSION = -1;
+
+    private final ConnectionConfiguration mConnectionConfiguration;
+    private final ConnectionManager mConnectionManager;
+    private final ServiceOperation<Integer> mApiVersionOperation;
+
+    @VisibleForTesting volatile int mCurrentVersion = UNKNOWN_VERSION;
+
+    public Client(
+            ClientConfiguration clientConfiguration,
+            ConnectionManager connectionManager,
+            VersionGetter versionGetter) {
+        QueueOperation versionOperation =
+                new QueueOperation() {
+                    @Override
+                    public void execute(IBinder binder) throws RemoteException {
+                        mCurrentVersion = versionGetter.readVersion(binder);
+                    }
+
+                    @Override
+                    public void setException(Throwable exception) {}
+
+                    @Override
+                    public QueueOperation trackExecution(ExecutionTracker tracker) {
+                        return this;
+                    }
+
+                    @Override
+                    public ConnectionConfiguration getConnectionConfiguration() {
+                        return Client.this.getConnectionConfiguration();
+                    }
+                };
+        this.mConnectionConfiguration =
+                new ConnectionConfiguration(
+                        clientConfiguration.getServicePackageName(),
+                        clientConfiguration.getApiClientName(),
+                        clientConfiguration.getBindAction(),
+                        versionOperation);
+        this.mConnectionManager = connectionManager;
+        this.mApiVersionOperation =
+                (binder, resultFuture) -> resultFuture.set(versionGetter.readVersion(binder));
+    }
+
+    /**
+     * Executes given operation against a IPC service defined by {@code clientConfiguration}.
+     *
+     * @param operation Operation that will be executed against the service
+     * @param <R> Type of returned variable
+     * @return {@link ListenableFuture<R>} with the result of the operation or an exception if the
+     *     execution fails.
+     */
+    protected <R> ListenableFuture<R> execute(ServiceOperation<R> operation) {
+        SettableFuture<R> settableFuture = SettableFuture.create();
+        mConnectionManager.scheduleForExecution(
+                createQueueOperation(operation, mConnectionConfiguration, settableFuture));
+        return settableFuture;
+    }
+
+    protected <R> ListenableFuture<R> executeWithVersionCheck(
+            ServiceOperation<R> operation, int minApiVersion) {
+        if (mCurrentVersion == UNKNOWN_VERSION) {
+            SettableFuture<R> settableFuture = SettableFuture.create();
+            ListenableFuture<Integer> versionFuture = execute(mApiVersionOperation);
+            Futures.addCallback(
+                    versionFuture,
+                    new FutureCallback<Integer>() {
+                        @Override
+                        public void onSuccess(@Nullable Integer remoteVersion) {
+                            mCurrentVersion =
+                                    remoteVersion == null ? UNKNOWN_VERSION : remoteVersion;
+                            if (mCurrentVersion < minApiVersion) {
+                                settableFuture.setException(
+                                        getApiVersionCheckFailureException(
+                                                mCurrentVersion, minApiVersion));
+                            } else {
+                                getConnectionManager()
+                                        .scheduleForExecution(
+                                                createQueueOperation(
+                                                        operation,
+                                                        getConnectionConfiguration(),
+                                                        settableFuture));
+                            }
+                        }
+
+                        @Override
+                        public void onFailure(Throwable throwable) {
+                            settableFuture.setException(throwable);
+                        }
+                    },
+                    MoreExecutors.directExecutor());
+            return settableFuture;
+        } else if (mCurrentVersion >= minApiVersion) {
+            return execute(operation);
+        } else {
+            // This empty operation is executed just to connect to the service. If we didn't connect
+            // it
+            // could happen that we won't detect change in the API version.
+            mConnectionManager.scheduleForExecution(
+                    new BaseQueueOperation(mConnectionConfiguration));
+            return Futures.immediateFailedFuture(
+                    getApiVersionCheckFailureException(mCurrentVersion, minApiVersion));
+        }
+    }
+
+    /**
+     * Registers a listener by executing the provided {@link ServiceOperation}.
+     *
+     * <p>The provided {@code registerListenerOperation} will be stored for every unique {@code
+     * listenerKey} and re-executed when connection is lost.
+     *
+     * @param listenerKey Key based on which listeners will be distinguished.
+     * @param registerListenerOperation Method that registers the listener, can by any {@link
+     *     ServiceOperation}.
+     * @param <R> Type of return value returned in the future.
+     * @return {@link ListenableFuture<R>} with the result of the operation or an exception if the
+     *     execution fails.
+     */
+    protected <R> ListenableFuture<R> registerListener(
+            ListenerKey listenerKey, ServiceOperation<R> registerListenerOperation) {
+        SettableFuture<R> settableFuture = SettableFuture.create();
+        mConnectionManager.registerListener(
+                listenerKey,
+                createQueueOperation(
+                        registerListenerOperation, mConnectionConfiguration, settableFuture));
+        return settableFuture;
+    }
+
+    /**
+     * Unregisters a listener by executing the provided {@link ServiceOperation}.
+     *
+     * @param listenerKey Key based on which listeners will be distinguished.
+     * @param unregisterListenerOperation Method that unregisters the listener, can by any {@link
+     *     ServiceOperation}.
+     * @param <R> Type of return value returned in the future.
+     * @return {@link ListenableFuture<R>} with the result of the operation or an exception if the
+     *     execution fails.
+     */
+    protected <R> ListenableFuture<R> unregisterListener(
+            ListenerKey listenerKey, ServiceOperation<R> unregisterListenerOperation) {
+        SettableFuture<R> settableFuture = SettableFuture.create();
+        mConnectionManager.unregisterListener(
+                listenerKey,
+                createQueueOperation(
+                        unregisterListenerOperation, getConnectionConfiguration(), settableFuture));
+        return settableFuture;
+    }
+
+    protected Exception getApiVersionCheckFailureException(int currentVersion, int minApiVersion) {
+        return new ApiVersionException(currentVersion, minApiVersion);
+    }
+
+    ConnectionConfiguration getConnectionConfiguration() {
+        return mConnectionConfiguration;
+    }
+
+    ConnectionManager getConnectionManager() {
+        return mConnectionManager;
+    }
+
+    private static <R> QueueOperation createQueueOperation(
+            ServiceOperation<R> operation,
+            ConnectionConfiguration connectionConfiguration,
+            SettableFuture<R> settableFuture) {
+        return new BaseQueueOperation(connectionConfiguration) {
+            @Override
+            public void execute(IBinder binder) throws RemoteException {
+                operation.execute(binder, settableFuture);
+            }
+
+            @Override
+            public void setException(Throwable exception) {
+                settableFuture.setException(exception);
+            }
+
+            @Override
+            public QueueOperation trackExecution(ExecutionTracker tracker) {
+                tracker.track(settableFuture);
+                return this;
+            }
+        };
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java
new file mode 100644
index 0000000..cf824d1
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ClientConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+/**
+ * An interface that provides basic information about the IPC service. This is required for building
+ * the service in {@link Client}.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class ClientConfiguration {
+    private final String mServicePackageName;
+    private final String mBindAction;
+    private final String mApiClientName;
+
+    public ClientConfiguration(String apiClientName, String servicePackageName, String bindAction) {
+        this.mServicePackageName = servicePackageName;
+        this.mBindAction = bindAction;
+        this.mApiClientName = apiClientName;
+    }
+
+    /** Returns the application package of the remote service. */
+    public String getServicePackageName() {
+        return mServicePackageName;
+    }
+
+    /** Returns the action used to bind to the remote service. */
+    public String getBindAction() {
+        return mBindAction;
+    }
+
+    /** Returns name of the service, use for logging and debugging only. */
+    public String getApiClientName() {
+        return mApiClientName;
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java
new file mode 100644
index 0000000..c15503e
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * General operation that will be executed against given service. A new operation can be created by
+ * implementing this interface. User is then responsible for setting the result Future with the
+ * result value.
+ *
+ * @param <R> Type of the returned value.
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public interface ServiceOperation<R> {
+
+    /**
+     * Method executed against the service.
+     *
+     * @param binder Already connected binder to the target service.
+     * @param resultFuture A {@link SettableFuture} that should be set with the result.
+     */
+    void execute(IBinder binder, SettableFuture<R> resultFuture) throws RemoteException;
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java
new file mode 100644
index 0000000..079d509
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/BaseQueueOperation.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+/**
+ * Abstract implementation of QueueOperation that accepts {@link ConnectionConfiguration} describing
+ * the service where it will be executed.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class BaseQueueOperation implements QueueOperation {
+    private final ConnectionConfiguration mConnectionConfiguration;
+
+    public BaseQueueOperation(ConnectionConfiguration connectionConfiguration) {
+        this.mConnectionConfiguration = checkNotNull(connectionConfiguration);
+    }
+
+    @Override
+    public void execute(IBinder binder) throws RemoteException {}
+
+    @Override
+    public void setException(Throwable exception) {}
+
+    @Override
+    public QueueOperation trackExecution(ExecutionTracker tracker) {
+        return this;
+    }
+
+    /** Configuration of the service connection on which the operation will be executed. */
+    @Override
+    public ConnectionConfiguration getConnectionConfiguration() {
+        return mConnectionConfiguration;
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java
new file mode 100644
index 0000000..9b6c42b
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.health.services.client.impl.ipc.ClientConfiguration;
+
+/**
+ * Internal representation of configuration of IPC service connection.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public final class ConnectionConfiguration {
+    private final String mPackageName;
+    private final String mClientName;
+    private final String mBindAction;
+    private final QueueOperation mRefreshVersionOperation;
+
+    public ConnectionConfiguration(
+            String packageName,
+            String clientName,
+            String bindAction,
+            QueueOperation refreshVersionOperation) {
+        this.mPackageName = checkNotNull(packageName);
+        this.mClientName = checkNotNull(clientName);
+        this.mBindAction = checkNotNull(bindAction);
+        this.mRefreshVersionOperation = checkNotNull(refreshVersionOperation);
+    }
+
+    /** A key that defines the connection among other IPC connections. It should be unique. */
+    String getKey() {
+        return String.format("%s#%s#%s", mClientName, mPackageName, mBindAction);
+    }
+
+    /** API Client name defined in the {@link ClientConfiguration#getApiClientName()}. */
+    String getClientName() {
+        return mClientName;
+    }
+
+    /**
+     * An action used to bind to the remote service. Taken from {@link
+     * ClientConfiguration#getBindAction()}.
+     */
+    String getBindAction() {
+        return mBindAction;
+    }
+
+    /**
+     * Package name of remote service. Taken from {@link
+     * ClientConfiguration#getServicePackageName()}.
+     */
+    String getPackageName() {
+        return mPackageName;
+    }
+
+    QueueOperation getRefreshVersionOperation() {
+        return mRefreshVersionOperation;
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java
new file mode 100644
index 0000000..739a531
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ConnectionManager.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manages connections to a service in a different process.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {
+    private static final String TAG = "ConnectionManager";
+
+    private static final int MSG_CONNECTED = 1;
+    private static final int MSG_DISCONNECTED = 2;
+    private static final int MSG_EXECUTE = 3;
+    private static final int MSG_REGISTER_LISTENER = 4;
+    private static final int MSG_UNREGISTER_LISTENER = 5;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Map<String, ServiceConnection> mServiceConnectionMap = new HashMap<>();
+
+    private boolean mBindToSelfEnabled;
+
+    public ConnectionManager(Context context, Looper looper) {
+        this.mContext = context;
+        this.mHandler = new Handler(looper, this);
+    }
+
+    /**
+     * Schedules operation for execution
+     *
+     * @param operation Operation prepared for scheduling on the connection queue.
+     */
+    public void scheduleForExecution(QueueOperation operation) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_EXECUTE, operation));
+    }
+
+    /**
+     * Registers a listener by executing an operation represented by the {@link QueueOperation}.
+     *
+     * @param listenerKey Key based on which listeners will be distinguished.
+     * @param registerOperation Queue operation executed against the corresponding connection to
+     *     register the listener. Will be used to re-register when connection is lost.
+     */
+    public void registerListener(ListenerKey listenerKey, QueueOperation registerOperation) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(
+                        MSG_REGISTER_LISTENER, new ListenerHolder(listenerKey, registerOperation)));
+    }
+
+    /**
+     * Unregisters a listener by executing an operation represented by the {@link QueueOperation}.
+     *
+     * @param listenerKey Key based on which listeners will be distinguished.
+     * @param unregisterOperation Queue operation executed against the corresponding connection to
+     *     unregister the listener.
+     */
+    public void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(
+                        MSG_UNREGISTER_LISTENER,
+                        new ListenerHolder(listenerKey, unregisterOperation)));
+    }
+
+    @Override
+    public void onConnected(ServiceConnection connection) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_CONNECTED, connection));
+    }
+
+    @Override
+    public void onDisconnected(ServiceConnection connection, long reconnectDelayMs) {
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(MSG_DISCONNECTED, connection), reconnectDelayMs);
+    }
+
+    @Override
+    public boolean isBindToSelfEnabled() {
+        return mBindToSelfEnabled;
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_CONNECTED:
+                ServiceConnection serviceConnection = ((ServiceConnection) msg.obj);
+                serviceConnection.reRegisterAllListeners();
+                serviceConnection.refreshServiceVersion();
+                serviceConnection.flushQueue();
+                return true;
+            case MSG_DISCONNECTED:
+                ((ServiceConnection) msg.obj).maybeReconnect();
+                return true;
+            case MSG_EXECUTE:
+                QueueOperation queueOperation = (QueueOperation) msg.obj;
+                getConnection(queueOperation.getConnectionConfiguration()).enqueue(queueOperation);
+                return true;
+            case MSG_REGISTER_LISTENER:
+                ListenerHolder registerListenerHolder = (ListenerHolder) msg.obj;
+                getConnection(
+                                registerListenerHolder
+                                        .getListenerOperation()
+                                        .getConnectionConfiguration())
+                        .registerListener(
+                                registerListenerHolder.getListenerKey(),
+                                registerListenerHolder.getListenerOperation());
+                return true;
+            case MSG_UNREGISTER_LISTENER:
+                ListenerHolder unregisterListenerHolder = (ListenerHolder) msg.obj;
+                getConnection(
+                                unregisterListenerHolder
+                                        .getListenerOperation()
+                                        .getConnectionConfiguration())
+                        .unregisterListener(
+                                unregisterListenerHolder.getListenerKey(),
+                                unregisterListenerHolder.getListenerOperation());
+                return true;
+            default:
+                Log.e(TAG, "Received unknown message: " + msg.what);
+                return false;
+        }
+    }
+
+    public void setBindToSelf(boolean bindToSelfEnabled) {
+        this.mBindToSelfEnabled = bindToSelfEnabled;
+    }
+
+    private ServiceConnection getConnection(ConnectionConfiguration connectionConfiguration) {
+        String connectionKey = connectionConfiguration.getKey();
+        ServiceConnection serviceConnection = mServiceConnectionMap.get(connectionKey);
+        if (serviceConnection == null) {
+            serviceConnection =
+                    new ServiceConnection(
+                            mContext, connectionConfiguration, new DefaultExecutionTracker(), this);
+            mServiceConnectionMap.put(connectionKey, serviceConnection);
+        }
+        return serviceConnection;
+    }
+
+    private static class ListenerHolder {
+        private final ListenerKey mListenerKey;
+        private final QueueOperation mListenerOperation;
+
+        ListenerHolder(ListenerKey listenerKey, QueueOperation listenerOperation) {
+            this.mListenerKey = listenerKey;
+            this.mListenerOperation = listenerOperation;
+        }
+
+        ListenerKey getListenerKey() {
+            return mListenerKey;
+        }
+
+        QueueOperation getListenerOperation() {
+            return mListenerOperation;
+        }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java
new file mode 100644
index 0000000..c8b527e
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/DefaultExecutionTracker.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Default implementation of {@link ExecutionTracker}.
+ *
+ * @hide
+ */
+@SuppressWarnings("ExecutorTaskName")
+@RestrictTo(Scope.LIBRARY)
+public class DefaultExecutionTracker implements ExecutionTracker {
+    private final Set<SettableFuture<?>> mFuturesInProgress = new HashSet<>();
+
+    @Override
+    public void track(SettableFuture<?> future) {
+        mFuturesInProgress.add(future);
+        future.addListener(() -> mFuturesInProgress.remove(future), MoreExecutors.directExecutor());
+    }
+
+    @Override
+    public void cancelPendingFutures(Throwable throwable) {
+        for (SettableFuture<?> future : mFuturesInProgress) {
+            future.setException(throwable);
+        }
+        mFuturesInProgress.clear();
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java
new file mode 100644
index 0000000..eb9e81d
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ExecutionTracker.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * Tracker for tracking operations that are currently in progress.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public interface ExecutionTracker {
+
+    /** Track given future as in progress. */
+    void track(SettableFuture<?> future);
+
+    /** Cancel all tracked futures with given exception. */
+    void cancelPendingFutures(Throwable throwable);
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java
new file mode 100644
index 0000000..f2960e3
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ListenerKey.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+/**
+ * Unique key to hold listener reference.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public final class ListenerKey {
+    private final Object mListenerKey;
+
+    public ListenerKey(Object listenerKey) {
+        this.mListenerKey = listenerKey;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ListenerKey)) {
+            return false;
+        }
+
+        ListenerKey that = (ListenerKey) o;
+        return mListenerKey.equals(that);
+    }
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(mListenerKey);
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(mListenerKey);
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java
new file mode 100644
index 0000000..6021bdf
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/QueueOperation.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+
+/**
+ * A wrapper for SDK operation that will be executed on a connected binder. It is intended for
+ * scheduling in execution queue.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public interface QueueOperation {
+    /**
+     * Method executed against the service.
+     *
+     * @param binder already connected to the target service.
+     */
+    void execute(IBinder binder) throws RemoteException;
+
+    /** Sets exception as the result of the operation. */
+    void setException(Throwable exception);
+
+    /**
+     * Tracks the operation execution with an {@link ExecutionTracker}.
+     *
+     * @param tracker To track the execution as in progress.
+     */
+    QueueOperation trackExecution(ExecutionTracker tracker);
+
+    /** Returns configuration of the service connection on which the operation will be executed. */
+    ConnectionConfiguration getConnectionConfiguration();
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java
new file mode 100644
index 0000000..fa432bc
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.ipc.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.DeadObjectException;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.annotation.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A class that maintains a connection to IPC backend service. If connection is not available it
+ * uses a queue to store service requests until connection is renewed. One {@link ServiceConnection}
+ * is associated with one AIDL file .
+ *
+ * <p>Note: this class is not thread safe and should be called always from the same thread.
+ *
+ * @hide
+ */
+@NotThreadSafe
+@RestrictTo(Scope.LIBRARY)
+public class ServiceConnection implements android.content.ServiceConnection {
+    private static final String TAG = "ServiceConnection";
+
+    /** Callback for reporting back to the manager. */
+    public interface Callback {
+
+        /** Called when the connection to the server was successfully established. */
+        void onConnected(ServiceConnection connection);
+
+        /**
+         * Called when the connection to the server was lost.
+         *
+         * @param connection Represents this connection to a service.
+         * @param reconnectDelayMs Delay before the caller should try to reconnect this connection.
+         */
+        void onDisconnected(ServiceConnection connection, long reconnectDelayMs);
+
+        /**
+         * Return true if the {@link ServiceConnection} should bind to the service in the same
+         * application for testing reason.
+         */
+        boolean isBindToSelfEnabled();
+    }
+
+    private static final int MAX_RETRIES = 10;
+
+    private final Context mContext;
+    private final Queue<QueueOperation> mOperationQueue = new ConcurrentLinkedQueue<>();
+    private final ConnectionConfiguration mConnectionConfiguration;
+    private final ExecutionTracker mExecutionTracker;
+    private final Map<ListenerKey, QueueOperation> mRegisteredListeners = new HashMap<>();
+    private final Callback mCallback;
+
+    @VisibleForTesting @Nullable IBinder mBinder;
+    private volatile boolean mIsServiceBound;
+    /** Denotes how many times connection to the service failed and we retried. */
+    private int mServiceConnectionRetry;
+
+    ServiceConnection(
+            Context context,
+            ConnectionConfiguration connectionConfiguration,
+            ExecutionTracker executionTracker,
+            Callback callback) {
+        this.mContext = checkNotNull(context);
+        this.mConnectionConfiguration = checkNotNull(connectionConfiguration);
+        this.mExecutionTracker = checkNotNull(executionTracker);
+        this.mCallback = checkNotNull(callback);
+    }
+
+    private String getBindPackageName() {
+        if (mCallback.isBindToSelfEnabled()) {
+            return mContext.getPackageName();
+        } else {
+            return mConnectionConfiguration.getPackageName();
+        }
+    }
+
+    /** Connects to the service. */
+    public void connect() {
+        if (mIsServiceBound) {
+            return;
+        }
+        try {
+            mIsServiceBound =
+                    mContext.bindService(
+                            new Intent()
+                                    .setPackage(getBindPackageName())
+                                    .setAction(mConnectionConfiguration.getBindAction()),
+                            this,
+                            Context.BIND_AUTO_CREATE | Context.BIND_ADJUST_WITH_ACTIVITY);
+        } catch (SecurityException exception) {
+            Log.w(
+                    TAG,
+                    "Failed to bind connection '"
+                            + mConnectionConfiguration.getKey()
+                            + "', no permission or service not found.",
+                    exception);
+            mIsServiceBound = false;
+            mBinder = null;
+            throw exception;
+        }
+
+        if (!mIsServiceBound) {
+            // Service not found or we don't have permission to call it.
+            Log.e(
+                    TAG,
+                    "Connection to service is not available for package '"
+                            + mConnectionConfiguration.getPackageName()
+                            + "' and action '"
+                            + mConnectionConfiguration.getBindAction()
+                            + "'.");
+            handleNonRetriableDisconnection(new CancellationException("Service not available"));
+        }
+    }
+
+    private void handleNonRetriableDisconnection(Throwable throwable) {
+        // Set retry count to maximum to prevent retries
+        mServiceConnectionRetry = MAX_RETRIES;
+        handleRetriableDisconnection(throwable);
+    }
+
+    private synchronized void handleRetriableDisconnection(Throwable throwable) {
+        if (isConnected()) {
+            // Connection is already re-established. So just return.
+            Log.w(TAG, "Connection is already re-established. No need to reconnect again");
+            return;
+        }
+
+        clearConnection(throwable);
+
+        if (mServiceConnectionRetry < MAX_RETRIES) {
+            Log.w(
+                    TAG,
+                    "WCS SDK Client '"
+                            + mConnectionConfiguration.getClientName()
+                            + "' disconnected, retrying connection. Retry attempt: "
+                            + mServiceConnectionRetry,
+                    throwable);
+            mCallback.onDisconnected(this, getRetryDelayMs(mServiceConnectionRetry));
+        } else {
+            Log.e(TAG, "Connection disconnected and maximum number of retries reached.", throwable);
+        }
+    }
+
+    private static int getRetryDelayMs(int retryNumber) {
+        // Exponential retry delay starting on 200ms.
+        return (200 << retryNumber);
+    }
+
+    private void clearConnection(Throwable throwable) {
+        if (mIsServiceBound) {
+            try {
+                mContext.unbindService(this);
+                mIsServiceBound = false;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Failed to unbind the service. Ignoring and continuing", e);
+            }
+        }
+
+        mBinder = null;
+        mExecutionTracker.cancelPendingFutures(throwable);
+        cancelAllOperationsInQueue(throwable);
+    }
+
+    void enqueue(QueueOperation operation) {
+        if (isConnected()) {
+            execute(operation);
+        } else {
+            mOperationQueue.add(operation);
+            connect();
+        }
+    }
+
+    void registerListener(ListenerKey listenerKey, QueueOperation registerListenerOperation) {
+        mRegisteredListeners.put(listenerKey, registerListenerOperation);
+        if (isConnected()) {
+            enqueue(registerListenerOperation);
+        } else {
+            connect();
+        }
+    }
+
+    void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterListenerOperation) {
+        mRegisteredListeners.remove(listenerKey);
+        enqueue(unregisterListenerOperation);
+    }
+
+    void maybeReconnect() {
+        if (mRegisteredListeners.isEmpty()) {
+            Log.d(
+                    TAG,
+                    "No listeners registered, service "
+                            + mConnectionConfiguration.getClientName()
+                            + " is not automatically reconnected.");
+        } else {
+            mServiceConnectionRetry++;
+            Log.d(
+                    TAG,
+                    "Listeners for service "
+                            + mConnectionConfiguration.getClientName()
+                            + " are registered, reconnecting.");
+            connect();
+        }
+    }
+
+    @VisibleForTesting
+    void execute(QueueOperation operation) {
+        try {
+            operation.trackExecution(mExecutionTracker);
+            operation.execute(checkNotNull(mBinder));
+        } catch (DeadObjectException exception) {
+            handleRetriableDisconnection(exception);
+            // TODO(b/152024821): Consider possible TransactionTooLargeException failure.
+        } catch (RemoteException | RuntimeException exception) {
+            operation.setException(exception);
+        }
+    }
+
+    void reRegisterAllListeners() {
+        for (Map.Entry<ListenerKey, QueueOperation> entry : mRegisteredListeners.entrySet()) {
+            Log.d(TAG, "Re-registering listener: " + entry.getKey());
+            execute(entry.getValue());
+        }
+    }
+
+    void refreshServiceVersion() {
+        mOperationQueue.add(mConnectionConfiguration.getRefreshVersionOperation());
+    }
+
+    void flushQueue() {
+        for (QueueOperation operation : new ArrayList<>(mOperationQueue)) {
+            boolean removed = mOperationQueue.remove(operation);
+            if (removed) {
+                execute(operation);
+            }
+        }
+    }
+
+    private void cancelAllOperationsInQueue(Throwable throwable) {
+        for (QueueOperation operation : new ArrayList<>(mOperationQueue)) {
+            boolean removed = mOperationQueue.remove(operation);
+            if (removed) {
+                operation.setException(throwable);
+                execute(operation);
+            }
+        }
+    }
+
+    private boolean isConnected() {
+        return mBinder != null && mBinder.isBinderAlive();
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName componentName, IBinder binder) {
+        Log.d(TAG, "onServiceConnected(), componentName = " + componentName);
+        if (binder == null) {
+            Log.e(TAG, "Service connected but binder is null.");
+            return;
+        }
+        mServiceConnectionRetry = 0;
+        cleanOnDeath(binder);
+        this.mBinder = binder;
+        mCallback.onConnected(this);
+    }
+
+    private void cleanOnDeath(IBinder binder) {
+        try {
+            binder.linkToDeath(
+                    () -> {
+                        Log.w(
+                                TAG,
+                                "Binder died for client:"
+                                        + mConnectionConfiguration.getClientName());
+                        handleRetriableDisconnection(new CancellationException());
+                    },
+                    /* flags= */ 0);
+        } catch (RemoteException exception) {
+            Log.w(
+                    TAG,
+                    "Cannot link to death, binder already died. Cleaning operations.",
+                    exception);
+            handleRetriableDisconnection(exception);
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName componentName) {
+        Log.d(TAG, "onServiceDisconnected(), componentName = " + componentName);
+        // Service disconnected but binding still exists so it should reconnect automatically.
+    }
+
+    @Override
+    public void onBindingDied(ComponentName name) {
+        Log.e(TAG, "Binding died for client '" + mConnectionConfiguration.getClientName() + "'.");
+        handleRetriableDisconnection(new CancellationException());
+    }
+
+    @Override
+    public void onNullBinding(ComponentName name) {
+        Log.e(
+                TAG,
+                "Cannot bind client '"
+                        + mConnectionConfiguration.getClientName()
+                        + "', binder is null");
+        // This connection will never be usable, don't bother with retries.
+        handleNonRetriableDisconnection(new CancellationException("Null binding"));
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.kt
new file mode 100644
index 0000000..6fc9161
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/AutoPauseAndResumeConfigRequest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Request for enabling/disabling auto pause/resume.
+ *
+ * @hide
+ */
+public data class AutoPauseAndResumeConfigRequest(
+    val packageName: String,
+    val shouldEnable: Boolean,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeInt(if (shouldEnable) 1 else 0)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<AutoPauseAndResumeConfigRequest> =
+            object : Parcelable.Creator<AutoPauseAndResumeConfigRequest> {
+                override fun createFromParcel(source: Parcel): AutoPauseAndResumeConfigRequest? {
+                    return AutoPauseAndResumeConfigRequest(
+                        source.readString() ?: return null,
+                        source.readInt() == 1,
+                    )
+                }
+
+                override fun newArray(size: Int): Array<AutoPauseAndResumeConfigRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.kt
new file mode 100644
index 0000000..2c0296a
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundRegistrationRequest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.DataType
+
+/**
+ * Request for background registration.
+ *
+ * @hide
+ */
+public data class BackgroundRegistrationRequest(
+    val packageName: String,
+    val dataTypes: Set<DataType>,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeTypedList(dataTypes.toList())
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<BackgroundRegistrationRequest> =
+            object : Parcelable.Creator<BackgroundRegistrationRequest> {
+                override fun createFromParcel(source: Parcel): BackgroundRegistrationRequest? {
+                    val packageName = source.readString() ?: return null
+                    val list = ArrayList<DataType>()
+                    source.readTypedList(list, DataType.CREATOR)
+                    return BackgroundRegistrationRequest(packageName, list.toSet())
+                }
+
+                override fun newArray(size: Int): Array<BackgroundRegistrationRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.kt
new file mode 100644
index 0000000..67fcaa8
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/BackgroundUnregistrationRequest.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Request for background unregistration.
+ *
+ * @hide
+ */
+public data class BackgroundUnregistrationRequest(val packageName: String) : Parcelable {
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<BackgroundUnregistrationRequest> =
+            object : Parcelable.Creator<BackgroundUnregistrationRequest> {
+                override fun createFromParcel(source: Parcel): BackgroundUnregistrationRequest? {
+                    val packageName = source.readString() ?: return null
+                    return BackgroundUnregistrationRequest(packageName)
+                }
+
+                override fun newArray(size: Int): Array<BackgroundUnregistrationRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/CapabilitiesRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/CapabilitiesRequest.kt
new file mode 100644
index 0000000..ba837e4
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/CapabilitiesRequest.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Request for capabilities.
+ *
+ * @hide
+ */
+public data class CapabilitiesRequest(val packageName: String) : Parcelable {
+
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<CapabilitiesRequest> =
+            object : Parcelable.Creator<CapabilitiesRequest> {
+                override fun createFromParcel(source: Parcel): CapabilitiesRequest? {
+                    val packageName = source.readString() ?: return null
+                    return CapabilitiesRequest(packageName)
+                }
+
+                override fun newArray(size: Int): Array<CapabilitiesRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/EventRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/EventRequest.kt
new file mode 100644
index 0000000..ddfce39
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/EventRequest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.event.Event
+
+/**
+ * Request for event registration.
+ *
+ * @hide
+ */
+public data class EventRequest(val packageName: String, val event: Event) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeParcelable(event, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<EventRequest> =
+            object : Parcelable.Creator<EventRequest> {
+                override fun createFromParcel(source: Parcel): EventRequest? {
+                    return EventRequest(
+                        source.readString() ?: return null,
+                        source.readParcelable(Event::class.java.classLoader) ?: return null,
+                    )
+                }
+
+                override fun newArray(size: Int): Array<EventRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/ExerciseGoalRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/ExerciseGoalRequest.kt
new file mode 100644
index 0000000..a427c67
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/ExerciseGoalRequest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseGoal
+
+/**
+ * Request for adding a [ExerciseGoal] to an exercise.
+ *
+ * @hide
+ */
+public data class ExerciseGoalRequest(val packageName: String, val exerciseGoal: ExerciseGoal) :
+    Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeParcelable(exerciseGoal, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseGoalRequest> =
+            object : Parcelable.Creator<ExerciseGoalRequest> {
+                override fun createFromParcel(source: Parcel): ExerciseGoalRequest? {
+                    return ExerciseGoalRequest(
+                        source.readString() ?: return null,
+                        source.readParcelable(ExerciseGoal::class.java.classLoader) ?: return null,
+                    )
+                }
+
+                override fun newArray(size: Int): Array<ExerciseGoalRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureRegistrationRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureRegistrationRequest.kt
new file mode 100644
index 0000000..2d88026
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureRegistrationRequest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.DataType
+
+/**
+ * Request for measure registration.
+ *
+ * @hide
+ */
+public data class MeasureRegistrationRequest(
+    val packageName: String,
+    val dataType: DataType,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeParcelable(dataType, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<MeasureRegistrationRequest> =
+            object : Parcelable.Creator<MeasureRegistrationRequest> {
+                override fun createFromParcel(source: Parcel): MeasureRegistrationRequest? {
+                    return MeasureRegistrationRequest(
+                        source.readString() ?: return null,
+                        source.readParcelable(DataType::class.java.classLoader) ?: return null
+                    )
+                }
+
+                override fun newArray(size: Int): Array<MeasureRegistrationRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.kt
new file mode 100644
index 0000000..55e8054
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/MeasureUnregistrationRequest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.DataType
+
+/**
+ * Request for measure unregistration.
+ *
+ * @hide
+ */
+public data class MeasureUnregistrationRequest(
+    val packageName: String,
+    val dataType: DataType,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeParcelable(dataType, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<MeasureUnregistrationRequest> =
+            object : Parcelable.Creator<MeasureUnregistrationRequest> {
+                override fun createFromParcel(source: Parcel): MeasureUnregistrationRequest? {
+                    val packageName = source.readString() ?: return null
+                    val dataType =
+                        source.readParcelable<DataType>(DataType::class.java.classLoader)
+                            ?: return null
+                    return MeasureUnregistrationRequest(packageName, dataType)
+                }
+
+                override fun newArray(size: Int): Array<MeasureUnregistrationRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/StartExerciseRequest.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/StartExerciseRequest.kt
new file mode 100644
index 0000000..d67b359
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/request/StartExerciseRequest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.request
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseConfig
+
+/**
+ * Request for starting an exercise.
+ *
+ * @hide
+ */
+public data class StartExerciseRequest(
+    val packageName: String,
+    val exerciseConfig: ExerciseConfig,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(packageName)
+        dest.writeParcelable(exerciseConfig, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<StartExerciseRequest> =
+            object : Parcelable.Creator<StartExerciseRequest> {
+                override fun createFromParcel(source: Parcel): StartExerciseRequest? {
+                    val packageName = source.readString() ?: return null
+                    val parcelable =
+                        source.readParcelable<ExerciseConfig>(
+                            ExerciseConfig::class.java.classLoader
+                        )
+                            ?: return null
+                    return StartExerciseRequest(packageName, parcelable)
+                }
+
+                override fun newArray(size: Int): Array<StartExerciseRequest?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/AvailabilityResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/AvailabilityResponse.kt
new file mode 100644
index 0000000..3a3ccf6
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/AvailabilityResponse.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.Availability
+import androidx.health.services.client.data.DataType
+
+/**
+ * Response sent on MeasureCallback with a [DataType] and its associated [Availability] status.
+ *
+ * @hide
+ */
+public data class AvailabilityResponse(
+    /** [DataType] of the [AvailabilityResponse]. */
+    val dataType: DataType,
+    /** [Availability] of the [AvailabilityResponse]. */
+    val availability: Availability,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(dataType, flags)
+        dest.writeInt(availability.id)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<AvailabilityResponse> =
+            object : Parcelable.Creator<AvailabilityResponse> {
+                override fun createFromParcel(source: Parcel): AvailabilityResponse? {
+                    val parcelable =
+                        source.readParcelable<DataType>(DataType::class.java.classLoader)
+                            ?: return null
+                    val availability = Availability.fromId(source.readInt()) ?: return null
+                    return AvailabilityResponse(parcelable, availability)
+                }
+
+                override fun newArray(size: Int): Array<AvailabilityResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/CapabilitiesResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/CapabilitiesResponse.kt
new file mode 100644
index 0000000..213a060
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/CapabilitiesResponse.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.Capabilities
+
+/**
+ * Response containing the capabilities of WHS client on the device.
+ *
+ * @hide
+ */
+public data class CapabilitiesResponse(
+    /** [Capabilities] supported by this device. */
+    val capabilities: Capabilities,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(capabilities, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<CapabilitiesResponse> =
+            object : Parcelable.Creator<CapabilitiesResponse> {
+                override fun createFromParcel(source: Parcel): CapabilitiesResponse? {
+                    val parcelable =
+                        source.readParcelable<Capabilities>(Capabilities::class.java.classLoader)
+                            ?: return null
+                    return CapabilitiesResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<CapabilitiesResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/DataPointsResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/DataPointsResponse.kt
new file mode 100644
index 0000000..0b30f6d
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/DataPointsResponse.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.DataPoint
+
+/**
+ * Response sent on MeasureCallback when new [DataPoints] [DataPoint] are available.
+ *
+ * @hide
+ */
+public data class DataPointsResponse(val dataPoints: List<DataPoint>) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeTypedList(dataPoints)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<DataPointsResponse> =
+            object : Parcelable.Creator<DataPointsResponse> {
+                override fun createFromParcel(source: Parcel): DataPointsResponse? {
+                    val list = ArrayList<DataPoint>()
+                    source.readTypedList(list, DataPoint.CREATOR)
+                    return DataPointsResponse(list)
+                }
+
+                override fun newArray(size: Int): Array<DataPointsResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseInfoResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseInfoResponse.kt
new file mode 100644
index 0000000..7a44767
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseInfoResponse.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseInfo
+
+/**
+ * Response containing [ExerciseInfo] when changed.
+ *
+ * @hide
+ */
+public data class ExerciseInfoResponse(val exerciseInfo: ExerciseInfo) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(exerciseInfo, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseInfoResponse> =
+            object : Parcelable.Creator<ExerciseInfoResponse> {
+                override fun createFromParcel(source: Parcel): ExerciseInfoResponse? {
+                    val parcelable: ExerciseInfo =
+                        source.readParcelable(ExerciseInfo::class.java.classLoader) ?: return null
+                    return ExerciseInfoResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<ExerciseInfoResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.kt
new file mode 100644
index 0000000..769346d
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseLapSummaryResponse.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseLapSummary
+
+/**
+ * Response containing [ExerciseLapSummary] when it's updated.
+ *
+ * @hide
+ */
+public data class ExerciseLapSummaryResponse(val exerciseLapSummary: ExerciseLapSummary) :
+    Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(exerciseLapSummary, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseLapSummaryResponse> =
+            object : Parcelable.Creator<ExerciseLapSummaryResponse> {
+                override fun createFromParcel(source: Parcel): ExerciseLapSummaryResponse? {
+                    val parcelable =
+                        source.readParcelable<ExerciseLapSummary>(
+                            ExerciseLapSummary::class.java.classLoader
+                        )
+                            ?: return null
+                    return ExerciseLapSummaryResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<ExerciseLapSummaryResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseUpdateResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseUpdateResponse.kt
new file mode 100644
index 0000000..6c800d4
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/ExerciseUpdateResponse.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.ExerciseUpdate
+
+/**
+ * Response containing [ExerciseUpdate] when it's updated.
+ *
+ * @hide
+ */
+public data class ExerciseUpdateResponse(val exerciseUpdate: ExerciseUpdate) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(exerciseUpdate, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<ExerciseUpdateResponse> =
+            object : Parcelable.Creator<ExerciseUpdateResponse> {
+                override fun createFromParcel(source: Parcel): ExerciseUpdateResponse? {
+                    val parcelable =
+                        source.readParcelable<ExerciseUpdate>(
+                            ExerciseUpdate::class.java.classLoader
+                        )
+                            ?: return null
+                    return ExerciseUpdateResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<ExerciseUpdateResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.kt
new file mode 100644
index 0000000..12f80e3
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/MeasureCapabilitiesResponse.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.MeasureCapabilities
+
+/**
+ * Response containing the capabilities of WHS client on the device.
+ *
+ * @hide
+ */
+public data class MeasureCapabilitiesResponse(
+    /** [MeasureCapabilities] supported by this device. */
+    val measureCapabilities: MeasureCapabilities,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(measureCapabilities, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<MeasureCapabilitiesResponse> =
+            object : Parcelable.Creator<MeasureCapabilitiesResponse> {
+                override fun createFromParcel(source: Parcel): MeasureCapabilitiesResponse? {
+                    val parcelable =
+                        source.readParcelable<MeasureCapabilities>(
+                            MeasureCapabilities::class.java.classLoader
+                        )
+                            ?: return null
+                    return MeasureCapabilitiesResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<MeasureCapabilitiesResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveActivityStateResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveActivityStateResponse.kt
new file mode 100644
index 0000000..77e98b5
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveActivityStateResponse.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.PassiveActivityState
+
+/**
+ * Response containing [PassiveActivityState].
+ *
+ * @hide
+ */
+public data class PassiveActivityStateResponse(val passiveActivityState: PassiveActivityState) :
+    Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(passiveActivityState, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<PassiveActivityStateResponse> =
+            object : Parcelable.Creator<PassiveActivityStateResponse> {
+                override fun createFromParcel(source: Parcel): PassiveActivityStateResponse? {
+                    val parcelable =
+                        source.readParcelable<PassiveActivityState>(
+                            PassiveActivityState::class.java.classLoader
+                        )
+                            ?: return null
+                    return PassiveActivityStateResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<PassiveActivityStateResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.kt
new file mode 100644
index 0000000..753735e
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/response/PassiveMonitoringCapabilitiesResponse.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.impl.response
+
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.health.services.client.data.PassiveMonitoringCapabilities
+
+/**
+ * Response containing the capabilities of WHS client on the device.
+ *
+ * @hide
+ */
+public data class PassiveMonitoringCapabilitiesResponse(
+    /** [PassiveMonitoringCapabilities] supported by this device. */
+    val passiveMonitoringCapabilities: PassiveMonitoringCapabilities,
+) : Parcelable {
+    override fun describeContents(): Int = 0
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeParcelable(passiveMonitoringCapabilities, flags)
+    }
+
+    public companion object {
+        @JvmField
+        public val CREATOR: Parcelable.Creator<PassiveMonitoringCapabilitiesResponse> =
+            object : Parcelable.Creator<PassiveMonitoringCapabilitiesResponse> {
+                override fun createFromParcel(
+                    source: Parcel
+                ): PassiveMonitoringCapabilitiesResponse? {
+                    val parcelable =
+                        source.readParcelable<PassiveMonitoringCapabilities>(
+                            PassiveMonitoringCapabilities::class.java.classLoader
+                        )
+                            ?: return null
+                    return PassiveMonitoringCapabilitiesResponse(parcelable)
+                }
+
+                override fun newArray(size: Int): Array<PassiveMonitoringCapabilitiesResponse?> {
+                    return arrayOfNulls(size)
+                }
+            }
+    }
+}
diff --git a/health/health-services-client/src/main/androidx/health/package-info.java b/health/health-services-client/src/main/java/androidx/health/services/client/package-info.java
similarity index 82%
copy from health/health-services-client/src/main/androidx/health/package-info.java
copy to health/health-services-client/src/main/java/androidx/health/services/client/package-info.java
index 2aa2c9c..09f9b13 100644
--- a/health/health-services-client/src/main/androidx/health/package-info.java
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
  */
 
 /**
- * Insert package level documentation here
+ * This package contains top level interfaces for the Health Services client.
  */
 package androidx.health.services.client;
 
diff --git a/media/media/api/current.txt b/media/media/api/current.txt
index ab43c37..e82dbe2 100644
--- a/media/media/api/current.txt
+++ b/media/media/api/current.txt
@@ -729,6 +729,7 @@
     field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
     field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
     field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
     field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
diff --git a/media/media/api/public_plus_experimental_current.txt b/media/media/api/public_plus_experimental_current.txt
index cf5874c..d9037ca 100644
--- a/media/media/api/public_plus_experimental_current.txt
+++ b/media/media/api/public_plus_experimental_current.txt
@@ -729,6 +729,7 @@
     field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
     field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
     field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
     field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
diff --git a/media/media/api/restricted_current.txt b/media/media/api/restricted_current.txt
index 3f5c9d9..bd39a46 100644
--- a/media/media/api/restricted_current.txt
+++ b/media/media/api/restricted_current.txt
@@ -761,6 +761,7 @@
     field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
     field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
     field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
     field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
     field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
diff --git a/media/media/src/main/java/androidx/media/utils/MediaConstants.java b/media/media/src/main/java/androidx/media/utils/MediaConstants.java
index 8d81004..bd04425 100644
--- a/media/media/src/main/java/androidx/media/utils/MediaConstants.java
+++ b/media/media/src/main/java/androidx/media/utils/MediaConstants.java
@@ -113,7 +113,7 @@
     /**
      * Bundle key used for media content id in {@link MediaMetadataCompat metadata}, should contain
      * the same ID provided to Media Actions Catalog in reference to this title (e.g., episode,
-     * movie). Google uses this information to allow users to resume watching this title on your app
+     * movie). This information can be used to allow users to resume watching this title on your app
      * across the supported surfaces (e.g., Android TV's Play Next row)
      *
      * <p>TYPE: String
@@ -126,12 +126,10 @@
 
     /**
      * Bundle key used for next episode's media content ID in {@link MediaMetadataCompat metadata},
-     * following the same ID and format provided to
-     * <a href="https://developers.google.com/actions/media">Media Actions Catalog</a> in reference
-     * to the next episode of the current title episode. Google uses this information to allow users
-     * to resume watching the next episode of this title on your app once the current episode ends
-     * across the supported surfaces (e.g., Android TV's Play Next row). This can be left blank for
-     * movies.
+     * following the same ID and format provided to Media Actions Catalog in reference to the next
+     * episode of the current title episode. This information can be used to allow users to resume
+     * watching the next episode of this title on your app once the current episode ends across the
+     * supported surfaces (e.g., Android TV's Play Next row). This can be left blank for movies.
      *
      * <p>TYPE: String
      *
@@ -142,6 +140,22 @@
             "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
 
     /**
+     * Bundle key used for the TV series's media content ID in {@link MediaMetadataCompat metadata},
+     * following the same ID and format provided to Media Actions Catalog</a> in reference to the
+     * TV series of the title episode. This information can be used to allow users to resume
+     * watching the current episode or next episode of this title on your app across the
+     * supported surfaces (e.g., Android TV's Play Next row). This value is only valid for TV
+     * Episode content type.
+     *
+     * <p>TYPE: String
+     *
+     * @see MediaMetadataCompat
+     */
+    @SuppressLint("IntentName")
+    public static final String METADATA_KEY_SERIES_CONTENT_ID =
+            "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+
+    /**
      * Key sent through a key-value mapping in {@link MediaMetadataCompat#getLong(String)} or in the
      * {@link MediaDescriptionCompat#getExtras()} bundle to the hosting {@link MediaBrowserCompat}
      * to indicate that the corresponding {@link MediaMetadataCompat} or {@link
diff --git a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
index 6bf9217..6f7d3de 100644
--- a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
+++ b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
@@ -58,6 +58,7 @@
                         selected = entryRoute == route,
                         onClick = {
                             navController.navigate(route) {
+                                launchSingleTop = true
                                 restoreState = true
                                 popUpTo(navController.graph.startDestinationId) {
                                     saveState = true
diff --git a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
index 3f63801..e385658 100644
--- a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
+++ b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt
@@ -62,7 +62,7 @@
      */
     @JvmStatic
     public fun onNavDestinationSelected(item: MenuItem, navController: NavController): Boolean {
-        val builder = NavOptions.Builder().setLaunchSingleTop(true)
+        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)
         if (
             navController.currentDestination!!.parent!!.findNode(item.itemId)
             is ActivityNavigator.Destination
@@ -78,7 +78,11 @@
                 .setPopExitAnim(R.animator.nav_default_pop_exit_anim)
         }
         if (item.order and Menu.CATEGORY_SECONDARY == 0) {
-            builder.setPopUpTo(findStartDestination(navController.graph).id, false)
+            builder.setPopUpTo(
+                findStartDestination(navController.graph).id,
+                inclusive = false,
+                saveState = true
+            )
         }
         val options = builder.build()
         return try {
diff --git a/settings.gradle b/settings.gradle
index 183c95f..48fb65e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -384,6 +384,10 @@
 includeProject(":emoji2:emoji2-views", "emoji2/emoji2-views", [BuildType.MAIN])
 includeProject(":emoji2:emoji2-views-helper", "emoji2/emoji2-views-helper", [BuildType.MAIN])
 includeProject(":emoji2:emoji2-benchmark", "emoji2/emoji2-benchmark", [BuildType.MAIN])
+includeProject(":emoji2:integration-tests:init-disabled-macrobenchmark", "emoji2/integration-tests/init-disabled-macrobenchmark", [BuildType.MAIN])
+includeProject(":emoji2:integration-tests:init-disabled-macrobenchmark-target", "emoji2/integration-tests/init-disabled-macrobenchmark-target", [BuildType.MAIN])
+includeProject(":emoji2:integration-tests:init-enabled-macrobenchmark", "emoji2/integration-tests/init-enabled-macrobenchmark", [BuildType.MAIN])
+includeProject(":emoji2:integration-tests:init-enabled-macrobenchmark-target", "emoji2/integration-tests/init-enabled-macrobenchmark-target", [BuildType.MAIN])
 includeProject(":enterprise-feedback", "enterprise/feedback", [BuildType.MAIN])
 includeProject(":enterprise-feedback-testing", "enterprise/feedback/testing", [BuildType.MAIN])
 includeProject(":exifinterface:exifinterface", "exifinterface/exifinterface", [BuildType.MAIN])
diff --git a/slices/core/src/main/res/values-af/strings.xml b/slices/core/src/main/res/values-af/strings.xml
index 1619490..c6a4763 100644
--- a/slices/core/src/main/res/values-af/strings.xml
+++ b/slices/core/src/main/res/values-af/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Laat <xliff:g id="APP_0">%1$s</xliff:g> toe om <xliff:g id="APP_2">%2$s</xliff:g>-skyfies te wys?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Dit kan inligting in <xliff:g id="APP">%1$s</xliff:g> lees"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Dit kan handelinge binne <xliff:g id="APP">%1$s</xliff:g> uitvoer"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om skyfies uit enige program te wys"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Laat toe"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weier"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-am/strings.xml b/slices/core/src/main/res/values-am/strings.xml
index c187e0f..3fc492a 100644
--- a/slices/core/src/main/res/values-am/strings.xml
+++ b/slices/core/src/main/res/values-am/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን እንዲያሳይ ይፈቀድለት?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ከ<xliff:g id="APP">%1$s</xliff:g> የመጣ መረጃን ማንበብ ይችላል"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- በ<xliff:g id="APP">%1$s</xliff:g> ውስጥ እርምጃዎችን መውሰድ ይችላል"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ከማንኛውም መተግበሪያ የመጡ ቁራጮችን እንዲያሳይ ፍቀድለት"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ፍቀድ"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ከልክል"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ar/strings.xml b/slices/core/src/main/res/values-ar/strings.xml
index b5de01c..2d76a8d 100644
--- a/slices/core/src/main/res/values-ar/strings.xml
+++ b/slices/core/src/main/res/values-ar/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"هل تريد السماح لتطبيق <xliff:g id="APP_0">%1$s</xliff:g> بعرض شرائح <xliff:g id="APP_2">%2$s</xliff:g>؟"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- إمكانية قراءة المعلومات من <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- إمكانية اتخاذ إجراءات داخل <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"السماح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بعرض شرائح من أي تطبيق"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"سماح"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"رفض"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-as/strings.xml b/slices/core/src/main/res/values-as/strings.xml
index 95722b9..ea2a877 100644
--- a/slices/core/src/main/res/values-as/strings.xml
+++ b/slices/core/src/main/res/values-as/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>ক <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাবলৈ অনুমতি দিবনে?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ তথ্য পঢ়িব পাৰে"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ ভিতৰত কাৰ্য কৰিব পাৰে"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>ক যিকোনো এপৰ অংশ দেখুওৱাবলৈ অনুমতি দিয়ক"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"অনুমতি দিয়ক"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"অস্বীকাৰ কৰক"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-az/strings.xml b/slices/core/src/main/res/values-az/strings.xml
index ff7be30..2f1bce4 100644
--- a/slices/core/src/main/res/values-az/strings.xml
+++ b/slices/core/src/main/res/values-az/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> tətbiqinə <xliff:g id="APP_2">%2$s</xliff:g> hissələrini göstərmək üçün icazə verilsin?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> tətbiqindən məlumat oxuya bilər"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> daxilində əməliyyatlar edə bilər"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə istənilən tətbiqdən hissə göstərmək icazəsi verin"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"İcazə verin"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rədd edin"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-b+sr+Latn/strings.xml b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
index 95c1692c..3e20b9e 100644
--- a/slices/core/src/main/res/values-b+sr+Latn/strings.xml
+++ b/slices/core/src/main/res/values-b+sr+Latn/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li da dozvolite aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Može da čita podatke iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Može da obavlja radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> da prikazuje isečke iz bilo koje aplikacije"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-be/strings.xml b/slices/core/src/main/res/values-be/strings.xml
index 5fadc3f..84cd4a22 100644
--- a/slices/core/src/main/res/values-be/strings.xml
+++ b/slices/core/src/main/res/values-be/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Дазволіць праграме <xliff:g id="APP_0">%1$s</xliff:g> паказваць фрагменты праграмы <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Можа счытваць інфармацыю з праграмы <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Можа выконваць дзеянні ў праграме <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дазволіць праграме <xliff:g id="APP">%1$s</xliff:g> паказваць фрагменты іншых праграм"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дазволіць"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Адмовіць"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-bg/strings.xml b/slices/core/src/main/res/values-bg/strings.xml
index cb6f067..dcd2606 100644
--- a/slices/core/src/main/res/values-bg/strings.xml
+++ b/slices/core/src/main/res/values-bg/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ще разрешите ли на <xliff:g id="APP_0">%1$s</xliff:g> да показва части от <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чете информация от <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да предприема действия в/ъв <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Разрешаване на <xliff:g id="APP">%1$s</xliff:g> да показва части от което и да е приложение"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Разрешаване"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Отказ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-bn/strings.xml b/slices/core/src/main/res/values-bn/strings.xml
index cfa569d..4b46f9b 100644
--- a/slices/core/src/main/res/values-bn/strings.xml
+++ b/slices/core/src/main/res/values-bn/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটিকে <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখানোর অনুমতি দেবেন?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর তথ্য অ্যাক্সেস করতে পারবে"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর মধ্যে কাজ করতে পারবে"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> অ্যাপটিকে যেকোনও অ্যাপের অংশ দেখাতে দিন"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"অনুমতি দিন"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"খারিজ করুন"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-bs/strings.xml b/slices/core/src/main/res/values-bs/strings.xml
index 651e4d6..b203a79 100644
--- a/slices/core/src/main/res/values-bs/strings.xml
+++ b/slices/core/src/main/res/values-bs/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Može poduzeti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> prikazivanje isječaka iz svake aplikacije"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dozvoli"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ca/strings.xml b/slices/core/src/main/res/values-ca/strings.xml
index 0c953cf..ac93488 100644
--- a/slices/core/src/main/res/values-ca/strings.xml
+++ b/slices/core/src/main/res/values-ca/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vols permetre que <xliff:g id="APP_0">%1$s</xliff:g> mostri porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pot llegir informació de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pot dur a terme accions dins de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permet que <xliff:g id="APP">%1$s</xliff:g> mostri porcions de qualsevol aplicació"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permet"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denega"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-cs/strings.xml b/slices/core/src/main/res/values-cs/strings.xml
index 6db0934..da1053b 100644
--- a/slices/core/src/main/res/values-cs/strings.xml
+++ b/slices/core/src/main/res/values-cs/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Povolit aplikaci <xliff:g id="APP_0">%1$s</xliff:g> zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Může číst informace z aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Může provádět akce v aplikaci <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> zobrazovat ukázky z libovolné aplikace"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povolit"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamítnout"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-da/strings.xml b/slices/core/src/main/res/values-da/strings.xml
index 70f1a22..67a7ed08 100644
--- a/slices/core/src/main/res/values-da/strings.xml
+++ b/slices/core/src/main/res/values-da/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du give <xliff:g id="APP_0">%1$s</xliff:g> tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Den kan læse oplysninger fra <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Den kan foretage handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillad, at <xliff:g id="APP">%1$s</xliff:g> viser eksempler fra enhver app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillad"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Afvis"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-de/strings.xml b/slices/core/src/main/res/values-de/strings.xml
index 89ce98e..419fa20 100644
--- a/slices/core/src/main/res/values-de/strings.xml
+++ b/slices/core/src/main/res/values-de/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> erlauben, Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzuzeigen?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Darf Informationen aus <xliff:g id="APP">%1$s</xliff:g> lesen"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Darf Aktionen in <xliff:g id="APP">%1$s</xliff:g> ausführen"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> darf Teile aus jeder beliebigen App anzeigen"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zulassen"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ablehnen"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-el/strings.xml b/slices/core/src/main/res/values-el/strings.xml
index ed0b624..898d2ea 100644
--- a/slices/core/src/main/res/values-el/strings.xml
+++ b/slices/core/src/main/res/values-el/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>;"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Μπορεί να διαβάζει πληροφορίες από την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Μπορεί να εκτελεί ενέργειες εντός της εφαρμογής <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να εμφανίζει τμήματα από οποιαδήποτε εφαρμογή"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Να επιτρέπεται"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Να μην επιτρέπεται"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-en-rAU/strings.xml b/slices/core/src/main/res/values-en-rAU/strings.xml
index d47c9ec..b4c1f11 100644
--- a/slices/core/src/main/res/values-en-rAU/strings.xml
+++ b/slices/core/src/main/res/values-en-rAU/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-en-rCA/strings.xml b/slices/core/src/main/res/values-en-rCA/strings.xml
index d47c9ec..b4c1f11 100644
--- a/slices/core/src/main/res/values-en-rCA/strings.xml
+++ b/slices/core/src/main/res/values-en-rCA/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-en-rGB/strings.xml b/slices/core/src/main/res/values-en-rGB/strings.xml
index d47c9ec..b4c1f11 100644
--- a/slices/core/src/main/res/values-en-rGB/strings.xml
+++ b/slices/core/src/main/res/values-en-rGB/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-en-rIN/strings.xml b/slices/core/src/main/res/values-en-rIN/strings.xml
index d47c9ec..b4c1f11 100644
--- a/slices/core/src/main/res/values-en-rIN/strings.xml
+++ b/slices/core/src/main/res/values-en-rIN/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– It can take actions inside <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Allow <xliff:g id="APP">%1$s</xliff:g> to show slices from any app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Allow"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Deny"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-en-rXC/strings.xml b/slices/core/src/main/res/values-en-rXC/strings.xml
index 5f82056..efb1d5f 100644
--- a/slices/core/src/main/res/values-en-rXC/strings.xml
+++ b/slices/core/src/main/res/values-en-rXC/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to show ‎‏‎‎‏‏‎<xliff:g id="APP_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎ slices?‎‏‎‎‏‎"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎- It can read information from ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎- It can take actions inside ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to show slices from any app‎‏‎‎‏‎"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎Allow‎‏‎‎‏‎"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎Deny‎‏‎‎‏‎"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-es-rUS/strings.xml b/slices/core/src/main/res/values-es-rUS/strings.xml
index 9db16c5..31746f0 100644
--- a/slices/core/src/main/res/values-es-rUS/strings.xml
+++ b/slices/core/src/main/res/values-es-rUS/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> muestre fragmentos de cualquier app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rechazar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-es/strings.xml b/slices/core/src/main/res/values-es/strings.xml
index 44283aa..3a65289 100644
--- a/slices/core/src/main/res/values-es/strings.xml
+++ b/slices/core/src/main/res/values-es/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> muestre fragmentos de cualquier aplicación"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-et/strings.xml b/slices/core/src/main/res/values-et/strings.xml
index 6c45d68..5462dd7 100644
--- a/slices/core/src/main/res/values-et/strings.xml
+++ b/slices/core/src/main/res/values-et/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Kas lubada rakendusel <xliff:g id="APP_0">%1$s</xliff:g> näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- See saab lugeda teavet rakendusest <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- See saab rakenduses <xliff:g id="APP">%1$s</xliff:g> toiminguid teha"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Luba rakendus <xliff:g id="APP">%1$s</xliff:g>, et kuvada lõike mis tahes rakendusest"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lubamine"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Keelamine"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-eu/strings.xml b/slices/core/src/main/res/values-eu/strings.xml
index e608918..8776fec 100644
--- a/slices/core/src/main/res/values-eu/strings.xml
+++ b/slices/core/src/main/res/values-eu/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioan ekintzak gauza ditzake."</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Eman aplikazio guztien zatiak erakusteko baimena <xliff:g id="APP">%1$s</xliff:g> aplikazioari"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Baimendu"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ukatu"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-fa/strings.xml b/slices/core/src/main/res/values-fa/strings.xml
index 38a286d..d5e0416 100644
--- a/slices/core/src/main/res/values-fa/strings.xml
+++ b/slices/core/src/main/res/values-fa/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"به <xliff:g id="APP_0">%1$s</xliff:g> اجازه داده شود تکه‌های <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد؟"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- می‌تواند اطلاعات <xliff:g id="APP">%1$s</xliff:g> را بخواند"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- می‌تواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"به <xliff:g id="APP">%1$s</xliff:g> اجازه داده شود تکه‌هایی از برنامه‌ها نشان دهد"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"مجاز بودن"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"مجاز نبودن"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-fi/strings.xml b/slices/core/src/main/res/values-fi/strings.xml
index 1cc8122..d682f1a 100644
--- a/slices/core/src/main/res/values-fi/strings.xml
+++ b/slices/core/src/main/res/values-fi/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Saako <xliff:g id="APP_0">%1$s</xliff:g> näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Se voi lukea tietoja sovelluksesta <xliff:g id="APP">%1$s</xliff:g>."</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Se voi suorittaa toimintoja sovelluksessa <xliff:g id="APP">%1$s</xliff:g>."</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Salli sovelluksen <xliff:g id="APP">%1$s</xliff:g> näyttää osia mistä tahansa sovelluksesta"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Salli"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Estä"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-fr-rCA/strings.xml b/slices/core/src/main/res/values-fr-rCA/strings.xml
index d92e649..a0e55d3 100644
--- a/slices/core/src/main/res/values-fr-rCA/strings.xml
+++ b/slices/core/src/main/res/values-fr-rCA/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Il peut effectuer des actions dans <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des tranches de n\'importe quelle application"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-fr/strings.xml b/slices/core/src/main/res/values-fr/strings.xml
index 9edcb27..65f06bc 100644
--- a/slices/core/src/main/res/values-fr/strings.xml
+++ b/slices/core/src/main/res/values-fr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Accès aux informations de <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Capacité d\'action dans <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des éléments de n\'importe quelle application"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Autoriser"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuser"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-gl/strings.xml b/slices/core/src/main/res/values-gl/strings.xml
index 617e5fc..50befe5 100644
--- a/slices/core/src/main/res/values-gl/strings.xml
+++ b/slices/core/src/main/res/values-gl/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Queres permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler información da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode levar a cabo accións dentro da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre fragmentos de calquera aplicación"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Denegar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-gu/strings.xml b/slices/core/src/main/res/values-gu/strings.xml
index 4e8fcb8..804b774 100644
--- a/slices/core/src/main/res/values-gu/strings.xml
+++ b/slices/core/src/main/res/values-gu/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- તે <xliff:g id="APP">%1$s</xliff:g>માંથી માહિતી વાંચી શકે છે"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- તે <xliff:g id="APP">%1$s</xliff:g>ની અંદર ક્રિયાઓ કરી શકે છે"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>ને કોઈપણ ઍપના સ્લાઇસ બતાવવાની મંજૂરી આપો"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"મંજૂરી આપો"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"નકારો"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-hi/strings.xml b/slices/core/src/main/res/values-hi/strings.xml
index 23e4d3f..9dfe2b0 100644
--- a/slices/core/src/main/res/values-hi/strings.xml
+++ b/slices/core/src/main/res/values-hi/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यह <xliff:g id="APP">%1$s</xliff:g> से जानकारी पा सकता है"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यह <xliff:g id="APP">%1$s</xliff:g> में कार्रवाई कर सकता है"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> काे किसी भी ऐप्लिकेशन के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दें"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"अनुमति न दें"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-hr/strings.xml b/slices/core/src/main/res/values-hr/strings.xml
index e0bffaa..9e614b5 100644
--- a/slices/core/src/main/res/values-hr/strings.xml
+++ b/slices/core/src/main/res/values-hr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Želite li dopustiti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– može čitati informacije aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– može vršiti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dopusti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da prikazuje isječke iz bilo koje aplikacije"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dopusti"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odbij"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-hu/strings.xml b/slices/core/src/main/res/values-hu/strings.xml
index 4601a88..004829f 100644
--- a/slices/core/src/main/res/values-hu/strings.xml
+++ b/slices/core/src/main/res/values-hu/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Engedélyezi a(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazásnak, hogy részleteket mutasson a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Információkat olvashat a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásból"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Műveleteket végezhet a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazáson belül"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásnak, hogy bármely alkalmazásból részletet jelenítsen meg"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Engedélyezés"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Elutasítás"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-hy/strings.xml b/slices/core/src/main/res/values-hy/strings.xml
index c8850ff..1d716d7 100644
--- a/slices/core/src/main/res/values-hy/strings.xml
+++ b/slices/core/src/main/res/values-hy/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Թույլատրե՞լ <xliff:g id="APP_0">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Կարող է կարդալ տեղեկություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածից"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Կարող է կատարել գործողություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածում"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Թույլատրել <xliff:g id="APP">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ ցանկացած հավելվածից"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Թույլատրել"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Մերժել"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-in/strings.xml b/slices/core/src/main/res/values-in/strings.xml
index a68a7c7..860ed1c 100644
--- a/slices/core/src/main/res/values-in/strings.xml
+++ b/slices/core/src/main/res/values-in/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Izinkan <xliff:g id="APP_0">%1$s</xliff:g> menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Dapat membaca informasi dari <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Dapat mengambil tindakan di dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Izinkan <xliff:g id="APP">%1$s</xliff:g> menampilkan potongan dari aplikasi apa pun"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Izinkan"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-is/strings.xml b/slices/core/src/main/res/values-is/strings.xml
index 24f3ace..da79a76 100644
--- a/slices/core/src/main/res/values-is/strings.xml
+++ b/slices/core/src/main/res/values-is/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Viltu leyfa <xliff:g id="APP_0">%1$s</xliff:g> að sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Það getur lesið upplýsingar úr <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Það getur gripið til aðgerða í <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að sýna sneiðar úr hvaða forriti sem er"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leyfa"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Hafna"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-it/strings.xml b/slices/core/src/main/res/values-it/strings.xml
index 333547d..5518d66 100644
--- a/slices/core/src/main/res/values-it/strings.xml
+++ b/slices/core/src/main/res/values-it/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vuoi consentire all\'app <xliff:g id="APP_0">%1$s</xliff:g> di mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Può leggere informazioni dell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Può compiere azioni nell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Consenti all\'app <xliff:g id="APP">%1$s</xliff:g> di mostrare porzioni di qualsiasi app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Consenti"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rifiuta"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-iw/strings.xml b/slices/core/src/main/res/values-iw/strings.xml
index 7534117..2151548 100644
--- a/slices/core/src/main/res/values-iw/strings.xml
+++ b/slices/core/src/main/res/values-iw/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"האם לאפשר ל-<xliff:g id="APP_0">%1$s</xliff:g> להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- תהיה לה אפשרות לקרוא מידע מהאפליקציה <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- תהיה לה יכולת לנקוט פעולה בתוך <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"יש לאשר לאפליקציית <xliff:g id="APP">%1$s</xliff:g> להציג חלקים מכל אפליקציה שהיא"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"אישור"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"אני לא מרשה"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ja/strings.xml b/slices/core/src/main/res/values-ja/strings.xml
index 315326f..1c28f4c 100644
--- a/slices/core/src/main/res/values-ja/strings.xml
+++ b/slices/core/src/main/res/values-ja/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> のスライスの表示を <xliff:g id="APP_0">%1$s</xliff:g> に許可しますか?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> からの情報を読み取ることができます"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> 内部で操作することがあります"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"すべてのアプリのスライスを表示することを <xliff:g id="APP">%1$s</xliff:g> に許可する"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"許可"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒否"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ka/strings.xml b/slices/core/src/main/res/values-ka/strings.xml
index f21d1be..b78206c 100644
--- a/slices/core/src/main/res/values-ka/strings.xml
+++ b/slices/core/src/main/res/values-ka/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"ანიჭებთ ნებართვას <xliff:g id="APP_0">%1$s</xliff:g>-ს, აჩვენოს <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- მას შეუძლია ინფორმაციის <xliff:g id="APP">%1$s</xliff:g>-დან წაკითხვა"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- მას შეუძლია ქმედებების <xliff:g id="APP">%1$s</xliff:g>-ში განხორციელება"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>-ისთვის ფრაგმენტების ნებისმიერი აპიდან ჩვენების ნების დართვა"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"დაშვება"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"უარყოფა"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-kk/strings.xml b/slices/core/src/main/res/values-kk/strings.xml
index aa9409f..fcb0509 100644
--- a/slices/core/src/main/res/values-kk/strings.xml
+++ b/slices/core/src/main/res/values-kk/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасына <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсетуге рұқсат берілсін бе?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасындағы ақпаратты оқи алады"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> қолданбасында әрекет ете алады"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына кез келген қолданбаның үзіндісін көрсетуге рұқсат беру"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Рұқсат беру"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Тыйым салу"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-km/strings.xml b/slices/core/src/main/res/values-km/strings.xml
index a98f409..5d0a988 100644
--- a/slices/core/src/main/res/values-km/strings.xml
+++ b/slices/core/src/main/res/values-km/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"អនុញ្ញាតឱ្យ <xliff:g id="APP_0">%1$s</xliff:g> បង្ហាញ​ស្ថិតិប្រើប្រាស់​របស់ <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- វា​អាច​អាន​ព័ត៌មាន​ពី <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- វាអាច​ធ្វើសកម្មភាព​នៅក្នុង <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"អនុញ្ញាត​ឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្ហាញ​ស្ថិតិ​ប្រើប្រាស់​ពី​កម្មវិធី​នានា"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"អនុញ្ញាត"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"បដិសេធ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-kn/strings.xml b/slices/core/src/main/res/values-kn/strings.xml
index e8a0559..7fe32e0 100644
--- a/slices/core/src/main/res/values-kn/strings.xml
+++ b/slices/core/src/main/res/values-kn/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP_0">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ನಿಂದ ಮಾಹಿತಿಯನ್ನು ಓದಬಹುದು"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ಒಳಗಡೆ ಕ್ರಿಯೆಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಸ್ಲೈಸ್‌ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸಿ"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ಅನುಮತಿಸಿ"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ನಿರಾಕರಿಸಿ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ko/strings.xml b/slices/core/src/main/res/values-ko/strings.xml
index cc88f25..93c62f0 100644
--- a/slices/core/src/main/res/values-ko/strings.xml
+++ b/slices/core/src/main/res/values-ko/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하도록 허용하시겠습니까?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g>의 정보를 읽을 수 있음"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g>에서 작업할 수 있음"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>에서 모든 앱의 슬라이스를 표시하도록 허용"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"허용"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"거부"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ky/strings.xml b/slices/core/src/main/res/values-ky/strings.xml
index 99ce121..9615740 100644
--- a/slices/core/src/main/res/values-ky/strings.xml
+++ b/slices/core/src/main/res/values-ky/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунда аракеттерди аткарат"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> бардык колдонмолордун үлгүлөрүн көрсөтүүгө уруксат берүү"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Уруксат берүү"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Тыюу салынат"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-lo/strings.xml b/slices/core/src/main/res/values-lo/strings.xml
index 74bb119..9b18f5b 100644
--- a/slices/core/src/main/res/values-lo/strings.xml
+++ b/slices/core/src/main/res/values-lo/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"ອະນຸຍາດ <xliff:g id="APP_0">%1$s</xliff:g> ໃຫ້ສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້ບໍ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ມັນສາມາດອ່ານຂໍ້ມູນຈາກ <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ມັນສາມາດໃຊ້ຄຳສັ່ງພາຍໃນ <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ອະນຸຍາດ <xliff:g id="APP">%1$s</xliff:g> ເພື່ອສະແດງສະໄລ້ຈາກແອັບ"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ອະນຸຍາດ"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ປະຕິເສດ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-lt/strings.xml b/slices/core/src/main/res/values-lt/strings.xml
index 50eb4a6..1e88cd6 100644
--- a/slices/core/src/main/res/values-lt/strings.xml
+++ b/slices/core/src/main/res/values-lt/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Leisti „<xliff:g id="APP_0">%1$s</xliff:g>“ rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Gali nuskaityti informaciją iš „<xliff:g id="APP">%1$s</xliff:g>“"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Gali imtis veiksmų programoje „<xliff:g id="APP">%1$s</xliff:g>“"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ rodyti bet kurios programos fragmentus"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Leisti"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Atmesti"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-lv/strings.xml b/slices/core/src/main/res/values-lv/strings.xml
index 4bfb688..1f3ccde 100644
--- a/slices/core/src/main/res/values-lv/strings.xml
+++ b/slices/core/src/main/res/values-lv/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vai atļaut lietotnei <xliff:g id="APP_0">%1$s</xliff:g> rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Var lasīt informāciju no lietotnes <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Var veikt darbības lietotnē <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> rādīt sadaļas no jebkuras lietotnes"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Atļaut"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neatļaut"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-mk/strings.xml b/slices/core/src/main/res/values-mk/strings.xml
index 2525781..a5ccc53 100644
--- a/slices/core/src/main/res/values-mk/strings.xml
+++ b/slices/core/src/main/res/values-mk/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Да се дозволи <xliff:g id="APP_0">%1$s</xliff:g> да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може да чита информации од <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може да презема дејства во <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволете <xliff:g id="APP">%1$s</xliff:g> да прикажува делови од која било апликација"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволете"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбијте"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ml/strings.xml b/slices/core/src/main/res/values-ml/strings.xml
index ce177d2..21802b7 100644
--- a/slices/core/src/main/res/values-ml/strings.xml
+++ b/slices/core/src/main/res/values-ml/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-ൽ നിന്ന് വിവരങ്ങൾ വായിക്കാനാകും"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-നുള്ളിൽ പ്രവർത്തനങ്ങൾ ചെയ്യാനാകും"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ഏത് ആപ്പിൽ നിന്നും സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP">%1$s</xliff:g>-നെ അനുവദിക്കുക"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"അനുവദിക്കുക"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"നിരസിക്കുക"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-mn/strings.xml b/slices/core/src/main/res/values-mn/strings.xml
index 50764d9..8e0661a 100644
--- a/slices/core/src/main/res/values-mn/strings.xml
+++ b/slices/core/src/main/res/values-mn/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g>-д <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг харуулахыг зөвшөөрөх үү?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Энэ <xliff:g id="APP">%1$s</xliff:g>-с мэдээлэл унших боломжтой"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Энэ <xliff:g id="APP">%1$s</xliff:g> дотор үйлдэл хийх боломжтой"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g>-д дурын аппаас хэсэг харуулахыг зөвшөөрөх"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Зөвшөөрөх"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Татгалзах"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-mr/strings.xml b/slices/core/src/main/res/values-mr/strings.xml
index f938652..ab48521 100644
--- a/slices/core/src/main/res/values-mr/strings.xml
+++ b/slices/core/src/main/res/values-mr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवण्याची अनुमती द्यायची का?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ते <xliff:g id="APP">%1$s</xliff:g> ची माहिती वाचू शकते"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ते <xliff:g id="APP">%1$s</xliff:g> मध्ये कृती करू शकते"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ला कुठल्याही अ‍ॅपमधील तुकडे दाखवण्याची अनुमती द्या"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमती द्या"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"नकार द्या"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ms/strings.xml b/slices/core/src/main/res/values-ms/strings.xml
index af2a67e..4b20a63 100644
--- a/slices/core/src/main/res/values-ms/strings.xml
+++ b/slices/core/src/main/res/values-ms/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Benarkan <xliff:g id="APP_0">%1$s</xliff:g> menunjukkan hirisan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Hos hirisan boleh membaca maklumat daripada <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Hos hirisan boleh mengambil tindakan dalam <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Benarkan <xliff:g id="APP">%1$s</xliff:g> menunjukkan hirisan daripada mana-mana apl"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Benarkan"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tolak"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-my/strings.xml b/slices/core/src/main/res/values-my/strings.xml
index 0cf5d3e..666640ef 100644
--- a/slices/core/src/main/res/values-my/strings.xml
+++ b/slices/core/src/main/res/values-my/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> အား <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များ ပြသခွင့်ပြုပါသလား။"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> မှ အချက်အလက်ကို ဖတ်နိုင်သည်"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> အတွင်း လုပ်ဆောင်ချက်များ ပြုလုပ်နိုင်သည်"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"မည်သည့်အက်ပ်မဆိုမှ အချပ်များ ပြသရန်အတွက် <xliff:g id="APP">%1$s</xliff:g> ကို ခွင့်ပြုရန်"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ခွင့်ပြုရန်"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ငြင်းပယ်ရန်"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-nb/strings.xml b/slices/core/src/main/res/values-nb/strings.xml
index 634eac3..9448d03 100644
--- a/slices/core/src/main/res/values-nb/strings.xml
+++ b/slices/core/src/main/res/values-nb/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vil du tillate at <xliff:g id="APP_0">%1$s</xliff:g> viser <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Den kan lese informasjon fra <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Den kan utføre handlinger i <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillat at <xliff:g id="APP">%1$s</xliff:g> viser utsnitt fra alle apper"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillat"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Ikke tillat"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ne/strings.xml b/slices/core/src/main/res/values-ne/strings.xml
index adf3a1b..bfa42445 100644
--- a/slices/core/src/main/res/values-ne/strings.xml
+++ b/slices/core/src/main/res/values-ne/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> लाई <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन अनुमति दिने हो?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- यसले <xliff:g id="APP">%1$s</xliff:g> को जानकारी पढ्न सक्छ"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- यसले <xliff:g id="APP">%1$s</xliff:g> भित्र कारबाही गर्न सक्छ"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> लाई सबै एपका स्लाइसहरू देखाउन अनुमति दिनुहोस्"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"अनुमति दिनुहोस्"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"नदिने"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-nl/strings.xml b/slices/core/src/main/res/values-nl/strings.xml
index 46b2c9f..4d8006e 100644
--- a/slices/core/src/main/res/values-nl/strings.xml
+++ b/slices/core/src/main/res/values-nl/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> te tonen?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> toestaan om segmenten van apps te tonen"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Toestaan"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Weigeren"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-or/strings.xml b/slices/core/src/main/res/values-or/strings.xml
index a87a506..a757613 100644
--- a/slices/core/src/main/res/values-or/strings.xml
+++ b/slices/core/src/main/res/values-or/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍‌କୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP_0">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ଏହା <xliff:g id="APP">%1$s</xliff:g>ରୁ ସୂଚନାକୁ ପଢ଼ିପାରିବ"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ଏହା <xliff:g id="APP">%1$s</xliff:g> ଭିତରେ କାମ କରିପାରିବ"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ଯେକୌଣସି ଆପ୍‌ରେ ସ୍ଲାଇସ୍‌କୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-pa/strings.xml b/slices/core/src/main/res/values-pa/strings.xml
index e1ef272..d68cc39 100644
--- a/slices/core/src/main/res/values-pa/strings.xml
+++ b/slices/core/src/main/res/values-pa/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"ਕੀ <xliff:g id="APP_0">%1$s</xliff:g> ਨੂੰ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੇਣੇ ਹਨ?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ਇਹ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚੋਂ ਜਾਣਕਾਰੀ ਪੜ੍ਹ ਸਕਦਾ ਹੈ"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ਇਸ <xliff:g id="APP">%1$s</xliff:g> ਦੇ ਅੰਦਰ ਕਾਰਵਾਈਆਂ ਕਰ ਸਕਦਾ ਹੈ"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ਨੂੰ ਕਿਸੇ ਵੀ ਐਪ ਵਿੱਚੋਂ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦਿਓ"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ਕਰਨ ਦਿਓ"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-pl/strings.xml b/slices/core/src/main/res/values-pl/strings.xml
index f66d32c..ea32902 100644
--- a/slices/core/src/main/res/values-pl/strings.xml
+++ b/slices/core/src/main/res/values-pl/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Zezwolić aplikacji <xliff:g id="APP_0">%1$s</xliff:g> na pokazywanie wycinków z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Może odczytywać informacje z aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Może wykonywać działania w aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Zezwalaj aplikacji <xliff:g id="APP">%1$s</xliff:g> na pokazywanie wycinków z dowolnych aplikacji"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Zezwól"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Odmów"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-pt-rBR/strings.xml b/slices/core/src/main/res/values-pt-rBR/strings.xml
index 246fc77..b58e786 100644
--- a/slices/core/src/main/res/values-pt-rBR/strings.xml
+++ b/slices/core/src/main/res/values-pt-rBR/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-pt-rPT/strings.xml b/slices/core/src/main/res/values-pt-rPT/strings.xml
index 472dce8..832b5e5 100644
--- a/slices/core/src/main/res/values-pt-rPT/strings.xml
+++ b/slices/core/src/main/res/values-pt-rPT/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que a app <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações da app <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações na app <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Recusar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-pt/strings.xml b/slices/core/src/main/res/values-pt/strings.xml
index 246fc77..b58e786 100644
--- a/slices/core/src/main/res/values-pt/strings.xml
+++ b/slices/core/src/main/res/values-pt/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Pode realizar ações no app <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permitir"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Negar"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ro/strings.xml b/slices/core/src/main/res/values-ro/strings.xml
index f4b1135..2db5e57 100644
--- a/slices/core/src/main/res/values-ro/strings.xml
+++ b/slices/core/src/main/res/values-ro/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Permiteți <xliff:g id="APP_0">%1$s</xliff:g> să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Poate citi informații din <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Poate efectua acțiuni în <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Permiteți <xliff:g id="APP">%1$s</xliff:g> să afișeze porțiuni din orice aplicație"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Permiteți"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzați"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ru/strings.xml b/slices/core/src/main/res/values-ru/strings.xml
index 43e261f..89dafbc 100644
--- a/slices/core/src/main/res/values-ru/strings.xml
+++ b/slices/core/src/main/res/values-ru/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Разрешить приложению \"<xliff:g id="APP_0">%1$s</xliff:g>\" показывать фрагменты приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Ему станут доступны данные из приложения \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Оно сможет совершать действия в приложении \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" показывать фрагменты других приложений"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Да"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Нет"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-si/strings.xml b/slices/core/src/main/res/values-si/strings.xml
index 70816e1..e5e8478 100644
--- a/slices/core/src/main/res/values-si/strings.xml
+++ b/slices/core/src/main/res/values-si/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට ඉඩ දෙන්නද?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- එයට <xliff:g id="APP">%1$s</xliff:g> වෙතින් තොරතුරු කියවිය හැකිය"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- එයට <xliff:g id="APP">%1$s</xliff:g> ඇතුළත ක්‍රියාමාර්ග ගත හැකිය"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ඕනෑම යෙදුමකින් කොටස් පෙන්වීමට <xliff:g id="APP">%1$s</xliff:g> හට ඉඩ දෙන්න"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"ඉඩ දෙන්න"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ප්‍රතික්ෂේප කර."</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sk/strings.xml b/slices/core/src/main/res/values-sk/strings.xml
index 4937a6c..8070718 100644
--- a/slices/core/src/main/res/values-sk/strings.xml
+++ b/slices/core/src/main/res/values-sk/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Povoliť aplikácii <xliff:g id="APP_0">%1$s</xliff:g> zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Môže čítať informácie z aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Môže vykonávať akcie v aplikácii <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> zobrazovať rezy z ľubovoľnej aplikácie"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Povoliť"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zamietnuť"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sl/strings.xml b/slices/core/src/main/res/values-sl/strings.xml
index 30f67c4..b3ab6f4 100644
--- a/slices/core/src/main/res/values-sl/strings.xml
+++ b/slices/core/src/main/res/values-sl/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ali aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> dovolite prikazovanje izrezov iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– lahko bere podatke v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– lahko izvaja dejanja v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Dovoli, da aplikacija <xliff:g id="APP">%1$s</xliff:g> prikaže izreze iz poljubne aplikacije"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Dovoli"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Zavrni"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sq/strings.xml b/slices/core/src/main/res/values-sq/strings.xml
index 47ce934..9ae77dd 100644
--- a/slices/core/src/main/res/values-sq/strings.xml
+++ b/slices/core/src/main/res/values-sq/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Të lejohet <xliff:g id="APP_0">%1$s</xliff:g> që të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Mund të lexojë informacion nga <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Mund të ndërmarrë veprime brenda <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Lejo <xliff:g id="APP">%1$s</xliff:g> për të shfaqur pjesë nga çdo aplikacion"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Lejo"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Refuzo"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sr/strings.xml b/slices/core/src/main/res/values-sr/strings.xml
index e059b1c..b7c29c5 100644
--- a/slices/core/src/main/res/values-sr/strings.xml
+++ b/slices/core/src/main/res/values-sr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Желите ли да дозволите апликацији <xliff:g id="APP_0">%1$s</xliff:g> да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Може да чита податке из апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Може да обавља радње у апликацији <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволи апликацији <xliff:g id="APP">%1$s</xliff:g> да приказује исечке из било које апликације"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволи"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Одбиј"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sv/strings.xml b/slices/core/src/main/res/values-sv/strings.xml
index e065cb3..9be28b3 100644
--- a/slices/core/src/main/res/values-sv/strings.xml
+++ b/slices/core/src/main/res/values-sv/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Tillåter du att bitar av <xliff:g id="APP_2">%2$s</xliff:g> visas i <xliff:g id="APP_0">%1$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– Kan läsa information från <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– Kan vidta åtgärder i <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Tillåt att bitar av vilken app som helst visas i <xliff:g id="APP">%1$s</xliff:g>"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Tillåt"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Neka"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-sw/strings.xml b/slices/core/src/main/res/values-sw/strings.xml
index 2365547..28459cd 100644
--- a/slices/core/src/main/res/values-sw/strings.xml
+++ b/slices/core/src/main/res/values-sw/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Ungependa kuruhusu <xliff:g id="APP_0">%1$s</xliff:g> ionyeshe vipengee <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Inaweza kusoma maelezo kutoka <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Inaweza kuchukua hatua ndani ya <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> ionyeshe vipengee kutoka programu yoyote"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruhusu"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Kataa"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ta/strings.xml b/slices/core/src/main/res/values-ta/strings.xml
index 0c8d874..36be75a 100644
--- a/slices/core/src/main/res/values-ta/strings.xml
+++ b/slices/core/src/main/res/values-ta/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிலிருக்கும் தகவலைப் படிக்கும்"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிற்குள் செயல்பாடுகளில் ஈடுபடும்"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"எந்தப் பயன்பாட்டிலிருந்தும் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதி"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"அனுமதி"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"நிராகரி"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-te/strings.xml b/slices/core/src/main/res/values-te/strings.xml
index 3f89a75..ce51a47 100644
--- a/slices/core/src/main/res/values-te/strings.xml
+++ b/slices/core/src/main/res/values-te/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించాలా?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- ఇది <xliff:g id="APP">%1$s</xliff:g> నుండి సమాచారాన్ని చదవగలుగుతుంది"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ఇది <xliff:g id="APP">%1$s</xliff:g> లోపల చర్యలు తీసుకోగలుగుతుంది"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"ఏ యాప్ నుండి అయినా స్లైస్‌లను చూపించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించండి"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"అనుమతించు"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"తిరస్కరించు"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-th/strings.xml b/slices/core/src/main/res/values-th/strings.xml
index afc42f2..07371a0 100644
--- a/slices/core/src/main/res/values-th/strings.xml
+++ b/slices/core/src/main/res/values-th/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"อนุญาตให้ <xliff:g id="APP_0">%1$s</xliff:g> แสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- อ่านข้อมูลจาก <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- ดำเนินการใน <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> แสดงส่วนต่างๆ จากแอปใดก็ได้"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"อนุญาต"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"ปฏิเสธ"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-tl/strings.xml b/slices/core/src/main/res/values-tl/strings.xml
index aa9d7b4..e4bf3e0 100644
--- a/slices/core/src/main/res/values-tl/strings.xml
+++ b/slices/core/src/main/res/values-tl/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Payagan ang <xliff:g id="APP_0">%1$s</xliff:g> na ipakita ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Nakakabasa ito ng impormasyon mula sa <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Nakakagawa ito ng mga pagkilos sa loob ng <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na ipakita ang mga slice mula sa anumang app"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Payagan"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Tanggihan"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-tr/strings.xml b/slices/core/src/main/res/values-tr/strings.xml
index 216a87c..2cbcfda 100644
--- a/slices/core/src/main/res/values-tr/strings.xml
+++ b/slices/core/src/main/res/values-tr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> uygulamasının, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermesine izin verilsin mi?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasından bilgileri okuyabilir"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasında işlem yapabilir"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının tüm uygulamalardan dilimleri göstermesine izin ver"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"İzin ver"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Reddet"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-uk/strings.xml b/slices/core/src/main/res/values-uk/strings.xml
index e908f43..b842f5c 100644
--- a/slices/core/src/main/res/values-uk/strings.xml
+++ b/slices/core/src/main/res/values-uk/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Дозволити додатку <xliff:g id="APP_0">%1$s</xliff:g> показувати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Може переглядати інформацію з додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Може виконувати дії в додатку <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> показувати фрагменти будь-якого додатка"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Дозволити"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Заборонити"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-ur/strings.xml b/slices/core/src/main/res/values-ur/strings.xml
index 0e97e52..8999e25 100644
--- a/slices/core/src/main/res/values-ur/strings.xml
+++ b/slices/core/src/main/res/values-ur/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> کو <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانے کی اجازت دیں؟"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- یہ <xliff:g id="APP">%1$s</xliff:g> کی معلومات پڑھ سکتا ہے"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- یہ <xliff:g id="APP">%1$s</xliff:g> کے اندر کارروائیاں کر سکتا ہے"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> کو کسی بھی ایپ سے سلائسز دکھانے کی اجازت دیں"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"اجازت دیں"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"مسترد کریں"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-uz/strings.xml b/slices/core/src/main/res/values-uz/strings.xml
index 8de5b2e..9fcb4ce 100644
--- a/slices/core/src/main/res/values-uz/strings.xml
+++ b/slices/core/src/main/res/values-uz/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasiga <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatishga ruxsat berilsinmi?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"– <xliff:g id="APP">%1$s</xliff:g> ma’lumotlarini o‘qiy oladi"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"– <xliff:g id="APP">%1$s</xliff:g> ichida amallar bajara oladi"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga boshqa ilovalardan fragmentlarni ko‘rsatishga ruxsat berish"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Ruxsat"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Rad etish"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-vi/strings.xml b/slices/core/src/main/res/values-vi/strings.xml
index 8ecd246..c067ac8 100644
--- a/slices/core/src/main/res/values-vi/strings.xml
+++ b/slices/core/src/main/res/values-vi/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Cho phép <xliff:g id="APP_0">%1$s</xliff:g> hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Có thể đọc thông tin từ <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Có thể thực hiện hành động bên trong <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Cho phép <xliff:g id="APP">%1$s</xliff:g> hiển thị các lát từ mọi ứng dụng"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Cho phép"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Từ chối"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-zh-rCN/strings.xml b/slices/core/src/main/res/values-zh-rCN/strings.xml
index 3a99e82..6ab2d3e 100644
--- a/slices/core/src/main/res/values-zh-rCN/strings.xml
+++ b/slices/core/src/main/res/values-zh-rCN/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允许“<xliff:g id="APP_0">%1$s</xliff:g>”显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块吗?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以读取“<xliff:g id="APP">%1$s</xliff:g>”中的信息"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在“<xliff:g id="APP">%1$s</xliff:g>”内执行操作"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允许“<xliff:g id="APP">%1$s</xliff:g>”显示任何应用的图块"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允许"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒绝"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-zh-rHK/strings.xml b/slices/core/src/main/res/values-zh-rHK/strings.xml
index bb478fc..5cf6943 100644
--- a/slices/core/src/main/res/values-zh-rHK/strings.xml
+++ b/slices/core/src/main/res/values-zh-rHK/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊嗎?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 可以讀取「<xliff:g id="APP">%1$s</xliff:g>」中的資料"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允許「<xliff:g id="APP">%1$s</xliff:g>」顯示任何應用程式的快訊"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-zh-rTW/strings.xml b/slices/core/src/main/res/values-zh-rTW/strings.xml
index caeeff1..df1ab8b 100644
--- a/slices/core/src/main/res/values-zh-rTW/strings.xml
+++ b/slices/core/src/main/res/values-zh-rTW/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊嗎?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- 它可以讀取「<xliff:g id="APP">%1$s</xliff:g>」的資訊"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- 它可以在「<xliff:g id="APP">%1$s</xliff:g>」內執行操作"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"允許「<xliff:g id="APP">%1$s</xliff:g>」顯示任何應用程式的區塊"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"允許"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"拒絕"</string>
 </resources>
diff --git a/slices/core/src/main/res/values-zu/strings.xml b/slices/core/src/main/res/values-zu/strings.xml
index 940334c..d9ada48 100644
--- a/slices/core/src/main/res/values-zu/strings.xml
+++ b/slices/core/src/main/res/values-zu/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_slice_permission_title" msgid="4175332421259324948">"Vumela i-<xliff:g id="APP_0">%1$s</xliff:g> ukuthi ibonise izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="abc_slice_permission_text_1" msgid="4525743640399572811">"- Ingafunda ulwazi kusukela ku-<xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="abc_slice_permission_text_2" msgid="7323565634860251794">"- Ingenza izenzo ngaphakathi kwe-<xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="abc_slice_permission_checkbox" msgid="5696872682700058611">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi ikubonise izingcezu kusukela kunoma iluphi uhlelo lokusebenza"</string>
+
     <string name="abc_slice_permission_allow" msgid="5024599872061409708">"Vumela"</string>
     <string name="abc_slice_permission_deny" msgid="3819478292430407705">"Phika"</string>
 </resources>
diff --git a/slices/core/src/main/res/values/strings.xml b/slices/core/src/main/res/values/strings.xml
index 2959af8..6f96605a 100644
--- a/slices/core/src/main/res/values/strings.xml
+++ b/slices/core/src/main/res/values/strings.xml
@@ -28,9 +28,6 @@
     <!-- Description of what kind of access is given to a slice host [CHAR LIMIT=NONE] -->
     <string name="abc_slice_permission_text_2"> - It can take actions inside <xliff:g id="app" example="Example App">%1$s</xliff:g></string>
 
-    <!-- Text on checkbox allowing the app to show slices from all apps [CHAR LIMIT=NONE] -->
-    <string name="abc_slice_permission_checkbox">Allow <xliff:g id="app" example="Example App">%1$s</xliff:g> to show slices from any app</string>
-
     <!-- Option to grant the slice permission request on the screen [CHAR LIMIT=15] -->
     <string name="abc_slice_permission_allow">Allow</string>
 
diff --git a/webkit/integration-tests/testapp/build.gradle b/webkit/integration-tests/testapp/build.gradle
index 4caa18a..3442df0 100644
--- a/webkit/integration-tests/testapp/build.gradle
+++ b/webkit/integration-tests/testapp/build.gradle
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("AndroidXPlugin")
@@ -24,21 +23,21 @@
     implementation("androidx.appcompat:appcompat:1.1.0")
     implementation("androidx.core:core:1.1.0")
     implementation(project(":webkit:webkit"))
-    implementation(GUAVA_ANDROID)
-    implementation(ESPRESSO_IDLING_NET)
-    implementation(ESPRESSO_IDLING_RESOURCE)
+    implementation(libs.guavaAndroid)
+    implementation(libs.espressoIdlingNet)
+    implementation(libs.espressoIdlingResource)
 
-    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
-    androidTestImplementation(ANDROIDX_TEST_CORE)
-    androidTestImplementation(ANDROIDX_TEST_RUNNER)
-    androidTestImplementation(ANDROIDX_TEST_RULES)
-    androidTestImplementation(ESPRESSO_CORE, excludes.espresso)
-    androidTestImplementation(ESPRESSO_CONTRIB, excludes.espresso)
-    androidTestImplementation(ESPRESSO_IDLING_RESOURCE)
-    androidTestImplementation(ESPRESSO_WEB, excludes.espresso)
-    androidTestImplementation(MOCKITO_CORE, excludes.bytebuddy)
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.espressoCore, excludes.espresso)
+    androidTestImplementation(libs.espressoContrib, excludes.espresso)
+    androidTestImplementation(libs.espressoIdlingResource)
+    androidTestImplementation(libs.espressoWeb, excludes.espresso)
+    androidTestImplementation(libs.mockitoCore, excludes.bytebuddy)
     // DexMaker has it"s own MockMaker
-    androidTestImplementation(DEXMAKER_MOCKITO, excludes.bytebuddy)
+    androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
 }
 
 rootProject.tasks.getByName("buildOnServer").dependsOn(project.path + ":assembleRelease")
diff --git a/webkit/webkit/build.gradle b/webkit/webkit/build.gradle
index a52b165..ff5de9e 100644
--- a/webkit/webkit/build.gradle
+++ b/webkit/webkit/build.gradle
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-import static androidx.build.dependencies.DependenciesKt.*
 import androidx.build.LibraryGroups
 import androidx.build.Publish
 import androidx.build.SupportConfigKt
@@ -28,15 +27,15 @@
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.core:core:1.1.0")
 
-    androidTestImplementation(OKHTTP_MOCKWEBSERVER)
-    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
-    androidTestImplementation(ANDROIDX_TEST_CORE)
-    androidTestImplementation(ANDROIDX_TEST_RUNNER)
-    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(libs.okhttpMockwebserver)
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testRules)
     androidTestImplementation("androidx.concurrent:concurrent-futures:1.0.0")
 
     // Hamcrest matchers:
-    androidTestImplementation(ESPRESSO_CONTRIB, excludes.espresso)
+    androidTestImplementation(libs.espressoContrib, excludes.espresso)
 }
 
 ext {
diff --git a/window/window/src/main/java/androidx/window/ExtensionWindowBackend.kt b/window/window/src/main/java/androidx/window/ExtensionWindowBackend.kt
index 24abe4e..477c79d 100644
--- a/window/window/src/main/java/androidx/window/ExtensionWindowBackend.kt
+++ b/window/window/src/main/java/androidx/window/ExtensionWindowBackend.kt
@@ -141,7 +141,7 @@
     }
 
     /**
-     * Wrapper around [<] that also includes the [Executor]
+     * Wrapper around [Consumer<WindowLayoutInfo>] that also includes the [Executor]
      * on which the callback should run and the [Activity].
      */
     internal class WindowLayoutChangeCallbackWrapper(
diff --git a/window/window/src/main/java/androidx/window/WindowManager.kt b/window/window/src/main/java/androidx/window/WindowManager.kt
index 3c29415..5b6deed 100644
--- a/window/window/src/main/java/androidx/window/WindowManager.kt
+++ b/window/window/src/main/java/androidx/window/WindowManager.kt
@@ -90,7 +90,7 @@
      * current bounds that the user has selected for the [Activity][android.app.Activity]'s
      * window.
      *
-     * @see .getMaximumWindowMetrics
+     * @see getMaximumWindowMetrics
      * @see android.view.WindowManager.getCurrentWindowMetrics
      */
     public fun getCurrentWindowMetrics(): WindowMetrics {
@@ -121,7 +121,7 @@
      * the region describing the side of the device the associated [context&#39;s][Context]
      * window is placed.
      *
-     * @see .getCurrentWindowMetrics
+     * @see getCurrentWindowMetrics
      * @see android.view.WindowManager.getMaximumWindowMetrics
      */
     public fun getMaximumWindowMetrics(): WindowMetrics {