Merge "Add more tests fort AppCard and TitleCard" into androidx-main
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
index 63aadd4..53177b2 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
@@ -28,6 +28,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import java.io.File
+import kotlin.test.assertContains
 import kotlin.test.assertEquals
 import kotlin.test.assertFalse
 import kotlin.test.assertNotNull
@@ -343,6 +344,19 @@
         assertEquals(listOf(Packages.TEST), Shell.getRunningProcessesForPackage(Packages.TEST))
     }
 
+    @SdkSuppress(minSdkVersion = 21)
+    @Test
+    fun checkRootStatus() {
+        if (Shell.isSessionRooted()) {
+            assertContains(Shell.executeCommand("id"), "uid=0(root)")
+        } else {
+            assertFalse(
+                Shell.executeCommand("id").contains("uid=0(root)"),
+                "Shell.isSessionRooted() is false so user should not be root"
+            )
+        }
+    }
+
     @RequiresApi(21)
     private fun pidof(packageName: String): Int? {
         return Shell.getPidsForProcess(packageName).firstOrNull()
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index 7394a61..b78279b 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -149,12 +149,12 @@
     }
 
     /**
-     * Returns true if the shell session is rooted, and thus root commands can be run (e.g. atrace
-     * commands with root-only tags)
+     * Returns true if the shell session is rooted or su is usable, and thus root commands can be
+     * run (e.g. atrace commands with root-only tags)
      */
     @RequiresApi(21)
     fun isSessionRooted(): Boolean {
-        return ShellImpl.executeCommand("getprop service.adb.root").trim() == "1"
+        return ShellImpl.isSessionRooted || ShellImpl.isSuAvailable
     }
 
     /**
@@ -339,11 +339,38 @@
     private val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
 
     /**
+     * When true, the session is already rooted and all commands run as root by default.
+     */
+    var isSessionRooted = false
+
+    /**
+     * When true, su is available for running commands and scripts as root.
+     */
+    var isSuAvailable = false
+
+    init {
+        // These variables are used in executeCommand and executeScript, so we keep them as var
+        // instead of val and use a separate initializer
+        isSessionRooted = executeCommand("id").contains("uid=0(root)")
+        isSuAvailable = executeScript(
+            "su root id",
+            null,
+            false
+        ).first.contains("uid=0(root)")
+    }
+
+    /**
      * Reimplementation of UiAutomator's Device.executeShellCommand,
      * to avoid the UiAutomator dependency
      */
     fun executeCommand(cmd: String): String {
-        val parcelFileDescriptor = uiAutomation.executeShellCommand(cmd)
+        val parcelFileDescriptor = uiAutomation.executeShellCommand(
+            if (!isSessionRooted && isSuAvailable) {
+                "su root $cmd"
+            } else {
+                cmd
+            }
+        )
         AutoCloseInputStream(parcelFileDescriptor).use { inputStream ->
             return inputStream.readBytes().toString(Charset.defaultCharset())
         }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index 1b5b012..55e0c22 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -144,6 +144,13 @@
  */
 const val KMP_ENABLE_LINUX = "androidx.kmp.linux.enabled"
 
+/**
+ * If true, include all native targets when building KMP.
+ * Replaces KMP_ENABLE_MAC and KMP_ENABLE_LINUX in collections, and will eventually be
+ * consolidated into the AndroidX plugin.
+ */
+const val KMP_ENABLE_NATIVE = "androidx.kmp.native.enabled"
+
 val ALL_ANDROIDX_PROPERTIES = setOf(
     ALL_WARNINGS_AS_ERRORS,
     ALTERNATIVE_PROJECT_URL,
@@ -171,7 +178,8 @@
     KMP_GITHUB_BUILD,
     KMP_ENABLE_MAC,
     KMP_ENABLE_JS,
-    KMP_ENABLE_LINUX
+    KMP_ENABLE_LINUX,
+    KMP_ENABLE_NATIVE
 )
 
 /**
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
index 602b86b..a35c78f 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
@@ -27,31 +27,40 @@
 import android.hardware.camera2.CaptureRequest
 import android.hardware.camera2.TotalCaptureResult
 import android.media.ImageReader
+import android.media.ImageWriter
 import android.os.Build
 import android.os.Handler
 import android.os.Looper
+import android.os.SystemClock
 import android.util.Size
 import android.view.Surface
 import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
 import androidx.camera.camera2.internal.compat.quirk.DeviceQuirks
+import androidx.camera.camera2.internal.util.RequestProcessorRequest
 import androidx.camera.camera2.interop.CaptureRequestOptions
+import androidx.camera.core.CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.Preview
 import androidx.camera.core.impl.CameraCaptureCallback
+import androidx.camera.core.impl.CameraCaptureFailure
 import androidx.camera.core.impl.CameraCaptureResult
 import androidx.camera.core.impl.CaptureConfig
 import androidx.camera.core.impl.Config
 import androidx.camera.core.impl.DeferrableSurface
 import androidx.camera.core.impl.ImmediateSurface
+import androidx.camera.core.impl.OptionsBundle
+import androidx.camera.core.impl.OutputSurface
+import androidx.camera.core.impl.RequestProcessor
 import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.SessionProcessor
+import androidx.camera.core.impl.SessionProcessorSurface
 import androidx.camera.core.impl.TagBundle
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CameraUtil.CameraDeviceHolder
 import androidx.camera.testing.CameraUtil.PreTestCameraIdList
-import androidx.camera.testing.fakes.FakeSessionProcessor
 import androidx.concurrent.futures.await
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
@@ -70,6 +79,7 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withTimeout
+import kotlinx.coroutines.withTimeoutOrNull
 import org.junit.After
 import org.junit.Assume.assumeTrue
 import org.junit.Before
@@ -78,6 +88,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+const val FAKE_CAPTURE_SEQUENCE_ID = 1
 const val JPEG_ORIENTATION_VALUE = 90
 const val JPEG_QUALITY_VALUE: Byte = 50
 
@@ -94,9 +105,9 @@
 @SdkSuppress(minSdkVersion = 23)
 class ProcessingCaptureSessionTest(
     private var lensFacing: Int,
-    // The pair specifies (Output image format to Input image format). SessionProcessor will
-    // create the surface even if input format is the same as output format. But if the
-    // output format is null, it means no conversion and original surface is used directly.
+    // The pair specifies (Origin image format to Transformed format), SessionProcessor will
+    // create the surface even if transformed format is the same as origin format but if the
+    // transformed format is null, it means no conversion and original surface is used directly.
     private var previewFormatConvert: Pair<Int, Int?>,
     private var captureFormatConvert: Pair<Int, Int?>,
 ) {
@@ -133,7 +144,7 @@
     private lateinit var cameraDeviceHolder: CameraDeviceHolder
     private lateinit var captureSessionRepository: CaptureSessionRepository
     private lateinit var captureSessionOpenerBuilder: SynchronizedCaptureSessionOpener.Builder
-    private lateinit var sessionProcessor: FakeSessionProcessor
+    private lateinit var sessionProcessor: CustomSessionProcessor
     private lateinit var executor: Executor
     private lateinit var handler: Handler
     private lateinit var sessionConfigParameters: SessionConfigParameters
@@ -151,10 +162,7 @@
 
         handler = Handler(Looper.getMainLooper())
         executor = CameraXExecutors.newHandlerExecutor(handler)
-        sessionProcessor = FakeSessionProcessor(
-            inputFormatPreview = previewFormatConvert.second,
-            inputFormatCapture = captureFormatConvert.second
-        )
+        sessionProcessor = CustomSessionProcessor()
 
         val cameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing)!!
         camera2CameraInfo = Camera2CameraInfoImpl(cameraId, cameraManagerCompat)
@@ -815,7 +823,7 @@
             )
             captureOutputDeferrableSurface = ImmediateSurface(
                 captureImageReader.surface, Size(640, 480),
-                captureFormat
+                JPEG
             )
             captureOutputDeferrableSurface.setContainerClass(ImageCapture::class.java)
             captureOutputDeferrableSurface.terminationFuture.addListener(
@@ -925,4 +933,297 @@
             closeOutputSurfaces()
         }
     }
+
+    inner class CustomSessionProcessor : SessionProcessor {
+        private lateinit var previewProcessorSurface: DeferrableSurface
+        private lateinit var captureProcessorSurface: DeferrableSurface
+        private var intermediaPreviewImageReader: ImageReader? = null
+        private var intermediaCaptureImageReader: ImageReader? = null
+        private var intermediaPreviewImageWriter: ImageWriter? = null
+        private var intermediaCaptureImageWriter: ImageWriter? = null
+
+        private val previewOutputConfigId = 1
+        private val captureOutputConfigId = 2
+
+        private var requestProcessor: RequestProcessor? = null
+
+        // Values of these Deferred are the timestamp to complete.
+        private val initSessionCalled = CompletableDeferred<Long>()
+        private val deInitSessionCalled = CompletableDeferred<Long>()
+        private val onCaptureSessionStartCalled = CompletableDeferred<Long>()
+        private val onCaptureSessionEndCalled = CompletableDeferred<Long>()
+        private val startRepeatingCalled = CompletableDeferred<Long>()
+        private val startCaptureCalled = CompletableDeferred<Long>()
+        private val setParametersCalled = CompletableDeferred<Config>()
+        private var latestParameters: Config = OptionsBundle.emptyBundle()
+        private var blockRunAfterInitSession: () -> Unit = {}
+
+        fun releaseSurfaces() {
+            intermediaPreviewImageReader?.close()
+            intermediaCaptureImageReader?.close()
+        }
+
+        fun runAfterInitSession(block: () -> Unit) {
+            blockRunAfterInitSession = block
+        }
+
+        override fun initSession(
+            cameraInfo: CameraInfo,
+            previewSurfaceConfig: OutputSurface,
+            imageCaptureSurfaceConfig: OutputSurface,
+            imageAnalysisSurfaceConfig: OutputSurface?
+        ): SessionConfig {
+            initSessionCalled.complete(SystemClock.elapsedRealtimeNanos())
+            val handler = Handler(Looper.getMainLooper())
+
+            var sessionBuilder = SessionConfig.Builder()
+
+            // Preview
+            lateinit var previewTransformedSurface: Surface
+            if (previewFormatConvert.second == null) { // no conversion, use origin surface.
+                previewTransformedSurface = previewSurfaceConfig.surface
+            } else {
+                intermediaPreviewImageReader = ImageReader.newInstance(
+                    640, 480,
+                    previewFormatConvert.second!!, 2
+                )
+                previewTransformedSurface = intermediaPreviewImageReader!!.surface
+
+                intermediaPreviewImageWriter = ImageWriter.newInstance(
+                    previewSurfaceConfig.surface, 2
+                )
+
+                intermediaPreviewImageReader!!.setOnImageAvailableListener(
+                    {
+                        it.acquireNextImage().use {
+                            val imageDequeued = intermediaPreviewImageWriter!!.dequeueInputImage()
+                            intermediaPreviewImageWriter!!.queueInputImage(imageDequeued)
+                        }
+                    },
+                    handler
+                )
+            }
+            previewProcessorSurface =
+                SessionProcessorSurface(previewTransformedSurface, previewOutputConfigId)
+            previewProcessorSurface.terminationFuture.addListener(
+                {
+                    intermediaPreviewImageReader?.close()
+                    intermediaPreviewImageWriter?.close()
+                },
+                CameraXExecutors.directExecutor()
+            )
+            sessionBuilder.addSurface(previewProcessorSurface)
+
+            // Capture
+            lateinit var captureTransformedSurface: Surface
+            if (captureFormatConvert.second == null) { // no conversion, use origin surface.
+                captureTransformedSurface = imageCaptureSurfaceConfig.surface
+            } else {
+                intermediaCaptureImageReader = ImageReader.newInstance(
+                    640, 480,
+                    captureFormatConvert.second!!, 2
+                )
+                captureTransformedSurface = intermediaCaptureImageReader!!.surface
+
+                intermediaCaptureImageWriter = ImageWriter.newInstance(
+                    imageCaptureSurfaceConfig.surface, 2
+                )
+
+                intermediaCaptureImageReader!!.setOnImageAvailableListener(
+                    {
+                        it.acquireNextImage().use {
+                            val imageDequeued = intermediaCaptureImageWriter!!.dequeueInputImage()
+                            intermediaCaptureImageWriter!!.queueInputImage(imageDequeued)
+                        }
+                    },
+                    handler
+                )
+            }
+            captureProcessorSurface =
+                SessionProcessorSurface(captureTransformedSurface, captureOutputConfigId)
+
+            captureProcessorSurface.terminationFuture.addListener(
+                {
+                    intermediaCaptureImageReader?.close()
+                    intermediaCaptureImageWriter?.close()
+                },
+                CameraXExecutors.directExecutor()
+            )
+            sessionBuilder.addSurface(captureProcessorSurface)
+
+            sessionBuilder.setTemplateType(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG)
+            val sessionConfig = sessionBuilder.build()
+            blockRunAfterInitSession()
+            return sessionConfig
+        }
+
+        override fun deInitSession() {
+            deInitSessionCalled.complete(SystemClock.elapsedRealtimeNanos())
+            previewProcessorSurface.close()
+            captureProcessorSurface.close()
+        }
+
+        override fun setParameters(config: Config) {
+            setParametersCalled.complete(config)
+            latestParameters = config
+        }
+
+        override fun onCaptureSessionStart(_requestProcessor: RequestProcessor) {
+            onCaptureSessionStartCalled.complete(SystemClock.elapsedRealtimeNanos())
+            requestProcessor = _requestProcessor
+        }
+
+        override fun onCaptureSessionEnd() {
+            onCaptureSessionEndCalled.complete(SystemClock.elapsedRealtimeNanos())
+        }
+
+        fun getLatestParameters(): Config {
+            return latestParameters
+        }
+
+        override fun startRepeating(callback: SessionProcessor.CaptureCallback): Int {
+            startRepeatingCalled.complete(SystemClock.elapsedRealtimeNanos())
+            val builder = RequestProcessorRequest.Builder().apply {
+                addTargetOutputConfigId(previewOutputConfigId)
+                setParameters(latestParameters)
+                setTemplateId(CameraDevice.TEMPLATE_PREVIEW)
+            }
+
+            requestProcessor!!.setRepeating(
+                builder.build(),
+                object : RequestProcessor.Callback {
+                    override fun onCaptureStarted(
+                        request: RequestProcessor.Request,
+                        frameNumber: Long,
+                        timestamp: Long
+                    ) {}
+
+                    override fun onCaptureProgressed(
+                        request: RequestProcessor.Request,
+                        captureResult: CameraCaptureResult
+                    ) {}
+
+                    override fun onCaptureCompleted(
+                        request: RequestProcessor.Request,
+                        captureResult: CameraCaptureResult
+                    ) {
+                        callback.onCaptureSequenceCompleted(1)
+                    }
+
+                    override fun onCaptureFailed(
+                        request: RequestProcessor.Request,
+                        captureFailure: CameraCaptureFailure
+                    ) {}
+
+                    override fun onCaptureBufferLost(
+                        request: RequestProcessor.Request,
+                        frameNumber: Long,
+                        outputConfigId: Int
+                    ) {}
+
+                    override fun onCaptureSequenceCompleted(
+                        sequenceId: Int,
+                        frameNumber: Long
+                    ) {}
+
+                    override fun onCaptureSequenceAborted(sequenceId: Int) {
+                    }
+                }
+            )
+            return FAKE_CAPTURE_SEQUENCE_ID
+        }
+
+        override fun stopRepeating() {
+        }
+
+        override fun startCapture(callback: SessionProcessor.CaptureCallback): Int {
+            startCaptureCalled.complete(SystemClock.elapsedRealtimeNanos())
+            val request = RequestProcessorRequest.Builder().apply {
+                addTargetOutputConfigId(captureOutputConfigId)
+                setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE)
+            }.build()
+
+            requestProcessor!!.submit(
+                request,
+                object : RequestProcessor.Callback {
+                    override fun onCaptureCompleted(
+                        request: RequestProcessor.Request,
+                        captureResult: CameraCaptureResult
+                    ) {
+                        callback.onCaptureSequenceCompleted(1)
+                    }
+
+                    override fun onCaptureStarted(
+                        request: RequestProcessor.Request,
+                        frameNumber: Long,
+                        timestamp: Long
+                    ) {}
+
+                    override fun onCaptureProgressed(
+                        request: RequestProcessor.Request,
+                        captureResult: CameraCaptureResult
+                    ) {}
+
+                    override fun onCaptureFailed(
+                        request: RequestProcessor.Request,
+                        captureFailure: CameraCaptureFailure
+                    ) {
+                        callback.onCaptureFailed(1)
+                    }
+
+                    override fun onCaptureBufferLost(
+                        request: RequestProcessor.Request,
+                        frameNumber: Long,
+                        outputConfigId: Int
+                    ) {}
+
+                    override fun onCaptureSequenceCompleted(sequenceId: Int, frameNumber: Long) {}
+
+                    override fun onCaptureSequenceAborted(sequenceId: Int) {}
+                }
+            )
+            return FAKE_CAPTURE_SEQUENCE_ID
+        }
+
+        override fun abortCapture(captureSequenceId: Int) {
+        }
+
+        suspend fun assertInitSessionInvoked(): Long {
+            return initSessionCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun wasInitSessionInvoked(): Boolean {
+            val result = withTimeoutOrNull(3000) { initSessionCalled.await() }
+            return result != null
+        }
+
+        suspend fun assertDeInitSessionInvoked(): Long {
+            return deInitSessionCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun assertOnCaptureSessionStartInvoked(): Long {
+            return onCaptureSessionStartCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun wasOnCaptureSessionStartInvoked(): Boolean {
+            val result = withTimeoutOrNull(3000) { onCaptureSessionStartCalled.await() }
+            return result != null
+        }
+
+        suspend fun assertOnCaptureEndInvoked(): Long {
+            return onCaptureSessionEndCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun assertStartRepeatingInvoked(): Long {
+            return startRepeatingCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun assertStartCaptureInvoked(): Long {
+            return startCaptureCalled.awaitWithTimeout(3000)
+        }
+
+        suspend fun assertSetParametersInvoked(): Config {
+            return setParametersCalled.awaitWithTimeout(3000)
+        }
+    }
 }
\ No newline at end of file
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
index b3dd1ee..203c4dc 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
@@ -17,7 +17,6 @@
 package androidx.camera.camera2.internal;
 
 import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CaptureRequest;
 import android.util.Size;
 
 import androidx.annotation.NonNull;
@@ -344,25 +343,9 @@
                 break;
             case ON_CAPTURE_SESSION_STARTED:
                 mIsExecutingStillCaptureRequest = true;
-                CaptureRequestOptions.Builder builder =
-                        CaptureRequestOptions.Builder.from(
-                                captureConfig.getImplementationOptions());
-
-                if (captureConfig.getImplementationOptions().containsOption(
-                        CaptureConfig.OPTION_ROTATION)) {
-                    builder.setCaptureRequestOption(CaptureRequest.JPEG_ORIENTATION,
-                            captureConfig.getImplementationOptions().retrieveOption(
-                                    CaptureConfig.OPTION_ROTATION));
-                }
-
-                if (captureConfig.getImplementationOptions().containsOption(
-                        CaptureConfig.OPTION_JPEG_QUALITY)) {
-                    builder.setCaptureRequestOption(CaptureRequest.JPEG_QUALITY,
-                            captureConfig.getImplementationOptions().retrieveOption(
-                                    CaptureConfig.OPTION_JPEG_QUALITY).byteValue());
-                }
-
-                mStillCaptureOptions = builder.build();
+                mStillCaptureOptions =
+                        CaptureRequestOptions.Builder.from(captureConfig.getImplementationOptions())
+                                .build();
                 updateParameters(mSessionOptions, mStillCaptureOptions);
                 mSessionProcessor.startCapture(new SessionProcessor.CaptureCallback() {
                     @Override
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
index 50d851e..f831878 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CapturePipelineTest.kt
@@ -166,7 +166,7 @@
         // Act.
         pipeline.executeCapture(
             listOf(singleRequest),
-            ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH,
+            FLASH_MODE_OFF,
         )
 
         // Assert.
diff --git a/camera/camera-core/lint-baseline.xml b/camera/camera-core/lint-baseline.xml
index aaff45e..4aba0fb 100644
--- a/camera/camera-core/lint-baseline.xml
+++ b/camera/camera-core/lint-baseline.xml
@@ -128,6 +128,116 @@
         errorLine1="    @Override"
         errorLine2="    ^">
         <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="53"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="76"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="103"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="108"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="113"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="118"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="123"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Nullable"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="128"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="134"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
+            file="src/main/java/androidx/camera/core/AndroidImageReaderProxy.java"
+            line="146"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="BanSynchronizedMethods"
+        message="Use of synchronized methods is not recommended"
+        errorLine1="    @Override"
+        errorLine2="    ^">
+        <location
             file="src/main/java/androidx/camera/core/ForwardingImageProxy.java"
             line="65"
             column="5"/>
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt
deleted file mode 100644
index be57eaf..0000000
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ModifiableImageReaderProxyTest.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.core
-
-import android.graphics.ImageFormat
-import android.graphics.Matrix
-import android.media.ImageReader
-import android.media.ImageWriter
-import android.os.Handler
-import androidx.camera.core.impl.ImageReaderProxy
-import androidx.camera.core.impl.MutableTagBundle
-import androidx.camera.core.impl.utils.executor.CameraXExecutors
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Mockito
-import org.mockito.Mockito.spy
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 23) // This test uses ImageWriter which is supported from api 23.
-class ModifiableImageReaderProxyTest {
-    private lateinit var imageReader: ImageReader
-    private lateinit var imageReaderProxy: ModifiableImageReaderProxy
-    private var imageWriter: ImageWriter? = null
-
-    @Before
-    fun setUp() {
-        imageReader = spy(ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2))
-        imageReaderProxy = ModifiableImageReaderProxy(imageReader)
-    }
-
-    @After
-    fun tearDown() {
-        imageReaderProxy.close()
-        imageWriter?.close()
-    }
-
-    @Test
-    fun canModifyImageTagBundle_acquireNext() {
-        generateImage(imageReader)
-
-        val tagBundle = MutableTagBundle.create()
-        imageReaderProxy.setImageTagBundle(tagBundle)
-        val imageProxy = imageReaderProxy.acquireNextImage()
-        assertThat(imageProxy!!.imageInfo.tagBundle).isEqualTo(tagBundle)
-    }
-
-    @Test
-    fun canModifyImageTagBundle_acquireLatest() {
-        generateImage(imageReader)
-
-        val tagBundle = MutableTagBundle.create()
-        imageReaderProxy.setImageTagBundle(tagBundle)
-        val imageProxy = imageReaderProxy.acquireLatestImage()
-        assertThat(imageProxy!!.imageInfo.tagBundle).isEqualTo(tagBundle)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageTimestamp_acquireNext() {
-        generateImage(imageReader)
-
-        imageReaderProxy.setImageTimeStamp(1000)
-        val imageProxy = imageReaderProxy.acquireNextImage()
-        assertThat(imageProxy!!.imageInfo.timestamp).isEqualTo(1000)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageTimestamp_acquireLatest() {
-        generateImage(imageReader)
-
-        imageReaderProxy.setImageTimeStamp(1000)
-        val imageProxy = imageReaderProxy.acquireLatestImage()
-        assertThat(imageProxy!!.imageInfo.timestamp).isEqualTo(1000)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageRotationDegrees_acquireNext() {
-        generateImage(imageReader)
-
-        imageReaderProxy.setImageRotationDegrees(90)
-        val imageProxy = imageReaderProxy.acquireNextImage()
-        assertThat(imageProxy!!.imageInfo.rotationDegrees).isEqualTo(90)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageRotationDegress_acquireLatest() {
-        generateImage(imageReader)
-
-        imageReaderProxy.setImageRotationDegrees(90)
-        val imageProxy = imageReaderProxy.acquireLatestImage()
-        assertThat(imageProxy!!.imageInfo.rotationDegrees).isEqualTo(90)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageMatrix_acquireNext() {
-        generateImage(imageReader)
-
-        val matrix = Matrix()
-        imageReaderProxy.setImageSensorToBufferTransformaMatrix(matrix)
-        val imageProxy = imageReaderProxy.acquireNextImage()
-        assertThat(imageProxy!!.imageInfo.sensorToBufferTransformMatrix).isSameInstanceAs(matrix)
-        imageProxy.close()
-    }
-
-    @Test
-    fun canModifyImageMatrix_acquireLatest() {
-        generateImage(imageReader)
-
-        val matrix = Matrix()
-        imageReaderProxy.setImageSensorToBufferTransformaMatrix(matrix)
-        val imageProxy = imageReaderProxy.acquireLatestImage()
-        assertThat(imageProxy!!.imageInfo.sensorToBufferTransformMatrix).isSameInstanceAs(matrix)
-        imageProxy.close()
-    }
-
-    private fun generateImage(imageReader: ImageReader) {
-        imageWriter = ImageWriter.newInstance(imageReader.surface, 2)
-        val image = imageWriter!!.dequeueInputImage()
-        imageWriter!!.queueInputImage(image)
-    }
-
-    @Test
-    fun parametersMatchesInnerImageReader() {
-        assertThat(imageReaderProxy.width).isEqualTo(640)
-        assertThat(imageReaderProxy.height).isEqualTo(480)
-        assertThat(imageReaderProxy.imageFormat).isEqualTo(ImageFormat.YUV_420_888)
-        assertThat(imageReaderProxy.maxImages).isEqualTo(2)
-        assertThat(imageReaderProxy.surface).isEqualTo(imageReader.surface)
-    }
-
-    @Test
-    fun setOnImageAvailableListener_innerReaderIsInvoked() {
-        val listener = Mockito.mock(
-            ImageReaderProxy.OnImageAvailableListener::class.java
-        )
-
-        imageReaderProxy.setOnImageAvailableListener(
-            listener,
-            CameraXExecutors.directExecutor()
-        )
-
-        val transformedListenerCaptor = ArgumentCaptor.forClass(
-            ImageReader.OnImageAvailableListener::class.java
-        )
-        val handlerCaptor = ArgumentCaptor.forClass(
-            Handler::class.java
-        )
-        Mockito.verify(imageReader, Mockito.times(1))
-            .setOnImageAvailableListener(
-                transformedListenerCaptor.capture(), handlerCaptor.capture()
-            )
-
-        transformedListenerCaptor.value.onImageAvailable(imageReader)
-        Mockito.verify(listener, Mockito.times(1)).onImageAvailable(imageReaderProxy)
-    }
-}
\ No newline at end of file
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageReaderProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageReaderProxy.java
index 92efe7d..ea2a97e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageReaderProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageReaderProxy.java
@@ -36,10 +36,9 @@
  * ImageReader}.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-class AndroidImageReaderProxy implements ImageReaderProxy {
-    @GuardedBy("mLock")
+final class AndroidImageReaderProxy implements ImageReaderProxy {
+    @GuardedBy("this")
     private final ImageReader mImageReader;
-    private final Object mLock = new Object();
 
     /**
      * Creates a new instance which wraps the given image reader.
@@ -53,52 +52,48 @@
 
     @Override
     @Nullable
-    public ImageProxy acquireLatestImage() {
-        synchronized (mLock) {
-            Image image;
-            try {
-                image = mImageReader.acquireLatestImage();
-            } catch (RuntimeException e) {
+    public synchronized ImageProxy acquireLatestImage() {
+        Image image;
+        try {
+            image = mImageReader.acquireLatestImage();
+        } catch (RuntimeException e) {
             /* In API level 23 or below,  it will throw "java.lang.RuntimeException:
                ImageReaderContext is not initialized" when ImageReader is closed. To make the
                behavior consistent as newer API levels,  we make it return null Image instead.*/
-                if (isImageReaderContextNotInitializedException(e)) {
-                    image = null;
-                } else {
-                    throw e;  // only catch RuntimeException:ImageReaderContext is not initialized
-                }
+            if (isImageReaderContextNotInitializedException(e)) {
+                image = null;
+            } else {
+                throw e;  // only catch RuntimeException:ImageReaderContext is not initialized
             }
-
-            if (image == null) {
-                return null;
-            }
-            return new AndroidImageProxy(image);
         }
+
+        if (image == null) {
+            return null;
+        }
+        return new AndroidImageProxy(image);
     }
 
     @Override
     @Nullable
-    public ImageProxy acquireNextImage() {
-        synchronized (mLock) {
-            Image image;
-            try {
-                image = mImageReader.acquireNextImage();
-            } catch (RuntimeException e) {
+    public synchronized ImageProxy acquireNextImage() {
+        Image image;
+        try {
+            image = mImageReader.acquireNextImage();
+        } catch (RuntimeException e) {
             /* In API level 23 or below,  it will throw "java.lang.RuntimeException:
                ImageReaderContext is not initialized" when ImageReader is closed. To make the
                behavior consistent as newer API levels,  we make it return null Image instead.*/
-                if (isImageReaderContextNotInitializedException(e)) {
-                    image = null;
-                } else {
-                    throw e;  // only catch RuntimeException:ImageReaderContext is not initialized
-                }
+            if (isImageReaderContextNotInitializedException(e)) {
+                image = null;
+            } else {
+                throw e;  // only catch RuntimeException:ImageReaderContext is not initialized
             }
-
-            if (image == null) {
-                return null;
-            }
-            return new AndroidImageProxy(image);
         }
+
+        if (image == null) {
+            return null;
+        }
+        return new AndroidImageProxy(image);
     }
 
     private boolean isImageReaderContextNotInitializedException(RuntimeException e) {
@@ -106,66 +101,50 @@
     }
 
     @Override
-    public void close() {
-        synchronized (mLock) {
-            mImageReader.close();
-        }
+    public synchronized void close() {
+        mImageReader.close();
     }
 
     @Override
-    public int getHeight() {
-        synchronized (mLock) {
-            return mImageReader.getHeight();
-        }
+    public synchronized int getHeight() {
+        return mImageReader.getHeight();
     }
 
     @Override
-    public int getWidth() {
-        synchronized (mLock) {
-            return mImageReader.getWidth();
-        }
+    public synchronized int getWidth() {
+        return mImageReader.getWidth();
     }
 
     @Override
-    public int getImageFormat() {
-        synchronized (mLock) {
-            return mImageReader.getImageFormat();
-        }
+    public synchronized int getImageFormat() {
+        return mImageReader.getImageFormat();
     }
 
     @Override
-    public int getMaxImages() {
-        synchronized (mLock) {
-            return mImageReader.getMaxImages();
-        }
+    public synchronized int getMaxImages() {
+        return mImageReader.getMaxImages();
     }
 
     @Nullable
     @Override
-    public Surface getSurface() {
-        synchronized (mLock) {
-            return mImageReader.getSurface();
-        }
+    public synchronized Surface getSurface() {
+        return mImageReader.getSurface();
     }
 
     @Override
-    public void setOnImageAvailableListener(
+    public synchronized void setOnImageAvailableListener(
             @NonNull OnImageAvailableListener listener,
             @NonNull Executor executor) {
-        synchronized (mLock) {
-            // ImageReader does not accept an executor. As a workaround, the callback is run on main
-            // handler then immediately posted to the executor.
-            ImageReader.OnImageAvailableListener transformedListener = (imageReader) ->
-                    executor.execute(() -> listener.onImageAvailable(AndroidImageReaderProxy.this));
-            mImageReader.setOnImageAvailableListener(transformedListener,
-                    MainThreadAsyncHandler.getInstance());
-        }
+        // ImageReader does not accept an executor. As a workaround, the callback is run on main
+        // handler then immediately posted to the executor.
+        ImageReader.OnImageAvailableListener transformedListener = (imageReader) ->
+                executor.execute(() -> listener.onImageAvailable(AndroidImageReaderProxy.this));
+        mImageReader.setOnImageAvailableListener(transformedListener,
+                MainThreadAsyncHandler.getInstance());
     }
 
     @Override
-    public void clearOnImageAvailableListener() {
-        synchronized (mLock) {
-            mImageReader.setOnImageAvailableListener(null, null);
-        }
+    public synchronized void clearOnImageAvailableListener() {
+        mImageReader.setOnImageAvailableListener(null, null);
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index b1b4c0c..053af09 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -31,7 +31,6 @@
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_MAX_CAPTURE_STAGES;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_MAX_RESOLUTION;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_SESSION_CONFIG_UNPACKER;
-import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_SESSION_PROCESSOR_ENABLED;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_SUPPORTED_RESOLUTIONS;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_TARGET_ASPECT_RATIO;
@@ -91,7 +90,6 @@
 import androidx.camera.core.impl.ImmediateSurface;
 import androidx.camera.core.impl.MutableConfig;
 import androidx.camera.core.impl.MutableOptionsBundle;
-import androidx.camera.core.impl.MutableTagBundle;
 import androidx.camera.core.impl.OptionsBundle;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
@@ -312,11 +310,6 @@
      */
     private boolean mUseSoftwareJpeg = false;
 
-    /**
-     * Whether SessionProcessor is enabled.
-     */
-    private boolean mIsSessionProcessorEnabled = true;
-
     ////////////////////////////////////////////////////////////////////////////////////////////
     // [UseCase attached dynamic] - Can change but is only available when the UseCase is attached.
     ////////////////////////////////////////////////////////////////////////////////////////////
@@ -390,54 +383,6 @@
                                     resolution.getHeight(), getImageFormat(), MAX_IMAGES, 0));
             mMetadataMatchingCaptureCallback = new CameraCaptureCallback() {
             };
-        } else if (mIsSessionProcessorEnabled) {
-            ImageReaderProxy imageReader;
-            if (getImageFormat() == ImageFormat.JPEG) {
-                imageReader =
-                        new AndroidImageReaderProxy(ImageReader.newInstance(resolution.getWidth(),
-                                resolution.getHeight(), getImageFormat(), MAX_IMAGES));
-            } else if (getImageFormat() == ImageFormat.YUV_420_888) { // convert it into Jpeg
-                if (Build.VERSION.SDK_INT >= 26) {
-                    // Jpeg rotation / quality will be set to softwareJpegProcessor later in
-                    // ImageCaptureRequestProcessor.
-                    mYuvToJpegProcessor =
-                            new YuvToJpegProcessor(getJpegQualityInternal(), MAX_IMAGES);
-
-                    ModifiableImageReaderProxy inputReader =
-                            new ModifiableImageReaderProxy(
-                                    ImageReader.newInstance(resolution.getWidth(),
-                                            resolution.getHeight(),
-                                            ImageFormat.YUV_420_888,
-                                            MAX_IMAGES));
-
-                    CaptureBundle captureBundle = CaptureBundles.singleDefaultCaptureBundle();
-                    ProcessingImageReader processingImageReader = new ProcessingImageReader.Builder(
-                            inputReader,
-                            captureBundle,
-                            mYuvToJpegProcessor
-                    ).setPostProcessExecutor(mExecutor).setOutputFormat(ImageFormat.JPEG).build();
-
-                    // Ensure the ImageProxy contains the same capture stage id expected from the
-                    // ProcessingImageReader.
-                    MutableTagBundle tagBundle = MutableTagBundle.create();
-                    tagBundle.putTag(processingImageReader.getTagBundleKey(),
-                            captureBundle.getCaptureStages().get(0).getId());
-                    inputReader.setImageTagBundle(tagBundle);
-
-                    YuvToJpegProcessor processorToClose = mYuvToJpegProcessor;
-                    processingImageReader.getCloseFuture().addListener(() -> {
-                        processorToClose.close();
-                    }, CameraXExecutors.directExecutor());
-
-                    imageReader = processingImageReader;
-                } else {
-                    throw new UnsupportedOperationException("Does not support API level < 26");
-                }
-            } else {
-                throw new IllegalArgumentException("Unsupported image format:" + getImageFormat());
-            }
-            mMetadataMatchingCaptureCallback = new CameraCaptureCallback() {};
-            mImageReader = new SafeCloseImageReaderProxy(imageReader);
         } else if (mCaptureProcessor != null || mUseSoftwareJpeg) {
             // Capture processor set from configuration takes precedence over software JPEG.
             CaptureProcessor captureProcessor = mCaptureProcessor;
@@ -468,14 +413,11 @@
             }
 
             // TODO: To allow user to use an Executor for the image processing.
-            mProcessingImageReader = new ProcessingImageReader.Builder(
-                    resolution.getWidth(),
-                    resolution.getHeight(),
-                    inputFormat,
-                    mMaxCaptureStages,
+            mProcessingImageReader = new ProcessingImageReader.Builder(resolution.getWidth(),
+                    resolution.getHeight(), inputFormat, mMaxCaptureStages,
                     getCaptureBundle(CaptureBundles.singleDefaultCaptureBundle()),
-                    captureProcessor
-            ).setPostProcessExecutor(mExecutor).setOutputFormat(outputFormat).build();
+                    captureProcessor).setPostProcessExecutor(mExecutor).setOutputFormat(
+                    outputFormat).build();
 
             mMetadataMatchingCaptureCallback = mProcessingImageReader.getCameraCaptureCallback();
             mImageReader = new SafeCloseImageReaderProxy(mProcessingImageReader);
@@ -712,21 +654,7 @@
                 builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT,
                         ImageFormat.YUV_420_888);
             } else {
-                List<Pair<Integer, Size[]>> supportedSizes =
-                        builder.getMutableConfig().retrieveOption(OPTION_SUPPORTED_RESOLUTIONS,
-                                null);
-                if (supportedSizes == null) {
-                    builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT, ImageFormat.JPEG);
-                } else {
-                    // Use Jpeg first if supported.
-                    if (isImageFormatSupported(supportedSizes, ImageFormat.JPEG)) {
-                        builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT,
-                                ImageFormat.JPEG);
-                    } else if (isImageFormatSupported(supportedSizes, ImageFormat.YUV_420_888)) {
-                        builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT,
-                                ImageFormat.YUV_420_888);
-                    }
-                }
+                builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT, ImageFormat.JPEG);
             }
         }
 
@@ -737,18 +665,6 @@
         return builder.getUseCaseConfig();
     }
 
-    private static boolean isImageFormatSupported(List<Pair<Integer, Size[]>> supportedSizes,
-            int imageFormat) {
-        if (supportedSizes == null) {
-            return false;
-        }
-        for (Pair<Integer, Size[]> supportedSize : supportedSizes) {
-            if (supportedSize.first.equals(imageFormat)) {
-                return true;
-            }
-        }
-        return false;
-    }
     /**
      * Configures flash mode to CameraControlInternal once it is ready.
      *
@@ -1638,7 +1554,6 @@
         // This will only be set to true if software JPEG was requested and
         // enforceSoftwareJpegConstraints() hasn't removed the request.
         mUseSoftwareJpeg = useCaseConfig.isSoftwareJpegEncoderRequested();
-        mIsSessionProcessorEnabled = useCaseConfig.isSessionProcessorEnabled();
 
         CameraInternal camera = getCamera();
         Preconditions.checkNotNull(camera, "Attached camera cannot be null");
@@ -2591,17 +2506,6 @@
         }
 
         /**
-         * Set the flag to indicate whether SessionProcessor is enabled.
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @NonNull
-        public Builder setSessionProcessorEnabled(boolean enabled) {
-            getMutableConfig().insertOption(OPTION_SESSION_PROCESSOR_ENABLED, enabled);
-            return this;
-        }
-
-        /**
          * Sets the max number of {@link CaptureStage}.
          *
          * @param maxCaptureStages The max CaptureStage number.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ModifiableImageReaderProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/ModifiableImageReaderProxy.java
deleted file mode 100644
index 4d9250b..0000000
--- a/camera/camera-core/src/main/java/androidx/camera/core/ModifiableImageReaderProxy.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.core;
-
-import android.graphics.Matrix;
-import android.media.ImageReader;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.camera.core.impl.TagBundle;
-
-/**
- * An ImageReaderProxy implementation that allows to modify the ImageInfo data of the images
- * retrieved.
- */
-@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-class ModifiableImageReaderProxy extends AndroidImageReaderProxy {
-    private volatile TagBundle mTagBundle = null;
-    private volatile Long mTimestamp = null;
-    private volatile Integer mRotationDegrees = null;
-    private volatile Matrix mSensorToBufferTransformMatrix = null;
-
-    ModifiableImageReaderProxy(@NonNull ImageReader imageReader) {
-        super(imageReader);
-    }
-
-    void setImageTagBundle(@NonNull TagBundle tagBundle) {
-        mTagBundle = tagBundle;
-    }
-
-    void setImageTimeStamp(long timestamp) {
-        mTimestamp = timestamp;
-    }
-
-    void setImageRotationDegrees(int rotationDegrees) {
-        mRotationDegrees = rotationDegrees;
-    }
-
-    void setImageSensorToBufferTransformaMatrix(@NonNull Matrix matrix) {
-        mSensorToBufferTransformMatrix = matrix;
-    }
-
-    @Nullable
-    @Override
-    public ImageProxy acquireLatestImage() {
-        return modifyImage(super.acquireNextImage());
-    }
-
-    @Nullable
-    @Override
-    public ImageProxy acquireNextImage() {
-        return modifyImage(super.acquireNextImage());
-    }
-
-    private ImageProxy modifyImage(ImageProxy imageProxy) {
-        ImageInfo origin = imageProxy.getImageInfo();
-        ImageInfo  imageInfo = ImmutableImageInfo.create(
-                mTagBundle != null ? mTagBundle : origin.getTagBundle(),
-                mTimestamp != null ? mTimestamp.longValue() : origin.getTimestamp(),
-                mRotationDegrees != null ? mRotationDegrees.intValue() :
-                        origin.getRotationDegrees(),
-                mSensorToBufferTransformMatrix != null ? mSensorToBufferTransformMatrix :
-                        origin.getSensorToBufferTransformMatrix());
-        return new SettableImageProxy(imageProxy, imageInfo);
-    }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index bf4d35b..9a92907 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -26,7 +26,6 @@
 import static androidx.camera.core.impl.PreviewConfig.OPTION_DEFAULT_SESSION_CONFIG;
 import static androidx.camera.core.impl.PreviewConfig.OPTION_MAX_RESOLUTION;
 import static androidx.camera.core.impl.PreviewConfig.OPTION_PREVIEW_CAPTURE_PROCESSOR;
-import static androidx.camera.core.impl.PreviewConfig.OPTION_RGBA8888_SURFACE_REQUIRED;
 import static androidx.camera.core.impl.PreviewConfig.OPTION_SESSION_CONFIG_UNPACKER;
 import static androidx.camera.core.impl.PreviewConfig.OPTION_SUPPORTED_RESOLUTIONS;
 import static androidx.camera.core.impl.PreviewConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
@@ -205,9 +204,8 @@
             mSessionDeferrableSurface.close();
         }
 
-        boolean isRGBA8888SurfaceRequired = config.isRgba8888SurfaceRequired(false);
         final SurfaceRequest surfaceRequest = new SurfaceRequest(resolution, getCamera(),
-                isRGBA8888SurfaceRequired);
+                captureProcessor != null);
         mCurrentSurfaceRequest = surfaceRequest;
 
         if (sendSurfaceRequestIfReady()) {
@@ -1033,18 +1031,6 @@
             return this;
         }
 
-        /**
-         * Sets if the surface requires RGBA8888 format.
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @NonNull
-        public Builder setIsRgba8888SurfaceRequired(boolean isRgba8888SurfaceRequired) {
-            getMutableConfig().insertOption(
-                    OPTION_RGBA8888_SURFACE_REQUIRED, isRgba8888SurfaceRequired);
-            return this;
-        }
-
         /** @hide */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java b/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
index 406ba95..e702f3b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ProcessingImageReader.java
@@ -144,7 +144,7 @@
     boolean mProcessing = false;
 
     @GuardedBy("mLock")
-    final ImageReaderProxy mInputImageReader;
+    final MetadataImageReader mInputImageReader;
 
     @GuardedBy("mLock")
     final ImageReaderProxy mOutputImageReader;
@@ -403,11 +403,7 @@
     @Nullable
     CameraCaptureCallback getCameraCaptureCallback() {
         synchronized (mLock) {
-            if (mInputImageReader instanceof MetadataImageReader) {
-                return ((MetadataImageReader) mInputImageReader).getCameraCaptureCallback();
-            } else {
-                return new CameraCaptureCallback() {};
-            }
+            return mInputImageReader.getCameraCaptureCallback();
         }
     }
 
@@ -458,7 +454,7 @@
      */
     static final class Builder {
         @NonNull
-        protected final ImageReaderProxy mInputImageReader;
+        protected final MetadataImageReader mInputImageReader;
         @NonNull
         protected final CaptureBundle mCaptureBundle;
         @NonNull
@@ -477,7 +473,7 @@
          * @param captureProcessor The {@link CaptureProcessor} to be invoked when the Images are
          *                         ready
          */
-        Builder(@NonNull ImageReaderProxy imageReader, @NonNull CaptureBundle captureBundle,
+        Builder(@NonNull MetadataImageReader imageReader, @NonNull CaptureBundle captureBundle,
                 @NonNull CaptureProcessor captureProcessor) {
             mInputImageReader = imageReader;
             mCaptureBundle = captureBundle;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageCaptureConfig.java
index fc37406..0f233fb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageCaptureConfig.java
@@ -62,8 +62,6 @@
             Option.create("camerax.core.imageCapture.flashType", int.class);
     public static final Option<Integer> OPTION_JPEG_COMPRESSION_QUALITY =
             Option.create("camerax.core.imageCapture.jpegCompressionQuality", int.class);
-    public static final Option<Boolean> OPTION_SESSION_PROCESSOR_ENABLED =
-            Option.create("camerax.core.imageCapture.sessionProcessorEnabled", boolean.class);
 
     // *********************************************************************************************
 
@@ -290,13 +288,6 @@
         return retrieveOption(OPTION_JPEG_COMPRESSION_QUALITY);
     }
 
-    /**
-     * Returns if the SessionProcessor is enabled.
-     */
-    public boolean isSessionProcessorEnabled() {
-        return retrieveOption(OPTION_SESSION_PROCESSOR_ENABLED, false);
-    }
-
     // Implementations of IO default methods
 
     /**
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/PreviewConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/PreviewConfig.java
index 6d235ab..146c52a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/PreviewConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/PreviewConfig.java
@@ -37,8 +37,6 @@
             "camerax.core.preview.imageInfoProcessor", ImageInfoProcessor.class);
     public static final Option<CaptureProcessor> OPTION_PREVIEW_CAPTURE_PROCESSOR =
             Option.create("camerax.core.preview.captureProcessor", CaptureProcessor.class);
-    public static final Option<Boolean> OPTION_RGBA8888_SURFACE_REQUIRED =
-            Option.create("camerax.core.preview.isRgba8888SurfaceRequired", Boolean.class);
     private final OptionsBundle mConfig;
 
     /** Creates a new configuration instance. */
@@ -91,12 +89,6 @@
     }
 
     /**
-     * Returns if the preview surface requires RGBA8888 format.
-     */
-    public boolean isRgba8888SurfaceRequired(boolean valueIfMissing) {
-        return retrieveOption(OPTION_RGBA8888_SURFACE_REQUIRED, valueIfMissing);
-    }
-    /**
      * Retrieves the format of the image that is fed as input.
      *
      * <p>This should be YUV_420_888, when processing is run on the image. Otherwise it is PRIVATE.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
index 70bdbc4..db0e00f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/UseCaseConfig.java
@@ -16,6 +16,8 @@
 
 package androidx.camera.core.impl;
 
+import android.util.Range;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -75,6 +77,13 @@
     Option<CameraSelector> OPTION_CAMERA_SELECTOR =
             Config.Option.create("camerax.core.useCase.cameraSelector", CameraSelector.class);
 
+    /**
+     * Option: camerax.core.useCase.targetFramerate
+     */
+    Option<Range<Integer>> OPTION_TARGET_FRAME_RATE =
+            Config.Option.create("camerax.core.useCase.targetFrameRate", CameraSelector.class);
+
+
     // *********************************************************************************************
 
     /**
@@ -250,6 +259,28 @@
     }
 
     /**
+     * Retrieves target frame rate
+     * @param valueIfMissing
+     * @return the stored value or <code>valueIfMissing</code> if the value does not exist in
+     * this configuration
+     */
+    @Nullable
+    default Range<Integer> getTargetFramerate(@Nullable Range<Integer> valueIfMissing) {
+        return retrieveOption(OPTION_TARGET_FRAME_RATE, valueIfMissing);
+    }
+
+    /**
+     * Retrieves the target frame rate
+     *
+     * @return The stored value, if it exists in this configuration.
+     * @throws IllegalArgumentException if the option does not exist in this configuration.
+     */
+    @NonNull
+    default Range<Integer> getTargetFramerate() {
+        return retrieveOption(OPTION_TARGET_FRAME_RATE);
+    }
+
+    /**
      * Builder for a {@link UseCase}.
      *
      * @param <T> The type of the object which will be built by {@link #build()}.
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt
new file mode 100644
index 0000000..0f6df49
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/UseCaseConfigTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.core.impl
+
+import android.os.Build
+import android.util.Range
+import androidx.camera.testing.fakes.FakeUseCaseConfig
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(
+    RobolectricTestRunner::class
+)
+@DoNotInstrument
+class UseCaseConfigTest {
+    @Test
+    fun canGetTargetFrameRate() {
+        val useCaseBuilder = FakeUseCaseConfig.Builder()
+        val range = Range(10, 20)
+        useCaseBuilder.mutableConfig.insertOption(UseCaseConfig.OPTION_TARGET_FRAME_RATE, range)
+        Truth.assertThat(useCaseBuilder.useCaseConfig.targetFramerate).isEqualTo(range)
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
index b7927fb..4204cc3 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsInfo.java
@@ -17,6 +17,9 @@
 package androidx.camera.extensions;
 
 
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
@@ -42,7 +45,9 @@
 import androidx.camera.extensions.internal.VendorExtender;
 import androidx.camera.extensions.internal.Version;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A class for querying extensions related information.
@@ -227,6 +232,11 @@
     private static VendorExtender getVendorExtender(int mode) {
         boolean isAdvancedExtenderSupported = isAdvancedExtenderSupported();
 
+        // Disable Advanced Extender until it is well tested.
+        if (isAdvancedExtenderSupported) {
+            return new DisabledVendorExtender();
+        }
+
         VendorExtender vendorExtender;
         if (isAdvancedExtenderSupported) {
             vendorExtender = new AdvancedVendorExtender(mode);
@@ -270,4 +280,47 @@
         }
         return id;
     }
+
+    static class DisabledVendorExtender implements VendorExtender {
+        @Override
+        public boolean isExtensionAvailable(@NonNull String cameraId,
+                @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+            return false;
+        }
+
+        @Override
+        public void init(@NonNull CameraInfo cameraInfo) {
+
+        }
+
+        @Nullable
+        @Override
+        public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size size) {
+            return null;
+        }
+
+        @NonNull
+        @Override
+        public List<Pair<Integer, Size[]>> getSupportedPreviewOutputResolutions() {
+            return Collections.emptyList();
+        }
+
+        @NonNull
+        @Override
+        public List<Pair<Integer, Size[]>> getSupportedCaptureOutputResolutions() {
+            return Collections.emptyList();
+        }
+
+        @NonNull
+        @Override
+        public Size[] getSupportedYuvAnalysisResolutions() {
+            return new Size[0];
+        }
+
+        @Nullable
+        @Override
+        public SessionProcessor createSessionProcessor(@NonNull Context context) {
+            return null;
+        }
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
index a11ff2b..72a78cf 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
@@ -180,11 +180,16 @@
         return map.getOutputSizes(imageFormat);
     }
 
-    private int getPreviewOutputImageFormat() {
-        return ImageFormat.PRIVATE;
+    private int getPreviewInputImageFormat() {
+        if (mPreviewExtenderImpl != null && mPreviewExtenderImpl.getProcessorType()
+                == PreviewExtenderImpl.ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR) {
+            return ImageFormat.YUV_420_888;
+        } else {
+            return ImageFormat.PRIVATE;
+        }
     }
 
-    private int getCaptureOutputImageFormat() {
+    private int getCaptureInputImageFormat() {
         if (mImageCaptureExtenderImpl != null
                 && mImageCaptureExtenderImpl.getCaptureProcessor() != null) {
             return ImageFormat.YUV_420_888;
@@ -213,7 +218,7 @@
         // Returns output sizes from stream configuration map if OEM returns null or OEM does not
         // implement the function. It is required to return all supported sizes so it must fetch
         // all sizes from the stream configuration map here.
-        int imageformat = getPreviewOutputImageFormat();
+        int imageformat = getPreviewInputImageFormat();
         return Arrays.asList(new Pair<>(imageformat, getOutputSizes(imageformat)));
     }
 
@@ -237,7 +242,7 @@
         // Returns output sizes from stream configuration map if OEM returns null or OEM does not
         // implement the function. It is required to return all supported sizes so it must fetch
         // all sizes from the stream configuration map here.
-        int imageFormat = getCaptureOutputImageFormat();
+        int imageFormat = getCaptureInputImageFormat();
         return Arrays.asList(new Pair<>(imageFormat, getOutputSizes(imageFormat)));
     }
 
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
index a09bf72..c280363 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
@@ -118,8 +118,6 @@
             } else {
                 Logger.e(TAG, "ImageCaptureExtenderImpl is null!");
             }
-        } else { // Advanced vendor interface
-            builder.setSessionProcessorEnabled(true);
         }
 
         builder.getMutableConfig().insertOption(OPTION_IMAGE_CAPTURE_CONFIG_PROVIDER_MODE,
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
index 9fa8a86..3da8a12 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
@@ -105,7 +105,6 @@
                                 AdaptingPreviewProcessor(
                                 (PreviewImageProcessorImpl) previewExtenderImpl.getProcessor());
                         builder.setCaptureProcessor(adaptingPreviewProcessor);
-                        builder.setIsRgba8888SurfaceRequired(true);
                         previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
                                 adaptingPreviewProcessor);
                         break;
@@ -119,10 +118,6 @@
             } else {
                 Logger.e(TAG, "PreviewExtenderImpl is null!");
             }
-        } else { // Advanced extensions interface.
-            // Set RGB8888 = true always since we have no way to tell if the OEM implementation does
-            // the processing or not.
-            builder.setIsRgba8888SurfaceRequired(true);
         }
 
         builder.getMutableConfig().insertOption(OPTION_PREVIEW_CONFIG_PROVIDER_MODE, effectMode);
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/SurfaceTextureProvider.java b/camera/camera-testing/src/main/java/androidx/camera/testing/SurfaceTextureProvider.java
index 110695c..e9443ca 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/SurfaceTextureProvider.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/SurfaceTextureProvider.java
@@ -101,30 +101,6 @@
     }
 
     /**
-     * Creates a {@link Preview.SurfaceProvider} that is backed by a {@link SurfaceTexture} which
-     * is suitable to be used in testing that doesn't actually show camera preview but just need
-     * a surface for preview.
-     *
-     * <p> The {@link SurfaceTexture} will be released when it is no longer needed.
-     *
-     */
-    @NonNull
-    public static Preview.SurfaceProvider createSurfaceTextureProvider() {
-        return createSurfaceTextureProvider(new SurfaceTextureCallback() {
-            @Override
-            public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
-                    @NonNull Size resolution) {
-                // no op
-            }
-
-            @Override
-            public void onSafeToRelease(@NonNull SurfaceTexture surfaceTexture) {
-                surfaceTexture.release();
-            }
-        });
-    }
-
-    /**
      * Creates a {@link Preview.SurfaceProvider} that is backed by a {@link SurfaceTexture}.
      *
      * <p>This method also creates a backing OpenGL thread that will automatically drain frames
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt
deleted file mode 100644
index f862765..0000000
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeSessionProcessor.kt
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.testing.fakes
-
-import android.hardware.camera2.CameraDevice
-import android.media.ImageReader
-import android.media.ImageWriter
-import android.os.Handler
-import android.os.Looper
-import android.os.SystemClock
-import android.view.Surface
-import androidx.annotation.RequiresApi
-import androidx.camera.core.CameraInfo
-import androidx.camera.core.impl.CameraCaptureFailure
-import androidx.camera.core.impl.CameraCaptureResult
-import androidx.camera.core.impl.Config
-import androidx.camera.core.impl.DeferrableSurface
-import androidx.camera.core.impl.OptionsBundle
-import androidx.camera.core.impl.OutputSurface
-import androidx.camera.core.impl.RequestProcessor
-import androidx.camera.core.impl.SessionConfig
-import androidx.camera.core.impl.SessionProcessor
-import androidx.camera.core.impl.SessionProcessorSurface
-import androidx.camera.core.impl.utils.executor.CameraXExecutors
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.withTimeout
-import kotlinx.coroutines.withTimeoutOrNull
-
-const val FAKE_CAPTURE_SEQUENCE_ID = 1
-
-@RequiresApi(23)
-class FakeSessionProcessor(
-    val inputFormatPreview: Int?,
-    val inputFormatCapture: Int?
-) : SessionProcessor {
-    private lateinit var previewProcessorSurface: DeferrableSurface
-    private lateinit var captureProcessorSurface: DeferrableSurface
-    private var intermediaPreviewImageReader: ImageReader? = null
-    private var intermediaCaptureImageReader: ImageReader? = null
-    private var intermediaPreviewImageWriter: ImageWriter? = null
-    private var intermediaCaptureImageWriter: ImageWriter? = null
-
-    private val previewOutputConfigId = 1
-    private val captureOutputConfigId = 2
-
-    private var requestProcessor: RequestProcessor? = null
-
-    // Values of these Deferred are the timestamp to complete.
-    private val initSessionCalled = CompletableDeferred<Long>()
-    private val deInitSessionCalled = CompletableDeferred<Long>()
-    private val onCaptureSessionStartCalled = CompletableDeferred<Long>()
-    private val onCaptureSessionEndCalled = CompletableDeferred<Long>()
-    private val startRepeatingCalled = CompletableDeferred<Long>()
-    private val startCaptureCalled = CompletableDeferred<Long>()
-    private val setParametersCalled = CompletableDeferred<Config>()
-    private var latestParameters: Config = OptionsBundle.emptyBundle()
-    private var blockRunAfterInitSession: () -> Unit = {}
-
-    fun releaseSurfaces() {
-        intermediaPreviewImageReader?.close()
-        intermediaCaptureImageReader?.close()
-    }
-
-    fun runAfterInitSession(block: () -> Unit) {
-        blockRunAfterInitSession = block
-    }
-
-    override fun initSession(
-        cameraInfo: CameraInfo,
-        previewSurfaceConfig: OutputSurface,
-        imageCaptureSurfaceConfig: OutputSurface,
-        imageAnalysisSurfaceConfig: OutputSurface?
-    ): SessionConfig {
-        initSessionCalled.complete(SystemClock.elapsedRealtimeNanos())
-        val handler = Handler(Looper.getMainLooper())
-
-        var sessionBuilder = SessionConfig.Builder()
-
-        // Preview
-        lateinit var previewTransformedSurface: Surface
-        if (inputFormatPreview == null) { // no conversion, use origin surface.
-            previewTransformedSurface = previewSurfaceConfig.surface
-        } else {
-            intermediaPreviewImageReader = ImageReader.newInstance(
-                640, 480,
-                inputFormatPreview, 2
-            )
-            previewTransformedSurface = intermediaPreviewImageReader!!.surface
-
-            intermediaPreviewImageWriter = ImageWriter.newInstance(
-                previewSurfaceConfig.surface, 2
-            )
-
-            intermediaPreviewImageReader!!.setOnImageAvailableListener(
-                {
-                    it.acquireNextImage().use {
-                        val imageDequeued = intermediaPreviewImageWriter!!.dequeueInputImage()
-                        intermediaPreviewImageWriter!!.queueInputImage(imageDequeued)
-                    }
-                },
-                handler
-            )
-        }
-        previewProcessorSurface =
-            SessionProcessorSurface(previewTransformedSurface, previewOutputConfigId)
-        previewProcessorSurface.terminationFuture.addListener(
-            {
-                intermediaPreviewImageReader?.close()
-                intermediaPreviewImageWriter?.close()
-            },
-            CameraXExecutors.directExecutor()
-        )
-        sessionBuilder.addSurface(previewProcessorSurface)
-
-        // Capture
-        lateinit var captureTransformedSurface: Surface
-        if (inputFormatCapture == null) { // no conversion, use origin surface.
-            captureTransformedSurface = imageCaptureSurfaceConfig.surface
-        } else {
-            intermediaCaptureImageReader = ImageReader.newInstance(
-                640, 480,
-                inputFormatCapture, 2
-            )
-            captureTransformedSurface = intermediaCaptureImageReader!!.surface
-
-            intermediaCaptureImageWriter = ImageWriter.newInstance(
-                imageCaptureSurfaceConfig.surface, 2
-            )
-
-            intermediaCaptureImageReader!!.setOnImageAvailableListener(
-                {
-                    it.acquireNextImage().use {
-                        val imageDequeued = intermediaCaptureImageWriter!!.dequeueInputImage()
-                        intermediaCaptureImageWriter!!.queueInputImage(imageDequeued)
-                    }
-                },
-                handler
-            )
-        }
-        captureProcessorSurface =
-            SessionProcessorSurface(captureTransformedSurface, captureOutputConfigId)
-
-        captureProcessorSurface.terminationFuture.addListener(
-            {
-                intermediaCaptureImageReader?.close()
-                intermediaCaptureImageWriter?.close()
-            },
-            CameraXExecutors.directExecutor()
-        )
-        sessionBuilder.addSurface(captureProcessorSurface)
-
-        sessionBuilder.setTemplateType(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG)
-        val sessionConfig = sessionBuilder.build()
-        blockRunAfterInitSession()
-        return sessionConfig
-    }
-
-    override fun deInitSession() {
-        deInitSessionCalled.complete(SystemClock.elapsedRealtimeNanos())
-        previewProcessorSurface.close()
-        captureProcessorSurface.close()
-    }
-
-    override fun setParameters(config: Config) {
-        setParametersCalled.complete(config)
-        latestParameters = config
-    }
-
-    override fun onCaptureSessionStart(_requestProcessor: RequestProcessor) {
-        onCaptureSessionStartCalled.complete(SystemClock.elapsedRealtimeNanos())
-        requestProcessor = _requestProcessor
-    }
-
-    override fun onCaptureSessionEnd() {
-        onCaptureSessionEndCalled.complete(SystemClock.elapsedRealtimeNanos())
-    }
-
-    fun getLatestParameters(): Config {
-        return latestParameters
-    }
-
-    override fun startRepeating(callback: SessionProcessor.CaptureCallback): Int {
-        startRepeatingCalled.complete(SystemClock.elapsedRealtimeNanos())
-        val builder = RequestProcessorRequest.Builder().apply {
-            addTargetOutputConfigId(previewOutputConfigId)
-            setParameters(latestParameters)
-            setTemplateId(CameraDevice.TEMPLATE_PREVIEW)
-        }
-
-        requestProcessor!!.setRepeating(
-            builder.build(),
-            object : RequestProcessor.Callback {
-                override fun onCaptureStarted(
-                    request: RequestProcessor.Request,
-                    frameNumber: Long,
-                    timestamp: Long
-                ) {}
-
-                override fun onCaptureProgressed(
-                    request: RequestProcessor.Request,
-                    captureResult: CameraCaptureResult
-                ) {}
-
-                override fun onCaptureCompleted(
-                    request: RequestProcessor.Request,
-                    captureResult: CameraCaptureResult
-                ) {
-                    callback.onCaptureSequenceCompleted(1)
-                }
-
-                override fun onCaptureFailed(
-                    request: RequestProcessor.Request,
-                    captureFailure: CameraCaptureFailure
-                ) {}
-
-                override fun onCaptureBufferLost(
-                    request: RequestProcessor.Request,
-                    frameNumber: Long,
-                    outputConfigId: Int
-                ) {}
-
-                override fun onCaptureSequenceCompleted(
-                    sequenceId: Int,
-                    frameNumber: Long
-                ) {}
-
-                override fun onCaptureSequenceAborted(sequenceId: Int) {
-                }
-            }
-        )
-        return FAKE_CAPTURE_SEQUENCE_ID
-    }
-
-    override fun stopRepeating() {
-    }
-
-    override fun startCapture(callback: SessionProcessor.CaptureCallback): Int {
-        startCaptureCalled.complete(SystemClock.elapsedRealtimeNanos())
-        val request = RequestProcessorRequest.Builder().apply {
-            addTargetOutputConfigId(captureOutputConfigId)
-            setParameters(latestParameters)
-            setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE)
-        }.build()
-
-        requestProcessor!!.submit(
-            request,
-            object : RequestProcessor.Callback {
-                override fun onCaptureCompleted(
-                    request: RequestProcessor.Request,
-                    captureResult: CameraCaptureResult
-                ) {
-                    callback.onCaptureSequenceCompleted(1)
-                }
-
-                override fun onCaptureStarted(
-                    request: RequestProcessor.Request,
-                    frameNumber: Long,
-                    timestamp: Long
-                ) {}
-
-                override fun onCaptureProgressed(
-                    request: RequestProcessor.Request,
-                    captureResult: CameraCaptureResult
-                ) {}
-
-                override fun onCaptureFailed(
-                    request: RequestProcessor.Request,
-                    captureFailure: CameraCaptureFailure
-                ) {
-                    callback.onCaptureFailed(1)
-                }
-
-                override fun onCaptureBufferLost(
-                    request: RequestProcessor.Request,
-                    frameNumber: Long,
-                    outputConfigId: Int
-                ) {}
-
-                override fun onCaptureSequenceCompleted(sequenceId: Int, frameNumber: Long) {}
-
-                override fun onCaptureSequenceAborted(sequenceId: Int) {}
-            }
-        )
-        return FAKE_CAPTURE_SEQUENCE_ID
-    }
-
-    override fun abortCapture(captureSequenceId: Int) {
-    }
-
-    suspend fun assertInitSessionInvoked(): Long {
-        return initSessionCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun wasInitSessionInvoked(): Boolean {
-        val result = withTimeoutOrNull(3000) { initSessionCalled.await() }
-        return result != null
-    }
-
-    suspend fun assertDeInitSessionInvoked(): Long {
-        return deInitSessionCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun assertOnCaptureSessionStartInvoked(): Long {
-        return onCaptureSessionStartCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun wasOnCaptureSessionStartInvoked(): Boolean {
-        val result = withTimeoutOrNull(3000) { onCaptureSessionStartCalled.await() }
-        return result != null
-    }
-
-    suspend fun assertOnCaptureEndInvoked(): Long {
-        return onCaptureSessionEndCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun assertStartRepeatingInvoked(): Long {
-        return startRepeatingCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun assertStartCaptureInvoked(): Long {
-        return startCaptureCalled.awaitWithTimeout(3000)
-    }
-
-    suspend fun assertSetParametersInvoked(): Config {
-        return setParametersCalled.awaitWithTimeout(3000)
-    }
-
-    private suspend fun <T> Deferred<T>.awaitWithTimeout(timeMillis: Long): T {
-        return withTimeout(timeMillis) {
-            await()
-        }
-    }
-}
-
-@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-internal class RequestProcessorRequest(
-    private val targetOutputConfigIds: List<Int>,
-    private val parameters: Config,
-    private val templateId: Int
-) : RequestProcessor.Request {
-    override fun getTargetOutputConfigIds(): List<Int> {
-        return targetOutputConfigIds
-    }
-
-    override fun getParameters(): Config {
-        return parameters
-    }
-
-    override fun getTemplateId(): Int {
-        return templateId
-    }
-
-    class Builder {
-        private var targetOutputConfigIds: MutableList<Int> = ArrayList()
-        private var parameters: Config = OptionsBundle.emptyBundle()
-        private var templateId = CameraDevice.TEMPLATE_PREVIEW
-
-        fun addTargetOutputConfigId(targetOutputConfigId: Int): Builder {
-            targetOutputConfigIds.add(targetOutputConfigId)
-            return this
-        }
-
-        fun setParameters(parameters: Config): Builder {
-            this.parameters = parameters
-            return this
-        }
-
-        fun setTemplateId(templateId: Int): Builder {
-            this.templateId = templateId
-            return this
-        }
-
-        fun build(): RequestProcessorRequest {
-            return RequestProcessorRequest(
-                targetOutputConfigIds.toList(),
-                OptionsBundle.from(parameters),
-                templateId
-            )
-        }
-    }
-}
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index 342ffd0..b06614e 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -41,37 +41,26 @@
 import androidx.camera.camera2.pipe.integration.CameraPipeConfig
 import androidx.camera.core.AspectRatio
 import androidx.camera.core.Camera
-import androidx.camera.core.CameraFilter
-import androidx.camera.core.CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.CameraXConfig
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageCaptureException
 import androidx.camera.core.ImageProxy
-import androidx.camera.core.Preview
 import androidx.camera.core.UseCaseGroup
 import androidx.camera.core.ViewPort
-import androidx.camera.core.impl.CameraConfig
 import androidx.camera.core.impl.CaptureBundle
 import androidx.camera.core.impl.CaptureConfig
 import androidx.camera.core.impl.CaptureProcessor
 import androidx.camera.core.impl.CaptureStage
-import androidx.camera.core.impl.Config
-import androidx.camera.core.impl.ExtendedCameraConfigProviderStore
-import androidx.camera.core.impl.Identifier
 import androidx.camera.core.impl.ImageCaptureConfig
 import androidx.camera.core.impl.ImageOutputConfig
 import androidx.camera.core.impl.ImageProxyBundle
-import androidx.camera.core.impl.MutableOptionsBundle
-import androidx.camera.core.impl.SessionProcessor
 import androidx.camera.core.impl.utils.CameraOrientationUtil
 import androidx.camera.core.impl.utils.Exif
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
-import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.fakes.FakeCaptureStage
 import androidx.camera.testing.fakes.FakeLifecycleOwner
-import androidx.camera.testing.fakes.FakeSessionProcessor
 import androidx.core.content.ContextCompat
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
@@ -1414,139 +1403,6 @@
         simpleCaptureProcessor.close()
     }
 
-    @Test
-    @SdkSuppress(minSdkVersion = 29)
-    fun returnJpegImage_whenSessionProcessorIsSet_outputFormantYuv() = runBlocking {
-        skipTestOnCameraPipeConfig()
-
-        val builder = ImageCapture.Builder()
-        val sessionProcessor = FakeSessionProcessor(
-            inputFormatPreview = null, // null means using the same output surface
-            inputFormatCapture = ImageFormat.YUV_420_888
-        )
-
-        val imageCapture = builder
-            .setSessionProcessorEnabled(true)
-            .setSupportedResolutions(
-                listOf(android.util.Pair(ImageFormat.YUV_420_888, arrayOf(Size(640, 480)))))
-            .build()
-
-        val preview = Preview.Builder().build()
-
-        var camera: Camera
-        withContext(Dispatchers.Main) {
-            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
-            val cameraSelector =
-                getCameraSelectorWithSessionProcessor(BACK_SELECTOR, sessionProcessor)
-            camera = cameraProvider.bindToLifecycle(
-                fakeLifecycleOwner, cameraSelector, imageCapture, preview)
-        }
-
-        val callback = FakeImageCaptureCallback(capturesCount = 1)
-        imageCapture.takePicture(mainExecutor, callback)
-
-        // Wait for the signal that the image has been captured.
-        callback.awaitCapturesAndAssert(capturedImagesCount = 1)
-
-        val imageProperties = callback.results.first()
-
-        // Check the output image rotation degrees value is correct.
-        assertThat(imageProperties.rotationDegrees).isEqualTo(
-            camera.cameraInfo.getSensorRotationDegrees(imageCapture.targetRotation)
-        )
-        // Check the output format is correct.
-        assertThat(imageProperties.format).isEqualTo(ImageFormat.JPEG)
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 29)
-    fun returnJpegImage_whenSessionProcessorIsSet_outputFormantJpeg() = runBlocking {
-        assumeFalse(
-            "Cuttlefish does not correctly handle Jpeg exif. Unable to test.",
-            Build.MODEL.contains("Cuttlefish")
-        )
-        skipTestOnCameraPipeConfig()
-
-        val builder = ImageCapture.Builder()
-        val sessionProcessor = FakeSessionProcessor(
-            inputFormatPreview = null, // null means using the same output surface
-            inputFormatCapture = null
-        )
-
-        val imageCapture = builder
-            .setSessionProcessorEnabled(true)
-            .setSupportedResolutions(
-                listOf(android.util.Pair(ImageFormat.JPEG, arrayOf(Size(640, 480)))))
-            .build()
-
-        val preview = Preview.Builder().build()
-
-        withContext(Dispatchers.Main) {
-            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
-            val cameraSelector =
-                getCameraSelectorWithSessionProcessor(BACK_SELECTOR, sessionProcessor)
-            cameraProvider.bindToLifecycle(
-                fakeLifecycleOwner, cameraSelector, imageCapture, preview)
-        }
-
-        val callback = FakeImageCaptureCallback(capturesCount = 1)
-        imageCapture.takePicture(mainExecutor, callback)
-
-        // Wait for the signal that the image has been captured.
-        callback.awaitCapturesAndAssert(capturedImagesCount = 1)
-
-        val imageProperties = callback.results.first()
-
-        // Check the output image rotation degrees value is correct.
-        assertThat(imageProperties.rotationDegrees).isEqualTo(imageProperties.exif!!.rotation)
-
-        // Check the output format is correct.
-        assertThat(imageProperties.format).isEqualTo(ImageFormat.JPEG)
-    }
-
-    private fun getCameraSelectorWithSessionProcessor(
-        cameraSelector: CameraSelector,
-        sessionProcessor: SessionProcessor
-    ): CameraSelector {
-        val identifier = Identifier.create("idStr")
-        ExtendedCameraConfigProviderStore.addConfig(identifier) { _, _ ->
-            object : CameraConfig {
-                override fun getConfig(): Config {
-                    return MutableOptionsBundle.create()
-                }
-
-                override fun getCompatibilityId(): Identifier {
-                    return Identifier.create(0)
-                }
-
-                override fun getSessionProcessor(
-                    valueIfMissing: SessionProcessor?
-                ): SessionProcessor? {
-                    return sessionProcessor
-                }
-
-                override fun getSessionProcessor(): SessionProcessor {
-                    return sessionProcessor
-                }
-            }
-        }
-
-        val builder = CameraSelector.Builder.fromSelector(cameraSelector)
-        builder.addCameraFilter(object : CameraFilter {
-            override fun filter(cameraInfos: MutableList<CameraInfo>): MutableList<CameraInfo> {
-                val newCameraInfos = mutableListOf<CameraInfo>()
-                newCameraInfos.addAll(cameraInfos)
-                return newCameraInfos
-            }
-
-            override fun getIdentifier(): Identifier {
-                return identifier
-            }
-        })
-
-        return builder.build()
-    }
-
     // Output JPEG format image when setting a CaptureProcessor is only enabled for devices that
     // API level is at least 29.
     @Test
diff --git a/car/app/app-automotive/src/main/res/values-ky/strings.xml b/car/app/app-automotive/src/main/res/values-ky/strings.xml
index 192fef2..a27b786 100644
--- a/car/app/app-automotive/src/main/res/values-ky/strings.xml
+++ b/car/app/app-automotive/src/main/res/values-ky/strings.xml
@@ -23,8 +23,8 @@
     <string name="error_message_client_side_error" msgid="3323186720368387787">"Колдонмодо ката кетти. Бул катаны колдонмонун иштеп чыгуучусуна кабарлаңыз"</string>
     <string name="error_message_host_error" msgid="5484419926049675696">"Тутум катасы"</string>
     <string name="error_message_host_connection_lost" msgid="5723205987837759151">"Тутум убактылуу жеткиликсиз"</string>
-    <string name="error_message_host_not_found" msgid="3241065067065670113">"Тутумду жаңыртуу керек"</string>
-    <string name="error_message_host_incompatible" msgid="160406216155183851">"Тутумду жаңыртуу керек"</string>
+    <string name="error_message_host_not_found" msgid="3241065067065670113">"Системаны жаңыртуу керек"</string>
+    <string name="error_message_host_incompatible" msgid="160406216155183851">"Системаны жаңыртуу керек"</string>
     <string name="error_message_multiple_hosts" msgid="2591031904206928207">"Шайкеш келбеген тутум"</string>
     <string name="error_message_unknown_error" msgid="1918523834689044166">"Белгисиз ката"</string>
     <string name="error_message_no_vending" msgid="5866202078252905802">"Унаа кызматтары менен байланышыңыз"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/SelectableListsDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/SelectableListsDemoScreen.java
index 8521109..0a53e69 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/SelectableListsDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/SelectableListsDemoScreen.java
@@ -55,21 +55,33 @@
                                                                         .ic_fastfood_white_48dp))
                                                         .build(),
                                                 Row.IMAGE_TYPE_ICON)
-                                        .setTitle("Option 1")
-                                        .addText("Some additional text")
+                                        .setTitle(
+                                                getCarContext().getString(R.string.option_1_title))
+                                        .addText(getCarContext().getString(
+                                                R.string.some_additional_text))
                                         .build())
-                        .addItem(new Row.Builder().setTitle("Option 2").build())
-                        .addItem(new Row.Builder().setTitle("Option 3").build())
+                        .addItem(new Row.Builder().setTitle(
+                                getCarContext().getString(R.string.option_2_title)).build())
+                        .addItem(new Row.Builder().setTitle(
+                                getCarContext().getString(R.string.option_3_title)).build())
                         .setOnSelectedListener(this::onSelected)
                         .build();
         templateBuilder.addSectionedList(
-                SectionedItemList.create(radioList, "Sample selectable list"));
+                SectionedItemList.create(radioList,
+                        getCarContext().getString(R.string.sample_additional_list)));
 
-        return templateBuilder.setTitle("Selectable Lists Demo").setHeaderAction(BACK).build();
+        return templateBuilder
+                .setTitle(getCarContext().getString(R.string.selectable_lists_demo_title))
+                .setHeaderAction(
+                        BACK).build();
     }
 
     private void onSelected(int index) {
-        CarToast.makeText(getCarContext(), "Changed selection to index: " + index, LENGTH_LONG)
+        CarToast.makeText(getCarContext(),
+                        getCarContext()
+                                .getString(R.string.changes_selection_to_index_toast_msg_prefix)
+                                + ":"
+                                + " " + index, LENGTH_LONG)
                 .show();
     }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/StartScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/StartScreen.java
index 19344b0..63ba613 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/StartScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/StartScreen.java
@@ -48,7 +48,7 @@
         ItemList.Builder listBuilder = new ItemList.Builder();
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Selectable Lists Demo")
+                        .setTitle(getCarContext().getString(R.string.selectable_lists_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -58,7 +58,7 @@
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Task Restriction Demo")
+                        .setTitle(getCarContext().getString(R.string.task_restriction_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -75,7 +75,7 @@
                                                 R.drawable.ic_map_white_48dp))
                                         .build(),
                                 Row.IMAGE_TYPE_ICON)
-                        .setTitle("Navigation Demos")
+                        .setTitle(getCarContext().getString(R.string.nav_demos_title))
                         .setOnClickListener(
                                 () -> getScreenManager()
                                         .push(new NavigationDemosScreen(getCarContext())))
@@ -90,7 +90,7 @@
         int miscTemplateDemoScreenItemLimit = listLimit;
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Misc Templates Demos")
+                        .setTitle(getCarContext().getString(R.string.misc_templates_demos_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -102,7 +102,7 @@
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Text and Icons Demos")
+                        .setTitle(getCarContext().getString(R.string.text_icons_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -111,7 +111,7 @@
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Misc Demos")
+                        .setTitle(getCarContext().getString(R.string.misc_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -121,7 +121,7 @@
                         .build());
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Showcase Demos")
+                .setTitle(getCarContext().getString(R.string.showcase_demos_title))
                 .setHeaderAction(Action.APP_ICON)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/TaskRestrictionDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/TaskRestrictionDemoScreen.java
index 8992b7f..9adf0c7 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/TaskRestrictionDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/TaskRestrictionDemoScreen.java
@@ -64,11 +64,12 @@
                                             mIsBackOperation = true);
 
             return new MessageTemplate.Builder(
-                    "Task limit reached\nGoing forward will force stop the app")
+                    getCarContext().getString(R.string.task_limit_reached_msg))
                     .setHeaderAction(BACK)
                     .addAction(
                             new Action.Builder()
-                                    .setTitle("Try Anyway")
+                                    .setTitle(getCarContext().getString(
+                                            R.string.try_anyway_action_title))
                                     .setOnClickListener(onClickListener)
                                     .build())
                     .build();
@@ -76,21 +77,23 @@
 
         ItemList.Builder builder = new ItemList.Builder();
         builder.addItem(
-                new Row.Builder()
-                        .setTitle("Task step " + mStep + " of " + MAX_STEPS_ALLOWED)
-                        .addText("Click to go forward")
-                        .setOnClickListener(
-                                () ->
-                                        getScreenManager()
-                                                .pushForResult(
-                                                        new TaskRestrictionDemoScreen(
-                                                                mStep + 1, getCarContext()),
-                                                        result -> mIsBackOperation = true))
-                        .build())
+                        new Row.Builder()
+                                .setTitle(getCarContext().getString(R.string.task_step_of_title,
+                                        mStep,
+                                        MAX_STEPS_ALLOWED))
+                                .addText(getCarContext().getString(R.string.task_step_of_text))
+                                .setOnClickListener(
+                                        () ->
+                                                getScreenManager()
+                                                        .pushForResult(
+                                                                new TaskRestrictionDemoScreen(
+                                                                        mStep + 1, getCarContext()),
+                                                                result -> mIsBackOperation = true))
+                                .build())
                 .addItem(
                         new Row.Builder()
-                                .setTitle("Toggle test")
-                                .addText("Stateful changes are allowed")
+                                .setTitle(getCarContext().getString(R.string.toggle_test_title))
+                                .addText(getCarContext().getString(R.string.toggle_test_text))
                                 .setToggle(
                                         new Toggle.Builder(
                                                 checked -> {
@@ -102,8 +105,8 @@
                                 .build())
                 .addItem(
                         new Row.Builder()
-                                .setTitle("Image test")
-                                .addText("Image changes are allowed")
+                                .setTitle(getCarContext().getString(R.string.image_test_title))
+                                .addText(getCarContext().getString(R.string.image_test_text))
                                 .setImage(
                                         new CarIcon.Builder(
                                                 IconCompat.createWithResource(
@@ -124,20 +127,21 @@
         if (mIsBackOperation) {
             builder.addItem(
                     new Row.Builder()
-                            .setTitle("Additional Data")
-                            .addText("Updates allows on back operations.")
+                            .setTitle(getCarContext().getString(R.string.additional_data_title))
+                            .addText(getCarContext().getString(R.string.additional_data_text))
                             .build());
         }
 
         return new ListTemplate.Builder()
                 .setSingleList(builder.build())
-                .setTitle("Task Restriction Demo")
+                .setTitle(getCarContext().getString(R.string.task_restriction_demo_title))
                 .setHeaderAction(BACK)
                 .setActionStrip(
                         new ActionStrip.Builder()
                                 .addAction(
                                         new Action.Builder()
-                                                .setTitle("HOME")
+                                                .setTitle(getCarContext().getString(
+                                                        R.string.home_caps_action_title))
                                                 .setOnClickListener(
                                                         () -> getScreenManager().popToRoot())
                                                 .build())
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/PlaceDetailsScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/PlaceDetailsScreen.java
index 6125f04..d0f0d11 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/PlaceDetailsScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/PlaceDetailsScreen.java
@@ -33,11 +33,17 @@
 import androidx.car.app.model.PaneTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** A screen that displays the details of a place. */
 public class PlaceDetailsScreen extends Screen {
     private final PlaceInfo mPlace;
 
+    private PlaceDetailsScreen(@NonNull CarContext carContext, @NonNull PlaceInfo place) {
+        super(carContext);
+        mPlace = place;
+    }
+
     /** Creates an instance of {@link PlaceDetailsScreen}. */
     @NonNull
     public static PlaceDetailsScreen create(
@@ -52,23 +58,23 @@
                 new Pane.Builder()
                         .addAction(
                                 new Action.Builder()
-                                        .setTitle("Navigate")
+                                        .setTitle(getCarContext().getString(R.string.navigate))
                                         .setBackgroundColor(CarColor.BLUE)
                                         .setOnClickListener(this::onClickNavigate)
                                         .build())
                         .addAction(
                                 new Action.Builder()
-                                        .setTitle("Dial")
+                                        .setTitle(getCarContext().getString(R.string.dial))
                                         .setOnClickListener(this::onClickDial)
                                         .build())
                         .addRow(
                                 new Row.Builder()
-                                        .setTitle("Address")
+                                        .setTitle(getCarContext().getString(R.string.address))
                                         .addText(mPlace.address)
                                         .build())
                         .addRow(
                                 new Row.Builder()
-                                        .setTitle("Phone")
+                                        .setTitle(getCarContext().getString(R.string.phone))
                                         .addText(mPlace.phoneNumber)
                                         .build());
 
@@ -86,9 +92,9 @@
             getCarContext().startCarApp(intent);
         } catch (HostException e) {
             CarToast.makeText(
-                    getCarContext(),
-                    "Failure starting navigation",
-                    LENGTH_LONG)
+                            getCarContext(),
+                            getCarContext().getString(R.string.fail_start_nav),
+                            LENGTH_LONG)
                     .show();
         }
     }
@@ -101,15 +107,10 @@
             getCarContext().startCarApp(intent);
         } catch (HostException e) {
             CarToast.makeText(
-                    getCarContext(),
-                    "Failure starting dialer",
-                    LENGTH_LONG)
+                            getCarContext(),
+                            getCarContext().getString(R.string.fail_start_dialer),
+                            LENGTH_LONG)
                     .show();
         }
     }
-
-    private PlaceDetailsScreen(@NonNull CarContext carContext, @NonNull PlaceInfo place) {
-        super(carContext);
-        mPlace = place;
-    }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
index d502dd9..aa6b979 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
@@ -55,12 +55,191 @@
     private final List<PlaceInfo> mPlaces;
     private final Screen mDemoScreen;
 
+    private SamplePlaces(Screen demoScreen) {
+        mDemoScreen = demoScreen;
+
+        CarContext carContext = demoScreen.getCarContext();
+
+        mAnchorLocation = new Location("ShowcaseDemo");
+        mAnchorLocation.setLatitude(47.6204588);
+        mAnchorLocation.setLongitude(-122.1918818);
+
+        mPlaces = getSamplePlaces(carContext);
+    }
+
     /** Create an instance of {@link SamplePlaces}. */
     @NonNull
     public static SamplePlaces create(@NonNull Screen demoScreen) {
         return new SamplePlaces(demoScreen);
     }
 
+    /**
+     * Returns the list of sample places.
+     *
+     * <p>We use a few Google locations around the Seattle area, using different types of markers to
+     * showcase those options. The "description" field of each place describes the type of marker
+     * itself.
+     */
+    private static List<PlaceInfo> getSamplePlaces(@NonNull CarContext carContext) {
+        List<PlaceInfo> places = new ArrayList<>();
+
+        Location location1 = new Location(SamplePlaces.class.getSimpleName());
+        location1.setLatitude(47.6696482);
+        location1.setLongitude(-122.19950278);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_1_title),
+                        carContext.getString(R.string.location_1_address),
+                        carContext.getString(R.string.location_1_description),
+                        carContext.getString(R.string.location_1_phone),
+                        location1,
+                        new PlaceMarker.Builder()
+                                .setIcon(
+                                        new CarIcon.Builder(
+                                                IconCompat.createWithResource(
+                                                        carContext,
+                                                        R.drawable.ic_commute_24px))
+                                                .setTint(CarColor.BLUE)
+                                                .build(),
+                                        PlaceMarker.TYPE_ICON)
+                                .build()));
+
+        Location location2 = new Location(SamplePlaces.class.getSimpleName());
+        location2.setLatitude(47.6204588);
+        location2.setLongitude(-122.1918818);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_2_title),
+                        carContext.getString(R.string.location_2_address),
+                        carContext.getString(R.string.location_2_description),
+                        carContext.getString(R.string.location_2_phone),
+                        location2,
+                        new PlaceMarker.Builder()
+                                .setIcon(
+                                        new CarIcon.Builder(
+                                                IconCompat.createWithResource(
+                                                        carContext, R.drawable.ic_520))
+                                                .build(),
+                                        PlaceMarker.TYPE_IMAGE)
+                                .build()));
+
+        Location location3 = new Location(SamplePlaces.class.getSimpleName());
+        location3.setLatitude(47.625567);
+        location3.setLongitude(-122.336427);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_3_title),
+                        carContext.getString(R.string.location_3_address),
+                        carContext.getString(R.string.location_3_description),
+                        carContext.getString(R.string.location_3_phone),
+                        location3,
+                        new PlaceMarker.Builder().setLabel("SLU").setColor(CarColor.RED).build()));
+
+        Location location4 = new Location(SamplePlaces.class.getSimpleName());
+        location4.setLatitude(47.6490374);
+        location4.setLongitude(-122.3527127);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_4_title),
+                        carContext.getString(R.string.location_4_address),
+                        carContext.getString(R.string.location_4_description),
+                        carContext.getString(R.string.location_4_phone),
+                        location4,
+                        new PlaceMarker.Builder()
+                                .setIcon(
+                                        new CarIcon.Builder(
+                                                IconCompat.createWithBitmap(
+                                                        BitmapFactory.decodeResource(
+                                                                carContext.getResources(),
+                                                                R.drawable.banana)))
+                                                .build(),
+                                        PlaceMarker.TYPE_IMAGE)
+                                .build()));
+
+        Location location5 = new Location(SamplePlaces.class.getSimpleName());
+        location5.setLatitude(37.422014);
+        location5.setLongitude(-122.084776);
+        SpannableString title5 = new SpannableString(" ");
+        title5.setSpan(CarIconSpan.create(new CarIcon.Builder(
+                        IconCompat.createWithBitmap(
+                                BitmapFactory.decodeResource(
+                                        carContext.getResources(),
+                                        R.drawable.ic_hi)))
+                        .build(), CarIconSpan.ALIGN_BOTTOM),
+                0,
+                1,
+                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+        SpannableString description5 = new SpannableString(" ");
+        places.add(
+                new PlaceInfo(
+                        title5,
+                        carContext.getString(R.string.location_5_address),
+                        description5,
+                        carContext.getString(R.string.location_5_phone),
+                        location5,
+                        new PlaceMarker.Builder()
+                                .setIcon(
+                                        new CarIcon.Builder(
+                                                IconCompat.createWithBitmap(
+                                                        BitmapFactory.decodeResource(
+                                                                carContext.getResources(),
+                                                                R.drawable.test_image_square)))
+                                                .build(),
+                                        PlaceMarker.TYPE_IMAGE)
+                                .build()));
+
+        Location location6 = new Location(SamplePlaces.class.getSimpleName());
+        location6.setLatitude(47.6490374);
+        location6.setLongitude(-122.3527127);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_6_title),
+                        carContext.getString(R.string.location_6_address),
+                        carContext.getString(R.string.location_description_text_label),
+                        carContext.getString(R.string.location_phone_not_available),
+                        location6,
+                        new PlaceMarker.Builder().build()));
+
+        // Some hosts may display more items in the list than others, so create 3 more items.
+        Location location7 = new Location(SamplePlaces.class.getSimpleName());
+        location7.setLatitude(47.5496056);
+        location7.setLongitude(-122.2571713);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_7_title),
+                        carContext.getString(R.string.location_7_address),
+                        carContext.getString(R.string.location_description_text_label),
+                        carContext.getString(R.string.location_phone_not_available),
+                        location7,
+                        new PlaceMarker.Builder().build()));
+
+        Location location8 = new Location(SamplePlaces.class.getSimpleName());
+        location8.setLatitude(47.5911456);
+        location8.setLongitude(-122.2256602);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_8_title),
+                        carContext.getString(R.string.location_8_address),
+                        carContext.getString(R.string.location_description_text_label),
+                        carContext.getString(R.string.location_phone_not_available),
+                        location8,
+                        new PlaceMarker.Builder().build()));
+
+        Location location9 = new Location(SamplePlaces.class.getSimpleName());
+        location9.setLatitude(47.6785932);
+        location9.setLongitude(-122.2113821);
+        places.add(
+                new PlaceInfo(
+                        carContext.getString(R.string.location_9_title),
+                        carContext.getString(R.string.location_9_address),
+                        carContext.getString(R.string.location_description_text_label),
+                        carContext.getString(R.string.location_phone_not_available),
+                        location9,
+                        new PlaceMarker.Builder().build()));
+
+        return places;
+    }
+
     /** Return the {@link ItemList} of the sample places. */
     @NonNull
     public ItemList getPlaceList() {
@@ -140,183 +319,4 @@
                 .getScreenManager()
                 .push(PlaceDetailsScreen.create(mDemoScreen.getCarContext(), place));
     }
-
-    private SamplePlaces(Screen demoScreen) {
-        mDemoScreen = demoScreen;
-
-        CarContext carContext = demoScreen.getCarContext();
-
-        mAnchorLocation = new Location("ShowcaseDemo");
-        mAnchorLocation.setLatitude(47.6204588);
-        mAnchorLocation.setLongitude(-122.1918818);
-
-        mPlaces = getSamplePlaces(carContext);
-    }
-
-    /**
-     * Returns the list of sample places.
-     *
-     * <p>We use a few Google locations around the Seattle area, using different types of markers to
-     * showcase those options. The "description" field of each place describes the type of marker
-     * itself.
-     */
-    private static List<PlaceInfo> getSamplePlaces(@NonNull CarContext carContext) {
-        List<PlaceInfo> places = new ArrayList<>();
-
-        Location location1 = new Location(SamplePlaces.class.getSimpleName());
-        location1.setLatitude(47.6696482);
-        location1.setLongitude(-122.19950278);
-        places.add(
-                new PlaceInfo(
-                        "Google Kirkland",
-                        "747 6th St South, Kirkland, WA 98033",
-                        "Tinted resource vector",
-                        "+14257395600",
-                        location1,
-                        new PlaceMarker.Builder()
-                                .setIcon(
-                                        new CarIcon.Builder(
-                                                IconCompat.createWithResource(
-                                                        carContext,
-                                                        R.drawable.ic_commute_24px))
-                                                .setTint(CarColor.BLUE)
-                                                .build(),
-                                        PlaceMarker.TYPE_ICON)
-                                .build()));
-
-        Location location2 = new Location(SamplePlaces.class.getSimpleName());
-        location2.setLatitude(47.6204588);
-        location2.setLongitude(-122.1918818);
-        places.add(
-                new PlaceInfo(
-                        "Google Bellevue",
-                        "1120 112th Ave NE, Bellevue, WA 98004",
-                        "Image resource bitmap",
-                        "+14252301301",
-                        location2,
-                        new PlaceMarker.Builder()
-                                .setIcon(
-                                        new CarIcon.Builder(
-                                                IconCompat.createWithResource(
-                                                        carContext, R.drawable.ic_520))
-                                                .build(),
-                                        PlaceMarker.TYPE_IMAGE)
-                                .build()));
-
-        Location location3 = new Location(SamplePlaces.class.getSimpleName());
-        location3.setLatitude(47.625567);
-        location3.setLongitude(-122.336427);
-        places.add(
-                new PlaceInfo(
-                        "Google South Lake Union",
-                        "1021 Valley St, Seattle, WA 98109",
-                        "Colored text marker",
-                        "+12065311800",
-                        location3,
-                        new PlaceMarker.Builder().setLabel("SLU").setColor(CarColor.RED).build()));
-
-        Location location4 = new Location(SamplePlaces.class.getSimpleName());
-        location4.setLatitude(47.6490374);
-        location4.setLongitude(-122.3527127);
-        places.add(
-                new PlaceInfo(
-                        "Google Seattle",
-                        "601 N 34th St, Seattle, WA 98103",
-                        "Image bitmap",
-                        "+12068761800",
-                        location4,
-                        new PlaceMarker.Builder()
-                                .setIcon(
-                                        new CarIcon.Builder(
-                                                IconCompat.createWithBitmap(
-                                                        BitmapFactory.decodeResource(
-                                                                carContext.getResources(),
-                                                                R.drawable.banana)))
-                                                .build(),
-                                        PlaceMarker.TYPE_IMAGE)
-                                .build()));
-
-        Location location5 = new Location(SamplePlaces.class.getSimpleName());
-        location5.setLatitude(37.422014);
-        location5.setLongitude(-122.084776);
-        SpannableString title5 = new SpannableString(" ");
-        title5.setSpan(CarIconSpan.create(new CarIcon.Builder(
-                IconCompat.createWithBitmap(
-                        BitmapFactory.decodeResource(
-                                carContext.getResources(),
-                                R.drawable.ic_hi)))
-                .build(), CarIconSpan.ALIGN_BOTTOM),
-                0,
-                1,
-                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
-        SpannableString description5 = new SpannableString(" ");
-        places.add(
-                new PlaceInfo(
-                        title5,
-                        "1600 Amphitheatre Pkwy, Mountain View, CA 94043",
-                        description5,
-                        "+16502530000",
-                        location5,
-                        new PlaceMarker.Builder()
-                                .setIcon(
-                                        new CarIcon.Builder(
-                                                IconCompat.createWithBitmap(
-                                                        BitmapFactory.decodeResource(
-                                                                carContext.getResources(),
-                                                                R.drawable.test_image_square)))
-                                                .build(),
-                                        PlaceMarker.TYPE_IMAGE)
-                                .build()));
-
-        Location location6 = new Location(SamplePlaces.class.getSimpleName());
-        location6.setLatitude(47.6490374);
-        location6.setLongitude(-122.3527127);
-        places.add(
-                new PlaceInfo(
-                        "Google Bothell",
-                        "11831 North Creek Pkwy, Bothell, WA 98011",
-                        "Text label",
-                        "n/a",
-                        location6,
-                        new PlaceMarker.Builder().build()));
-
-        // Some hosts may display more items in the list than others, so create 3 more items.
-        Location location7 = new Location(SamplePlaces.class.getSimpleName());
-        location7.setLatitude(47.5496056);
-        location7.setLongitude(-122.2571713);
-        places.add(
-                new PlaceInfo(
-                        "Seward Park",
-                        "5900 Lake Washington Blvd S, Seattle, WA 98118",
-                        "Text label",
-                        "n/a",
-                        location7,
-                        new PlaceMarker.Builder().build()));
-
-        Location location8 = new Location(SamplePlaces.class.getSimpleName());
-        location8.setLatitude(47.5911456);
-        location8.setLongitude(-122.2256602);
-        places.add(
-                new PlaceInfo(
-                        "Luther Burbank Park",
-                        "2040 84th Ave SE, Mercer Island, WA 98040",
-                        "Text label",
-                        "n/a",
-                        location8,
-                        new PlaceMarker.Builder().build()));
-
-        Location location9 = new Location(SamplePlaces.class.getSimpleName());
-        location9.setLatitude(47.6785932);
-        location9.setLongitude(-122.2113821);
-        places.add(
-                new PlaceInfo(
-                        "Heritage Park",
-                        "111 Waverly Way, Kirkland, WA 98033",
-                        "Text label",
-                        "n/a",
-                        location9,
-                        new PlaceMarker.Builder().build()));
-
-        return places;
-    }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareDemoScreen.java
index b1e1e09..de76440 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareDemoScreen.java
@@ -81,7 +81,8 @@
                                 .build())
                         .addAction(
                                 new Action.Builder()
-                                        .setTitle("BACK")
+                                        .setTitle(getCarContext()
+                                                .getString(R.string.back_caps_action_title))
                                         .setOnClickListener(this::finish)
                                         .build())
                         .build();
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
index 2c125e2..9140932 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/CarHardwareInfoScreen.java
@@ -33,6 +33,7 @@
 import androidx.car.app.model.PaneTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.core.content.ContextCompat;
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.Lifecycle;
@@ -124,25 +125,27 @@
         Pane.Builder paneBuilder = new Pane.Builder();
         if (allInfoAvailable()) {
             Row.Builder modelRowBuilder = new Row.Builder()
-                    .setTitle("Model Information");
+                    .setTitle(getCarContext().getString(R.string.model_info));
             if (!mHasModelPermission) {
-                modelRowBuilder.addText("No Model Permission.");
+                modelRowBuilder.addText(getCarContext().getString(R.string.no_model_permission));
             } else {
                 StringBuilder info = new StringBuilder();
                 if (mModel.getManufacturer().getStatus() != CarValue.STATUS_SUCCESS) {
-                    info.append("Manufacturer unavailable, ");
+                    info.append(getCarContext().getString(R.string.manufacturer_unavailable));
+                    info.append(", ");
                 } else {
                     info.append(mModel.getManufacturer().getValue());
                     info.append(", ");
                 }
                 if (mModel.getName().getStatus() != CarValue.STATUS_SUCCESS) {
-                    info.append("Model unavailable, ");
+                    info.append(getCarContext().getString(R.string.model_unavailable));
+                    info.append(", ");
                 } else {
                     info.append(mModel.getName().getValue());
                     info.append(", ");
                 }
                 if (mModel.getYear().getStatus() != CarValue.STATUS_SUCCESS) {
-                    info.append("Year unavailable");
+                    info.append(getCarContext().getString(R.string.year_unavailable));
                 } else {
                     info.append(mModel.getYear().getValue());
                 }
@@ -151,15 +154,19 @@
             paneBuilder.addRow(modelRowBuilder.build());
 
             Row.Builder energyProfileRowBuilder = new Row.Builder()
-                    .setTitle("Energy Profile");
+                    .setTitle(getCarContext().getString(R.string.energy_profile));
             if (!mHasEnergyProfilePermission) {
-                energyProfileRowBuilder.addText("No Energy Profile Permission.");
+                energyProfileRowBuilder.addText(getCarContext()
+                        .getString(R.string.no_energy_profile_permission));
             } else {
                 StringBuilder fuelInfo = new StringBuilder();
                 if (mEnergyProfile.getFuelTypes().getStatus() != CarValue.STATUS_SUCCESS) {
-                    fuelInfo.append("Fuel Types: Unavailable.");
+                    fuelInfo.append(getCarContext().getString(R.string.fuel_types));
+                    fuelInfo.append(": ");
+                    fuelInfo.append(getCarContext().getString(R.string.unavailable));
                 } else {
-                    fuelInfo.append("Fuel Types: ");
+                    fuelInfo.append(getCarContext().getString(R.string.fuel_types));
+                    fuelInfo.append(": ");
                     for (int fuelType : mEnergyProfile.getFuelTypes().getValue()) {
                         fuelInfo.append(fuelTypeAsString(fuelType));
                         fuelInfo.append(" ");
@@ -168,9 +175,13 @@
                 energyProfileRowBuilder.addText(fuelInfo);
                 StringBuilder evInfo = new StringBuilder();
                 if (mEnergyProfile.getEvConnectorTypes().getStatus() != CarValue.STATUS_SUCCESS) {
-                    evInfo.append(" EV Connector Types: Unavailable.");
+                    evInfo.append(" ");
+                    evInfo.append(getCarContext().getString(R.string.ev_connector_types));
+                    evInfo.append(": ");
+                    evInfo.append(getCarContext().getString(R.string.unavailable));
                 } else {
-                    evInfo.append("EV Connector Types: ");
+                    evInfo.append(getCarContext().getString(R.string.ev_connector_types));
+                    evInfo.append(": ");
                     for (int connectorType : mEnergyProfile.getEvConnectorTypes().getValue()) {
                         evInfo.append(evConnectorAsString(connectorType));
                         evInfo.append(" ");
@@ -184,7 +195,7 @@
         }
         return new PaneTemplate.Builder(paneBuilder.build())
                 .setHeaderAction(Action.BACK)
-                .setTitle("Car Hardware Information")
+                .setTitle(getCarContext().getString(R.string.car_hardware_info))
                 .build();
     }
 
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ColorDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ColorDemoScreen.java
index e638b72..a447320 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ColorDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ColorDemoScreen.java
@@ -49,8 +49,9 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 1")
-                        .addText(Utils.colorize("This text has a red color", RED, 16, 3))
+                        .setTitle(getCarContext().getString(R.string.example_title, 1))
+                        .addText(Utils.colorize(getCarContext().getString(R.string.example_1_text),
+                                RED, 16, 3))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -61,8 +62,9 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 2")
-                        .addText(Utils.colorize("This text has a green color", GREEN, 16, 5))
+                        .setTitle(getCarContext().getString(R.string.example_title, 2))
+                        .addText(Utils.colorize(getCarContext().getString(R.string.example_2_text),
+                                GREEN, 16, 5))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -73,8 +75,9 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 3")
-                        .addText(Utils.colorize("This text has a blue color", BLUE, 16, 4))
+                        .setTitle(getCarContext().getString(R.string.example_title, 3))
+                        .addText(Utils.colorize(getCarContext().getString(R.string.example_3_text),
+                                BLUE, 16, 4))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -85,8 +88,9 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 4")
-                        .addText(Utils.colorize("This text has a yellow color", YELLOW, 16, 6))
+                        .setTitle(getCarContext().getString(R.string.example_title, 4))
+                        .addText(Utils.colorize(getCarContext().getString(R.string.example_4_text),
+                                YELLOW, 16, 6))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -97,8 +101,9 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 5")
-                        .addText(Utils.colorize("This text uses the primary color", PRIMARY, 19, 7))
+                        .setTitle(getCarContext().getString(R.string.example_title, 5))
+                        .addText(Utils.colorize(getCarContext().getString(R.string.example_5_text),
+                                PRIMARY, 19, 7))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -109,10 +114,11 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Example 6")
+                        .setTitle(getCarContext().getString(R.string.example_title, 6))
                         .addText(
                                 Utils.colorize(
-                                        "This text uses the secondary color", SECONDARY, 19, 9))
+                                        getCarContext().getString(R.string.example_6_text),
+                                        SECONDARY, 19, 9))
                         .setImage(new CarIcon.Builder(
                                 IconCompat.createWithResource(
                                         getCarContext(),
@@ -123,7 +129,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Color Demo")
+                .setTitle(getCarContext().getString(R.string.color_demo))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ContentLimitsDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ContentLimitsDemoScreen.java
index 9f3e853..d50f284 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ContentLimitsDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ContentLimitsDemoScreen.java
@@ -26,6 +26,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /**
  * A {@link Screen} that shows examples on how to query for various content limits via the
@@ -44,31 +45,31 @@
         ItemList.Builder listBuilder = new ItemList.Builder();
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("List Limit")
+                        .setTitle(getCarContext().getString(R.string.list_limit))
                         .addText(Integer.toString(manager.getContentLimit(
                                 ConstraintManager.CONTENT_LIMIT_TYPE_LIST)))
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Grid Limit")
+                        .setTitle(getCarContext().getString(R.string.grid_limit))
                         .addText(Integer.toString(manager.getContentLimit(
                                 ConstraintManager.CONTENT_LIMIT_TYPE_GRID)))
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Pane Limit")
+                        .setTitle(getCarContext().getString(R.string.pane_limit))
                         .addText(Integer.toString(manager.getContentLimit(
                                 ConstraintManager.CONTENT_LIMIT_TYPE_PANE)))
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Place List Limit")
+                        .setTitle(getCarContext().getString(R.string.place_list_limit))
                         .addText(Integer.toString(manager.getContentLimit(
                                 ConstraintManager.CONTENT_LIMIT_TYPE_PLACE_LIST)))
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Route List Limit")
+                        .setTitle(getCarContext().getString(R.string.route_list_limit))
                         .addText(Integer.toString(manager.getContentLimit(
                                 ConstraintManager.CONTENT_LIMIT_TYPE_ROUTE_LIST)))
                         .build());
@@ -76,7 +77,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Content Limits")
+                .setTitle(getCarContext().getString(R.string.content_limits))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/FinishAppScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/FinishAppScreen.java
index b7d239b..2466224 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/FinishAppScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/FinishAppScreen.java
@@ -26,6 +26,7 @@
 import androidx.car.app.model.Action;
 import androidx.car.app.model.MessageTemplate;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.sample.showcase.common.ShowcaseService;
 
 /** A {@link Screen} that provides an action to exit the car app. */
@@ -37,10 +38,8 @@
     @NonNull
     @Override
     public Template onGetTemplate() {
-        return new MessageTemplate.Builder(
-                "This will finish the app, and when you return it will pre-seed a permission "
-                        + "screen")
-                .setTitle("Finish App Demo")
+        return new MessageTemplate.Builder(getCarContext().getString(R.string.finish_app_msg))
+                .setTitle(getCarContext().getString(R.string.finish_app_title))
                 .setHeaderAction(BACK)
                 .addAction(
                         new Action.Builder()
@@ -56,7 +55,7 @@
                                                     .apply();
                                             getCarContext().finishCarApp();
                                         })
-                                .setTitle("Exit")
+                                .setTitle(getCarContext().getString(R.string.exit_action_title))
                                 .build())
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/LoadingDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/LoadingDemoScreen.java
index 6af04ed..1c23c76 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/LoadingDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/LoadingDemoScreen.java
@@ -28,6 +28,7 @@
 import androidx.car.app.model.PaneTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
 
@@ -62,11 +63,13 @@
         if (!mIsFinishedLoading) {
             paneBuilder.setLoading(true);
         } else {
-            paneBuilder.addRow(new Row.Builder().setTitle("Loading Complete!").build());
+            paneBuilder.addRow(new Row.Builder()
+                    .setTitle(getCarContext().getString(R.string.loading_demo_row_title))
+                    .build());
         }
 
         return new PaneTemplate.Builder(paneBuilder.build())
-                .setTitle("Loading Demo")
+                .setTitle(getCarContext().getString(R.string.loading_demo_title))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/MiscDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/MiscDemoScreen.java
index 034eb41..06ae337 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/MiscDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/MiscDemoScreen.java
@@ -27,6 +27,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.sample.showcase.common.ShowcaseSession;
 
 /** Creates a screen that has an assortment of API demos. */
@@ -59,23 +60,28 @@
 
         switch (mPage) {
             case 0:
-                listBuilder.addItem(createRow("Notification Demo",
+                listBuilder.addItem(createRow(getCarContext().getString(R.string.notification_demo),
                         new NotificationDemoScreen(getCarContext())));
-                listBuilder.addItem(createRow("PopTo Demo",
+                listBuilder.addItem(createRow(getCarContext().getString(R.string.pop_to_title),
                         new PopToDemoScreen(getCarContext())));
-                listBuilder.addItem(createRow("Loading Demo",
-                        new LoadingDemoScreen(getCarContext())));
-                listBuilder.addItem(createRow("Request Permission Demo",
-                        new RequestPermissionScreen(getCarContext())));
-                listBuilder.addItem(createRow("Pre-seed the Screen backstack on next run Demo",
-                        new FinishAppScreen(getCarContext())));
-                listBuilder.addItem(createRow("Car Hardware Demo",
-                        new CarHardwareDemoScreen(getCarContext(), mShowcaseSession)));
+                listBuilder.addItem(
+                        createRow(getCarContext().getString(R.string.loading_demo_title),
+                                new LoadingDemoScreen(getCarContext())));
+                listBuilder.addItem(
+                        createRow(getCarContext().getString(R.string.request_permissions_title),
+                                new RequestPermissionScreen(getCarContext())));
+                listBuilder.addItem(
+                        createRow(getCarContext().getString(R.string.finish_app_demo_title),
+                                new FinishAppScreen(getCarContext())));
+                listBuilder.addItem(
+                        createRow(getCarContext().getString(R.string.car_hardware_demo_title),
+                                new CarHardwareDemoScreen(getCarContext(), mShowcaseSession)));
                 break;
             case 1:
-                listBuilder.addItem(createRow("Content Limits Demo",
-                        new ContentLimitsDemoScreen(getCarContext())));
-                listBuilder.addItem(createRow("Color Demo",
+                listBuilder.addItem(
+                        createRow(getCarContext().getString(R.string.content_limits_demo_title),
+                                new ContentLimitsDemoScreen(getCarContext())));
+                listBuilder.addItem(createRow(getCarContext().getString(R.string.color_demo),
                         new ColorDemoScreen(getCarContext())));
                 break;
 
@@ -83,13 +89,13 @@
 
         ListTemplate.Builder builder = new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Misc Demos")
+                .setTitle(getCarContext().getString(R.string.misc_demo_title))
                 .setHeaderAction(BACK);
 
         if (mPage + 1 < MAX_PAGES) {
             builder.setActionStrip(new ActionStrip.Builder()
                     .addAction(new Action.Builder()
-                            .setTitle("More")
+                            .setTitle(getCarContext().getString(R.string.more_action_title))
                             .setOnClickListener(() -> {
                                 getScreenManager().push(
                                         new MiscDemoScreen(getCarContext(), mShowcaseSession,
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
index 7951ef1..a233245 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/NotificationDemoScreen.java
@@ -57,44 +57,39 @@
 /** A simple screen that demonstrates how to use notifications in a car app. */
 public final class NotificationDemoScreen extends Screen implements DefaultLifecycleObserver {
 
+    static final long NOTIFICATION_DELAY_IN_MILLIS = SECONDS.toMillis(1);
     private static final String NOTIFICATION_CHANNEL_ID = "channel_00";
     private static final CharSequence NOTIFICATION_CHANNEL_NAME = "Default Channel";
     private static final int NOTIFICATION_ID = 1001;
-
     private static final String NOTIFICATION_CHANNEL_HIGH_ID = "channel_01";
     private static final CharSequence NOTIFICATION_CHANNEL_HIGH_NAME = "High Channel";
-
     private static final String NOTIFICATION_CHANNEL_LOW_ID = "channel_02";
     private static final CharSequence NOTIFICATION_CHANNEL_LOW_NAME = "Low Channel";
-
     private static final String INTENT_ACTION_PRIMARY_PHONE =
             "androidx.car.app.sample.showcase.common.INTENT_ACTION_PRIMARY_PHONE";
     private static final String INTENT_ACTION_SECONDARY_PHONE =
             "androidx.car.app.sample.showcase.common.INTENT_ACTION_SECONDARY_PHONE";
-
     private static final int MSG_SEND_NOTIFICATION = 1;
-
-    static final long NOTIFICATION_DELAY_IN_MILLIS = SECONDS.toMillis(1);
     final Handler mHandler = new Handler(Looper.getMainLooper(), new HandlerCallback());
 
     private final IconCompat mIcon = IconCompat.createWithResource(getCarContext(),
             R.drawable.ic_face_24px);
-    private int mImportance = NotificationManager.IMPORTANCE_DEFAULT;
-    private boolean mIsNavCategory = false;
-    private boolean mSetOngoing = false;
-    private int mNotificationCount = 0;
-
     /** A broadcast receiver that can show a toast message upon receiving a broadcast. */
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             CarToast.makeText(
-                    getCarContext(),
-                    "Triggered: " + intent.getAction(),
-                    CarToast.LENGTH_SHORT)
+                            getCarContext(),
+                            getCarContext().getString(R.string.triggered_toast_msg) + ": "
+                                    + intent.getAction(),
+                            CarToast.LENGTH_SHORT)
                     .show();
         }
     };
+    private int mImportance = NotificationManager.IMPORTANCE_DEFAULT;
+    private boolean mIsNavCategory = false;
+    private boolean mSetOngoing = false;
+    private int mNotificationCount = 0;
 
     public NotificationDemoScreen(@NonNull CarContext carContext) {
         super(carContext);
@@ -121,7 +116,7 @@
         // Send a single notification with the settings configured by other buttons.
         listBuilder.addItem(
                 new GridItem.Builder()
-                        .setTitle("Send a notification")
+                        .setTitle(getCarContext().getString(R.string.send_notification_title))
                         .setImage(new CarIcon.Builder(mIcon).build())
                         .setOnClickListener(this::sendNotification)
                         .build());
@@ -129,7 +124,7 @@
         // Start a repeating notification with the settings configured by other buttons.
         listBuilder.addItem(
                 new GridItem.Builder()
-                        .setTitle("Start notifications")
+                        .setTitle(getCarContext().getString(R.string.start_notifications_title))
                         .setImage(new CarIcon.Builder(mIcon).build())
                         .setOnClickListener(() -> mHandler.sendMessage(
                                 mHandler.obtainMessage(MSG_SEND_NOTIFICATION)))
@@ -138,7 +133,7 @@
         // Stop the repeating notification and reset the count.
         listBuilder.addItem(
                 new GridItem.Builder()
-                        .setTitle("Stop notifications")
+                        .setTitle(getCarContext().getString(R.string.stop_notifications_title))
                         .setImage(new CarIcon.Builder(mIcon).build())
                         .setOnClickListener(() -> {
                             mHandler.removeMessages(MSG_SEND_NOTIFICATION);
@@ -151,7 +146,7 @@
         listBuilder.addItem(
                 new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build())
-                        .setTitle("Importance")
+                        .setTitle(getCarContext().getString(R.string.importance_title))
                         .setText(getImportanceString())
                         .setOnClickListener(() -> {
                             setImportance();
@@ -163,7 +158,7 @@
         listBuilder.addItem(
                 new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build())
-                        .setTitle("Category")
+                        .setTitle(getCarContext().getString(R.string.category_title))
                         .setText(getCategoryString())
                         .setOnClickListener(() -> {
                             mIsNavCategory = !mIsNavCategory;
@@ -175,7 +170,7 @@
         listBuilder.addItem(
                 new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build())
-                        .setTitle("Ongoing")
+                        .setTitle(getCarContext().getString(R.string.ongoing_title))
                         .setText(String.valueOf(mSetOngoing))
                         .setOnClickListener(() -> {
                             mSetOngoing = !mSetOngoing;
@@ -185,15 +180,19 @@
 
         return new GridTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Notification Demo")
+                .setTitle(getCarContext().getString(R.string.notification_demo))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
 
     void sendNotification() {
         mNotificationCount++;
-        String title = "Notification: " + getImportanceString() + ", " + mNotificationCount;
-        String text = "Category: " + getCategoryString() + ", ongoing: " + mSetOngoing;
+        String title =
+                getCarContext().getString(R.string.notification_title) + ": "
+                        + getImportanceString() + ", " + mNotificationCount;
+        String text = getCarContext().getString(R.string.category_title) + ": "
+                + getCategoryString() + ", "
+                + getCarContext().getString(R.string.ongoing_title) + ": " + mSetOngoing;
 
         switch (mImportance) {
             case NotificationManager.IMPORTANCE_HIGH:
@@ -269,11 +268,11 @@
                                                 R.drawable.ic_hi))
                                 .addAction(
                                         R.drawable.ic_commute_24px,
-                                        "Navigate",
+                                        getCarContext().getString(R.string.navigate),
                                         getPendingIntentForNavigation())
                                 .addAction(
                                         R.drawable.ic_face_24px,
-                                        "Call",
+                                        getCarContext().getString(R.string.call_action_title),
                                         createPendingIntentForCall())
                                 .build());
 
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/PopToDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/PopToDemoScreen.java
index 78bff01..06b3699 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/PopToDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/PopToDemoScreen.java
@@ -25,6 +25,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /**
  * A {@link Screen} that allows you to push deeper in the screen stack, or pop to previous marker,
@@ -48,17 +49,17 @@
         ItemList.Builder listBuilder = new ItemList.Builder();
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Pop to root")
+                        .setTitle(getCarContext().getString(R.string.pop_to_root))
                         .setOnClickListener(() -> getScreenManager().popToRoot())
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Pop to Misc Demo Marker")
+                        .setTitle(getCarContext().getString(R.string.pop_to_marker))
                         .setOnClickListener(() -> getScreenManager().popTo(MiscDemoScreen.MARKER))
                         .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Push further in stack")
+                        .setTitle(getCarContext().getString(R.string.push_stack))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -69,7 +70,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Pop To " + mId)
+                .setTitle(getCarContext().getString(R.string.pop_to_prefix) + mId)
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/RequestPermissionScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/RequestPermissionScreen.java
index 7f9e70d..95db90e 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/RequestPermissionScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/RequestPermissionScreen.java
@@ -37,6 +37,7 @@
 import androidx.car.app.model.OnClickListener;
 import androidx.car.app.model.ParkedOnlyOnClickListener;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.core.location.LocationManagerCompat;
 
 import java.util.ArrayList;
@@ -63,7 +64,7 @@
      * the permissions that need to be granted.
      */
     private final Action mRefreshAction = new Action.Builder()
-            .setTitle("Refresh")
+            .setTitle(getCarContext().getString(R.string.refresh_action_title))
             .setBackgroundColor(CarColor.BLUE)
             .setOnClickListener(this::invalidate)
             .build();
@@ -91,7 +92,8 @@
                             PackageManager.GET_PERMISSIONS);
             declaredPermissions = info.requestedPermissions;
         } catch (PackageManager.NameNotFoundException e) {
-            return new MessageTemplate.Builder("Package Not found.")
+            return new MessageTemplate.Builder(
+                    getCarContext().getString(R.string.package_not_found_error_msg))
                     .setHeaderAction(headerAction)
                     .addAction(mRefreshAction)
                     .build();
@@ -112,18 +114,18 @@
             }
         }
         if (permissions.isEmpty()) {
-            return new MessageTemplate.Builder("All permissions have been granted. Please "
-                    + "revoke permissions from Settings.")
+            return new MessageTemplate.Builder(
+                    getCarContext().getString(R.string.permissions_granted_msg))
                     .setHeaderAction(headerAction)
                     .addAction(new Action.Builder()
-                            .setTitle("Close")
+                            .setTitle(getCarContext().getString(R.string.close_action_title))
                             .setOnClickListener(this::finish)
                             .build())
                     .build();
         }
 
         StringBuilder message = new StringBuilder()
-                .append("The app needs access to the following permissions:\n");
+                .append(getCarContext().getString(R.string.needs_access_msg_prefix));
         for (String permission : permissions) {
             message.append(permission);
             message.append("\n");
@@ -139,13 +141,14 @@
                                 CarToast.LENGTH_LONG).show();
                     });
             if (!getCarContext().getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
-                CarToast.makeText(getCarContext(), "Grant Permission on the phone screen",
+                CarToast.makeText(getCarContext(),
+                        getCarContext().getString(R.string.phone_screen_permission_msg),
                         CarToast.LENGTH_LONG).show();
             }
         });
 
         Action action = new Action.Builder()
-                .setTitle("Grant Access")
+                .setTitle(getCarContext().getString(R.string.grant_access_action_title))
                 .setBackgroundColor(CarColor.BLUE)
                 .setOnClickListener(listener)
                 .build();
@@ -155,9 +158,11 @@
         LocationManager locationManager =
                 (LocationManager) getCarContext().getSystemService(Context.LOCATION_SERVICE);
         if (!LocationManagerCompat.isLocationEnabled(locationManager)) {
-            message.append("Enable Location Permissions on device\n");
+            message.append(
+                    getCarContext().getString(R.string.enable_location_permission_on_device_msg));
+            message.append("\n");
             action2 = new Action.Builder()
-                    .setTitle("Enable Location")
+                    .setTitle(getCarContext().getString(R.string.enable_location_action_title))
                     .setBackgroundColor(CarColor.BLUE)
                     .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
                         getCarContext().startActivity(
@@ -165,8 +170,9 @@
                                         Intent.FLAG_ACTIVITY_NEW_TASK));
                         if (!getCarContext().getPackageManager().hasSystemFeature(
                                 FEATURE_AUTOMOTIVE)) {
-                            CarToast.makeText(getCarContext(), "Enable location on the phone "
-                                            + "screen",
+                            CarToast.makeText(getCarContext(),
+                                    getCarContext().getString(
+                                            R.string.enable_location_permission_on_phone_msg),
                                     CarToast.LENGTH_LONG).show();
                         }
                     }))
@@ -175,7 +181,7 @@
 
 
         LongMessageTemplate.Builder builder = new LongMessageTemplate.Builder(message)
-                .setTitle("Required Permissions")
+                .setTitle(getCarContext().getString(R.string.required_permissions_title))
                 .addAction(action)
                 .setHeaderAction(headerAction);
 
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ReservationCancelledScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ReservationCancelledScreen.java
index 36dce22..fb8d0b9 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ReservationCancelledScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ReservationCancelledScreen.java
@@ -25,6 +25,7 @@
 import androidx.car.app.model.PaneTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** A screen that displays text about canceling the reservation */
 public final class ReservationCancelledScreen extends Screen {
@@ -36,13 +37,14 @@
     @NonNull
     @Override
     public Template onGetTemplate() {
-        Pane pane =
-                new Pane.Builder()
-                        .addRow(new Row.Builder().setTitle("Reservation canceled").build())
-                        .build();
+        Pane pane = new Pane.Builder()
+                .addRow(new Row.Builder()
+                        .setTitle(getCarContext().getString(R.string.reservation_cancelled_msg))
+                        .build())
+                .build();
 
         return new PaneTemplate.Builder(pane)
-                .setTitle("Cancel Reservation Screen")
+                .setTitle(getCarContext().getString(R.string.cancel_reservation_title))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ResultDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ResultDemoScreen.java
index 884448c..c46df85 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ResultDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/misc/ResultDemoScreen.java
@@ -26,6 +26,7 @@
 import androidx.car.app.model.Action;
 import androidx.car.app.model.MessageTemplate;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /**
  * A screen to demo the use of {@link CarContext#setCarAppResult(int, android.content.Intent)}
@@ -40,16 +41,17 @@
     public Template onGetTemplate() {
         ComponentName callingComponent = getCarContext().getCallingComponent();
         if (callingComponent == null) {
-            return new MessageTemplate.Builder("This app was not started for result")
-                    .setTitle("Result demo")
+            return new MessageTemplate.Builder(
+                    getCarContext().getString(R.string.not_started_for_result_msg))
+                    .setTitle(getCarContext().getString(R.string.result_demo_title))
                     .setHeaderAction(Action.BACK)
                     .build();
         }
 
-        return new MessageTemplate.Builder("This app was called for result from "
-                + callingComponent.getPackageName() + ". Please select the"
-                + " result to send back to the caller")
-                .setTitle("Result demo")
+        return new MessageTemplate.Builder(
+                getCarContext().getString(R.string.started_for_result_msg,
+                        callingComponent.getPackageName()))
+                .setTitle(getCarContext().getString(R.string.result_demo_title))
                 .setHeaderAction(Action.BACK)
                 .addAction(new Action.Builder()
                         .setTitle("Okay (action = 'foo')")
@@ -60,7 +62,7 @@
                         })
                         .build())
                 .addAction(new Action.Builder()
-                        .setTitle("Cancel")
+                        .setTitle(getCarContext().getString(R.string.cancel_action_title))
                         .setOnClickListener(() -> {
                             getCarContext().setCarAppResult(Activity.RESULT_CANCELED, null);
                             getCarContext().finishCarApp();
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java
index e9c59de..8e10bb9 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java
@@ -79,12 +79,12 @@
         paneBuilder.setImage(new CarIcon.Builder(mPaneImage).build());
 
         Action.Builder primaryActionBuilder = new Action.Builder()
-                .setTitle("Reserve Chair")
+                .setTitle(getCarContext().getString(R.string.primary_action_title))
                 .setBackgroundColor(CarColor.BLUE)
                 .setOnClickListener(
                         () -> CarToast.makeText(
                                         getCarContext(),
-                                        "Reserve/Primary button pressed",
+                                        getCarContext().getString(R.string.primary_toast_msg),
                                         LENGTH_SHORT)
                                 .show());
         if (getCarContext().getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
@@ -95,11 +95,12 @@
                 .addAction(primaryActionBuilder.build())
                 .addAction(
                         new Action.Builder()
-                                .setTitle("Options")
+                                .setTitle(getCarContext().getString(R.string.options_action_title))
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
                                                         getCarContext(),
-                                                        "Options button pressed",
+                                                        getCarContext().getString(
+                                                                R.string.options_toast_msg),
                                                         LENGTH_SHORT)
                                                 .show())
                                 .build());
@@ -118,7 +119,11 @@
                         .setOnClickListener(() -> {
                             CarToast.makeText(
                                             getCarContext(),
-                                            mIsFavorite ? "Not a favorite!" : "Favorite!",
+                                            mIsFavorite
+                                                    ? getCarContext()
+                                                            .getString(R.string.favorite_toast_msg)
+                                                    : getCarContext().getString(
+                                                            R.string.not_favorite_toast_msg),
                                             LENGTH_SHORT)
                                     .show();
                             mIsFavorite = !mIsFavorite;
@@ -134,7 +139,7 @@
                                                 R.drawable.ic_close_white_24dp))
                                         .build())
                         .build())
-                .setTitle("Map Template with Pane Demo")
+                .setTitle(getCarContext().getString(R.string.map_template_pane_demo_title))
                 .build();
 
 
@@ -148,7 +153,8 @@
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
                                                         getCarContext(),
-                                                        "Bug reported!",
+                                                        getCarContext().getString(
+                                                                R.string.bug_reported_toast_msg),
                                                         CarToast.LENGTH_SHORT)
                                                 .show())
                                 .setIcon(
@@ -175,18 +181,18 @@
             case 0:
                 // Row with a large image.
                 return new Row.Builder()
-                        .setTitle("Row with a large image and long text long text long text long "
-                                + "text long text")
-                        .addText("Text text text")
-                        .addText("Text text text")
+                        .setTitle(getCarContext().getString(R.string.first_row_title))
+                        .addText(getCarContext().getString(R.string.first_row_text))
+                        .addText(getCarContext().getString(R.string.first_row_text))
                         .setImage(new CarIcon.Builder(mRowLargeIcon).build())
                         .build();
             default:
                 return new Row.Builder()
-                        .setTitle("Row title " + (index + 1))
-                        .addText("R"
-                                + "ow text 1")
-                        .addText("Row text 2")
+                        .setTitle(
+                                getCarContext().getString(R.string.other_row_title_prefix) + (index
+                                        + 1))
+                        .addText(getCarContext().getString(R.string.other_row_text))
+                        .addText(getCarContext().getString(R.string.other_row_text))
                         .build();
 
         }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
index c6a28de..72642a5 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
@@ -49,7 +49,7 @@
                                                 R.drawable.ic_explore_white_24dp))
                                         .build(),
                                 Row.IMAGE_TYPE_ICON)
-                        .setTitle("Navigation Template Demo")
+                        .setTitle(getCarContext().getString(R.string.nav_template_demos_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -61,7 +61,8 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Place List Navigation Template Demo")
+                        .setTitle(getCarContext().getString(
+                                R.string.place_list_nav_template_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -72,7 +73,8 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Route Preview Template Demo")
+                        .setTitle(getCarContext().getString(
+                                R.string.route_preview_template_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -81,7 +83,8 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Notification Template Demo")
+                        .setTitle(getCarContext().getString(
+                                R.string.notification_template_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -92,7 +95,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Navigation Template with map only Demo")
+                        .setTitle(getCarContext().getString(R.string.nav_map_template_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -101,7 +104,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Map Template with Pane Demo")
+                        .setTitle(getCarContext().getString(R.string.map_template_pane_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -110,7 +113,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Navigation Demos")
+                .setTitle(getCarContext().getString(R.string.nav_demos_title))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationMapOnlyScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationMapOnlyScreen.java
index ca57c8c..b328da4 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationMapOnlyScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationMapOnlyScreen.java
@@ -23,6 +23,7 @@
 import androidx.car.app.model.ActionStrip;
 import androidx.car.app.model.Template;
 import androidx.car.app.navigation.model.NavigationTemplate;
+import androidx.car.app.sample.showcase.common.R;
 
 /** Simple demo of how to present a navigation screen with only a map. */
 public final class NavigationMapOnlyScreen extends Screen {
@@ -38,7 +39,8 @@
                 new ActionStrip.Builder()
                         .addAction(
                                 new Action.Builder()
-                                        .setTitle("BACK")
+                                        .setTitle(getCarContext().getString(
+                                                R.string.back_caps_action_title))
                                         .setOnClickListener(this::finish)
                                         .build())
                         .build();
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationService.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationService.java
index 3d1b041..d79a8e5 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationService.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationService.java
@@ -61,7 +61,7 @@
      * The number of notifications fired so far.
      *
      * <p>We use this number to post notifications with a repeating list of directions. See {@link
-     * #getDirectionInfo(int)} for details.
+     * #getDirectionInfo(Context, int)} for details.
      */
     int mNotificationCount = 0;
 
@@ -119,7 +119,7 @@
             Context context, int notificationCount) {
         NotificationCompat.Builder builder =
                 new NotificationCompat.Builder(context, NAV_NOTIFICATION_CHANNEL_ID);
-        DirectionInfo directionInfo = getDirectionInfo(notificationCount);
+        DirectionInfo directionInfo = getDirectionInfo(context, notificationCount);
 
         // Set an intent to open the car app. The app receives this intent when the user taps the
         // heads-up notification or the rail widget.
@@ -189,7 +189,7 @@
      * <p>There are 5 directions, repeating in order. For each direction, the alert will only show
      * once, but the distance will update on every count on the rail widget.
      */
-    private static DirectionInfo getDirectionInfo(int notificationCount) {
+    private static DirectionInfo getDirectionInfo(Context context, int notificationCount) {
         DecimalFormat formatter = new DecimalFormat("#.##");
         formatter.setRoundingMode(RoundingMode.DOWN);
         int repeatingCount = notificationCount % 35;
@@ -197,7 +197,7 @@
             // Distance decreases from 1km to 0.1km
             String distance = formatter.format((10 - repeatingCount) * 0.1) + "km";
             return new DirectionInfo(
-                    "Go Straight",
+                    context.getString(R.string.go_straight),
                     distance,
                     R.drawable.arrow_straight,
                     /* onlyAlertOnce= */ repeatingCount > 0);
@@ -205,7 +205,7 @@
             // Distance decreases from 5km to 0.5km
             String distance = formatter.format((20 - repeatingCount) * 0.5) + "km";
             return new DirectionInfo(
-                    "Turn Right",
+                    context.getString(R.string.turn_right),
                     distance,
                     R.drawable.arrow_right_turn,
                     /* onlyAlertOnce= */ repeatingCount > 10);
@@ -213,7 +213,7 @@
             // Distance decreases from 200m to 40m
             String distance = formatter.format((25 - repeatingCount) * 40) + "m";
             return new DirectionInfo(
-                    "Take 520",
+                    context.getString(R.string.take_520),
                     distance,
                     R.drawable.ic_520,
                     /* onlyAlertOnce= */ repeatingCount > 20);
@@ -221,7 +221,7 @@
             // Distance decreases from 1km to 0.1km
             String distance = formatter.format((35 - repeatingCount) * 0.1) + "km";
             return new DirectionInfo(
-                    "Gas Station",
+                    context.getString(R.string.gas_station),
                     distance,
                     R.drawable.ic_local_gas_station_white_48dp,
                     repeatingCount > 25);
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationsDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationsDemoScreen.java
index 2db959c..e183ab3 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationsDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationNotificationsDemoScreen.java
@@ -30,6 +30,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** A simple screen that demonstrates how to use navigation notifications in a car app. */
 public final class NavigationNotificationsDemoScreen extends Screen {
@@ -48,7 +49,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Start Notification")
+                        .setTitle(getCarContext().getString(R.string.start_notification_title))
                         .setOnClickListener(
                                 () -> {
                                     Context context = getCarContext();
@@ -65,7 +66,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Stop Notification")
+                        .setTitle(getCarContext().getString(R.string.stop_notification_title))
                         .setOnClickListener(
                                 () ->
                                         getCarContext()
@@ -78,7 +79,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Navigation Notification Demo")
+                .setTitle(getCarContext().getString(R.string.nav_notification_demo_title))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java
index ffd9a81..16e2e22 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java
@@ -23,6 +23,7 @@
 import androidx.car.app.model.ActionStrip;
 import androidx.car.app.model.Template;
 import androidx.car.app.navigation.model.PlaceListNavigationTemplate;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.sample.showcase.common.common.SamplePlaces;
 import androidx.car.app.sample.showcase.common.navigation.routing.RoutingDemoModels;
 
@@ -47,7 +48,8 @@
                         new ActionStrip.Builder()
                                 .addAction(
                                         new Action.Builder()
-                                                .setTitle("Search")
+                                                .setTitle(getCarContext().getString(
+                                                        R.string.search_action_title))
                                                 .setOnClickListener(() -> {
                                                 })
                                                 .build())
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/RoutePreviewDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/RoutePreviewDemoScreen.java
index 84cf7ad..8f2fe42 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/RoutePreviewDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/RoutePreviewDemoScreen.java
@@ -32,6 +32,7 @@
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
 import androidx.car.app.navigation.model.RoutePreviewNavigationTemplate;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.sample.showcase.common.navigation.routing.RoutingDemoModels;
 import androidx.car.app.versioning.CarAppApiLevels;
 
@@ -48,27 +49,35 @@
             case 0:
                 // Set text variants for the first route.
                 SpannableString shortRouteLongText = new SpannableString(
-                        "   \u00b7 ---------------- Short" + "  " + "route "
-                                + "-------------------");
+                        "   \u00b7 ---------------- " + getCarContext().getString(
+                                R.string.short_route)
+                                + " -------------------");
                 shortRouteLongText.setSpan(DurationSpan.create(TimeUnit.HOURS.toSeconds(26)), 0, 1,
                         0);
-                SpannableString firstRouteShortText = new SpannableString("   \u00b7 Short route");
+                SpannableString firstRouteShortText = new SpannableString(
+                        "   \u00b7 " + getCarContext().getString(R.string.short_route));
                 firstRouteShortText.setSpan(DurationSpan.create(TimeUnit.HOURS.toSeconds(26)), 0, 1,
                         0);
                 return new CarText.Builder(shortRouteLongText)
                         .addVariant(firstRouteShortText)
                         .build();
             case 1:
-                SpannableString lessBusyRouteText = new SpannableString("   \u00b7 Less busy");
+                SpannableString lessBusyRouteText =
+                        new SpannableString(
+                                "   \u00b7 " + getCarContext().getString(R.string.less_busy));
                 lessBusyRouteText.setSpan(DurationSpan.create(TimeUnit.HOURS.toSeconds(24)), 0, 1,
                         0);
                 return new CarText.Builder(lessBusyRouteText).build();
             case 2:
-                SpannableString hovRouteText = new SpannableString("   \u00b7 HOV friendly");
+                SpannableString hovRouteText =
+                        new SpannableString(
+                                "   \u00b7 " + getCarContext().getString(R.string.hov_friendly));
                 hovRouteText.setSpan(DurationSpan.create(TimeUnit.MINUTES.toSeconds(867)), 0, 1, 0);
                 return new CarText.Builder(hovRouteText).build();
             default:
-                SpannableString routeText = new SpannableString("   \u00b7 Long route");
+                SpannableString routeText =
+                        new SpannableString(
+                                "   \u00b7 " + getCarContext().getString(R.string.long_route));
                 routeText.setSpan(DurationSpan.create(TimeUnit.MINUTES.toSeconds(867L + index)),
                         0, 1, 0);
                 return new CarText.Builder(routeText).build();
@@ -105,8 +114,9 @@
 
         // Set text variants for the navigate action text.
         CarText navigateActionText =
-                new CarText.Builder("Continue to start navigation").addVariant("Continue to "
-                        + "route").build();
+                new CarText.Builder(getCarContext().getString(R.string.continue_start_nav))
+                        .addVariant(getCarContext().getString(R.string.continue_route))
+                        .build();
 
         return new RoutePreviewNavigationTemplate.Builder()
                 .setItemList(itemListBuilder.build())
@@ -115,25 +125,30 @@
                                 .setTitle(navigateActionText)
                                 .setOnClickListener(this::onNavigate)
                                 .build())
-                .setTitle("Routes")
+                .setTitle(getCarContext().getString(R.string.routes_title))
                 .setMapActionStrip(RoutingDemoModels.getMapActionStrip(getCarContext()))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
 
     private void onNavigate() {
-        CarToast.makeText(getCarContext(), "Navigation Requested", LENGTH_LONG * 2).show();
+        CarToast.makeText(getCarContext(),
+                getCarContext().getString(R.string.nav_requested_toast_msg),
+                LENGTH_LONG * 2).show();
     }
 
     private void onRouteSelected(int index) {
-        CarToast.makeText(getCarContext(), "Selected route: " + index, LENGTH_LONG).show();
+        CarToast.makeText(getCarContext(),
+                getCarContext().getString(R.string.selected_route_toast_msg) + ": " + index,
+                LENGTH_LONG).show();
     }
 
     private void onRoutesVisible(int startIndex, int endIndex) {
         CarToast.makeText(
-                getCarContext(),
-                "Visible routes: [" + startIndex + "," + endIndex + "]",
-                LENGTH_LONG)
+                        getCarContext(),
+                        getCarContext().getString(R.string.visible_routes_toast_msg)
+                                + ": [" + startIndex + "," + endIndex + "]",
+                        LENGTH_LONG)
                 .show();
     }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/ArrivedDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/ArrivedDemoScreen.java
index 78a58f9..0368d0e 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/ArrivedDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/ArrivedDemoScreen.java
@@ -39,8 +39,9 @@
     public Template onGetTemplate() {
         return new NavigationTemplate.Builder()
                 .setNavigationInfo(
-                        new MessageInfo.Builder("Arrived!")
-                                .setText("Google Bellevue Office\n1120 112th Ave NE")
+                        new MessageInfo.Builder(
+                                getCarContext().getString(R.string.arrived_exclamation_msg))
+                                .setText(getCarContext().getString(R.string.arrived_address_msg))
                                 .setImage(
                                         new CarIcon.Builder(
                                                 IconCompat.createWithResource(
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/NavigationTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/NavigationTemplateDemoScreen.java
index 2f849e6..7ed0a75 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/NavigationTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/NavigationTemplateDemoScreen.java
@@ -24,6 +24,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** A screen showing a demos for the navigation template in different states. */
 public final class NavigationTemplateDemoScreen extends Screen {
@@ -38,7 +39,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Loading Demo")
+                        .setTitle(getCarContext().getString(R.string.loading_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -47,7 +48,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Navigating Demo")
+                        .setTitle(getCarContext().getString(R.string.navigating_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -56,7 +57,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Arrived Demo")
+                        .setTitle(getCarContext().getString(R.string.arrived_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -65,7 +66,7 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Junction Image Demo")
+                        .setTitle(getCarContext().getString(R.string.junction_image_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -74,7 +75,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Navigation Template Demos")
+                .setTitle(getCarContext().getString(R.string.nav_template_demos_title))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/RoutingDemoModels.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/RoutingDemoModels.java
index cc374fc..55583e4 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/RoutingDemoModels.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/routing/RoutingDemoModels.java
@@ -48,11 +48,14 @@
 /** A class that provides models for the routing demos. */
 public abstract class RoutingDemoModels {
 
+    private RoutingDemoModels() {
+    }
+
     /** Returns the current {@link Step} with information such as the cue text and images. */
     @NonNull
     public static Step getCurrentStep(@NonNull CarContext carContext) {
         // Create the cue text, and span the "520" text with a highway sign image.
-        String currentStepCue = "Roy st 520";
+        String currentStepCue = carContext.getString(R.string.current_step_cue);
         SpannableString currentStepCueWithImage = new SpannableString(currentStepCue);
         CarIconSpan highwaySign =
                 CarIconSpan.create(
@@ -101,7 +104,7 @@
     @NonNull
     public static Step getNextStep(@NonNull CarContext carContext) {
         // Create the cue text, and span the "I5" text with an image.
-        String nextStepCue = "I5 Aurora Ave N";
+        String nextStepCue = carContext.getString(R.string.next_step_cue);
         SpannableString nextStepCueWithImage = new SpannableString(nextStepCue);
         CarIconSpan highwaySign =
                 CarIconSpan.create(
@@ -134,7 +137,8 @@
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
                                                         carContext,
-                                                        "Bug reported!",
+                                                        carContext.getString(
+                                                                R.string.bug_reported_toast_msg),
                                                         CarToast.LENGTH_SHORT)
                                                 .show())
                                 .setIcon(
@@ -146,7 +150,7 @@
                                 .build())
                 .addAction(
                         new Action.Builder()
-                                .setTitle("Stop")
+                                .setTitle(carContext.getString(R.string.stop_action_title))
                                 .setOnClickListener(onStopNavigation)
                                 .setFlags(Action.FLAG_IS_PERSISTENT)
                                 .build())
@@ -165,7 +169,8 @@
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
                                                         carContext,
-                                                        "Zoomed in",
+                                                        carContext.getString(
+                                                                R.string.zoomed_in_toast_msg),
                                                         CarToast.LENGTH_SHORT)
                                                 .show())
                                 .setIcon(
@@ -180,7 +185,8 @@
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
                                                         carContext,
-                                                        "Zoomed out",
+                                                        carContext.getString(
+                                                                R.string.zoomed_out_toast_msg),
                                                         CarToast.LENGTH_SHORT)
                                                 .show())
                                 .setIcon(
@@ -212,7 +218,7 @@
                 .setRemainingTimeSeconds(TimeUnit.MILLISECONDS.toSeconds(timeToDestinationMillis))
                 .setRemainingTimeColor(CarColor.YELLOW)
                 .setRemainingDistanceColor(CarColor.RED)
-                .setTripText(CarText.create("Pick Up Alice"))
+                .setTripText(CarText.create(carContext.getString(R.string.travel_est_trip_text)))
                 .setTripIcon(new CarIcon.Builder(
                         IconCompat.createWithResource(
                                 carContext,
@@ -220,7 +226,4 @@
                         .build())
                 .build();
     }
-
-    private RoutingDemoModels() {
-    }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
index fc72bed..bca753c 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
@@ -43,6 +43,7 @@
 import androidx.car.app.hardware.info.Mileage;
 import androidx.car.app.hardware.info.Speed;
 import androidx.car.app.hardware.info.TollCard;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.versioning.CarAppApiLevels;
 import androidx.core.content.ContextCompat;
 
@@ -83,16 +84,6 @@
     CarHardwareLocation mCarHardwareLocation;
     @Nullable
     private Runnable mRequestRenderRunnable;
-    private boolean mHasTollCardPermission;
-    private boolean mHasEnergyLevelPermission;
-    private boolean mHasSpeedPermission;
-    private boolean mHasMileagePermission;
-    private boolean mHasEvStatusPermission;
-    private boolean mHasAccelerometerPermission;
-    private boolean mHasGyroscopePermission;
-    private boolean mHasCompassPermission;
-    private boolean mHasCarHardwareLocationPermission;
-
     private final OnCarDataAvailableListener<TollCard> mTollListener = data -> {
         synchronized (this) {
             Log.i(TAG, "Received toll information:" + data);
@@ -156,6 +147,15 @@
             requestRenderFrame();
         }
     };
+    private boolean mHasTollCardPermission;
+    private boolean mHasEnergyLevelPermission;
+    private boolean mHasSpeedPermission;
+    private boolean mHasMileagePermission;
+    private boolean mHasEvStatusPermission;
+    private boolean mHasAccelerometerPermission;
+    private boolean mHasGyroscopePermission;
+    private boolean mHasCompassPermission;
+    private boolean mHasCarHardwareLocationPermission;
 
     public CarHardwareRenderer(@NonNull CarContext carContext) {
         mCarContext = carContext;
@@ -369,12 +369,13 @@
             // Prepare text for Toll card status
             StringBuilder info = new StringBuilder();
             if (!mHasTollCardPermission) {
-                info.append("No TollCard Permission.");
+                info.append(mCarContext.getString(R.string.no_toll_card_permission));
             } else if (mTollCard == null) {
-                info.append("Fetching Toll information.");
+                info.append(mCarContext.getString(R.string.fetch_toll_info));
             } else {
                 info.append(
-                        generateCarValueText("Toll card state", mTollCard.getCardState(), ". "));
+                        generateCarValueText(mCarContext.getString(R.string.toll_card_state),
+                                mTollCard.getCardState(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -382,18 +383,22 @@
             // Prepare text for Energy Level
             info = new StringBuilder();
             if (!mHasEnergyLevelPermission) {
-                info.append("No EnergyLevel Permission.");
+                info.append(mCarContext.getString(R.string.no_energy_level_permission));
             } else if (mEnergyLevel == null) {
-                info.append("Fetching Energy Level.");
+                info.append(mCarContext.getString(R.string.fetch_energy_level));
             } else {
                 info.append(
-                        generateCarValueText("Low energy", mEnergyLevel.getEnergyIsLow(), ". "));
+                        generateCarValueText(mCarContext.getString(R.string.low_energy),
+                                mEnergyLevel.getEnergyIsLow(), ". "));
                 info.append(
-                        generateCarValueText("Range", mEnergyLevel.getRangeRemainingMeters(),
+                        generateCarValueText(mCarContext.getString(R.string.range),
+                                mEnergyLevel.getRangeRemainingMeters(),
                                 " m. "));
-                info.append(generateCarValueText("Fuel", mEnergyLevel.getFuelPercent(), " %. "));
+                info.append(generateCarValueText(mCarContext.getString(R.string.fuel),
+                        mEnergyLevel.getFuelPercent(), " %. "));
                 info.append(
-                        generateCarValueText("Battery", mEnergyLevel.getBatteryPercent(), " %. "));
+                        generateCarValueText(mCarContext.getString(R.string.battery),
+                                mEnergyLevel.getBatteryPercent(), " %. "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -401,15 +406,17 @@
             // Prepare text for Speed
             info = new StringBuilder();
             if (!mHasSpeedPermission) {
-                info.append("No Speed Permission.");
+                info.append(mCarContext.getString(R.string.no_speed_permission));
             } else if (mSpeed == null) {
-                info.append("Fetching Speed.");
+                info.append(mCarContext.getString(R.string.fetch_speed));
             } else {
-                info.append(generateCarValueText("Display Speed",
+                info.append(generateCarValueText(mCarContext.getString(R.string.display_speed),
                         mSpeed.getDisplaySpeedMetersPerSecond(), " m/s. "));
-                info.append(generateCarValueText("Raw Speed", mSpeed.getRawSpeedMetersPerSecond(),
+                info.append(generateCarValueText(mCarContext.getString(R.string.raw_speed),
+                        mSpeed.getRawSpeedMetersPerSecond(),
                         " m/s. "));
-                info.append(generateCarValueText("Unit", mSpeed.getSpeedDisplayUnit(), ". "));
+                info.append(generateCarValueText(mCarContext.getString(R.string.unit),
+                        mSpeed.getSpeedDisplayUnit(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -419,14 +426,16 @@
                     FEATURE_AUTOMOTIVE)) {
                 info = new StringBuilder();
                 if (!mHasMileagePermission) {
-                    info.append("No Mileage Permission.");
+                    info.append(mCarContext.getString(R.string.no_mileage_permission));
                 } else if (mMileage == null) {
-                    info.append("Fetching mileage.");
+                    info.append(mCarContext.getString(R.string.no_mileage_permission));
                 } else {
                     info.append(
-                            generateCarValueText("Odometer", mMileage.getOdometerMeters(), " m. "));
+                            generateCarValueText(mCarContext.getString(R.string.odometer),
+                                    mMileage.getOdometerMeters(), " m. "));
                     info.append(
-                            generateCarValueText("Unit", mMileage.getDistanceDisplayUnit(), ". "));
+                            generateCarValueText(mCarContext.getString(R.string.unit),
+                                    mMileage.getDistanceDisplayUnit(), ". "));
                 }
                 canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
                 verticalPos += height;
@@ -438,13 +447,13 @@
                 // Prepare text for EV status
                 info = new StringBuilder();
                 if (!mHasEvStatusPermission) {
-                    info.append("No EV status Permission.");
+                    info.append(mCarContext.getString(R.string.no_ev_status_permission));
                 } else if (mEvStatus == null) {
-                    info.append("Fetching EV status.");
+                    info.append(mCarContext.getString(R.string.fetch_ev_status));
                 } else {
-                    info.append(generateCarValueText("Ev Charge Port Connected",
+                    info.append(generateCarValueText(mCarContext.getString(R.string.ev_connected),
                             mEvStatus.getEvChargePortConnected(), ". "));
-                    info.append(generateCarValueText("Ev Charge Port Open",
+                    info.append(generateCarValueText(mCarContext.getString(R.string.ev_open),
                             mEvStatus.getEvChargePortOpen(), ". "));
                 }
                 canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
@@ -454,12 +463,13 @@
             // Prepare text for Accelerometer
             info = new StringBuilder();
             if (!mHasAccelerometerPermission) {
-                info.append("No Accelerometer Permission.");
+                info.append(mCarContext.getString(R.string.no_accelerometer_permission));
             } else if (mAccelerometer == null) {
-                info.append("Fetching accelerometer");
+                info.append(mCarContext.getString(R.string.fetch_accelerometer));
             } else {
                 info.append(
-                        generateCarValueText("Accelerometer", mAccelerometer.getForces(), ". "));
+                        generateCarValueText(mCarContext.getString(R.string.accelerometer),
+                                mAccelerometer.getForces(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -467,11 +477,12 @@
             // Prepare text for Gyroscope
             info = new StringBuilder();
             if (!mHasGyroscopePermission) {
-                info.append("No Gyroscope Permission.");
+                info.append(mCarContext.getString(R.string.no_gyroscope_permission));
             } else if (mGyroscope == null) {
-                info.append("Fetching gyroscope");
+                info.append(mCarContext.getString(R.string.fetch_gyroscope));
             } else {
-                info.append(generateCarValueText("Gyroscope", mGyroscope.getRotations(), ". "));
+                info.append(generateCarValueText(mCarContext.getString(R.string.gyroscope),
+                        mGyroscope.getRotations(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -479,11 +490,12 @@
             // Prepare text for Compass
             info = new StringBuilder();
             if (!mHasCompassPermission) {
-                info.append("No Compass Permission.");
+                info.append(mCarContext.getString(R.string.no_compass_permission));
             } else if (mCompass == null) {
-                info.append("Fetching compass");
+                info.append(mCarContext.getString(R.string.fetch_compass));
             } else {
-                info.append(generateCarValueText("Compass", mCompass.getOrientations(), ". "));
+                info.append(generateCarValueText(mCarContext.getString(R.string.compass),
+                        mCompass.getOrientations(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
@@ -491,12 +503,13 @@
             // Prepare text for Location
             info = new StringBuilder();
             if (!mHasCarHardwareLocationPermission) {
-                info.append("No CarHardwareLocation Permission.");
+                info.append(mCarContext.getString(R.string.no_car_hardware_location));
             } else if (mCarHardwareLocation == null) {
-                info.append("Fetching location");
+                info.append(mCarContext.getString(R.string.fetch_location));
             } else {
-                info.append(generateCarValueText("Car Hardware Location",
-                        mCarHardwareLocation.getLocation(), ". "));
+                info.append(
+                        generateCarValueText(mCarContext.getString(R.string.car_hardware_location),
+                                mCarHardwareLocation.getLocation(), ". "));
             }
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
         }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/GridTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/GridTemplateDemoScreen.java
index 86fb82a..fd0a075 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/GridTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/GridTemplateDemoScreen.java
@@ -91,18 +91,19 @@
                 // Grid item with an icon and a title.
                 return new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build(), GridItem.IMAGE_TYPE_ICON)
-                        .setTitle("Non-actionable")
+                        .setTitle(getCarContext().getString(R.string.non_actionable))
                         .build();
             case 1:
                 // Grid item with an icon, a title, onClickListener and no text.
                 return new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build(), GridItem.IMAGE_TYPE_ICON)
-                        .setTitle("Second Item")
+                        .setTitle(getCarContext().getString(R.string.second_item))
                         .setOnClickListener(
                                 () -> CarToast.makeText(
-                                        getCarContext(),
-                                        "Clicked second item",
-                                        LENGTH_SHORT)
+                                                getCarContext(),
+                                                getCarContext()
+                                                        .getString(R.string.second_item_toast_msg),
+                                                LENGTH_SHORT)
                                         .show())
                         .build();
             case 2:
@@ -110,15 +111,19 @@
                 // unchecked state.
                 return new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mIcon).build(), GridItem.IMAGE_TYPE_ICON)
-                        .setTitle("Third Item")
-                        .setText(mThirdItemToggleState ? "Checked" : "Unchecked")
+                        .setTitle(getCarContext().getString(R.string.third_item))
+                        .setText(mThirdItemToggleState
+                                ? getCarContext().getString(R.string.checked_action_title)
+                                : getCarContext().getString(R.string.unchecked_action_title))
                         .setOnClickListener(
                                 () -> {
                                     mThirdItemToggleState = !mThirdItemToggleState;
                                     CarToast.makeText(
-                                            getCarContext(),
-                                            "Third item checked: " + mThirdItemToggleState,
-                                            LENGTH_SHORT)
+                                                    getCarContext(),
+                                                    getCarContext().getString(
+                                                            R.string.third_item_checked_toast_msg)
+                                                            + ": " + mThirdItemToggleState,
+                                                    LENGTH_SHORT)
                                             .show();
                                     invalidate();
                                 })
@@ -129,15 +134,19 @@
                 // update.
                 if (mIsFourthItemLoading) {
                     return new GridItem.Builder()
-                            .setTitle("Fourth")
-                            .setText(mFourthItemToggleState ? "On" : "Off")
+                            .setTitle(getCarContext().getString(R.string.fourth_item))
+                            .setText(mFourthItemToggleState
+                                    ? getCarContext().getString(R.string.on_action_title)
+                                    : getCarContext().getString(R.string.off_action_title))
                             .setLoading(true)
                             .build();
                 } else {
                     return new GridItem.Builder()
                             .setImage(new CarIcon.Builder(mImage).build())
-                            .setTitle("Fourth")
-                            .setText(mFourthItemToggleState ? "On" : "Off")
+                            .setTitle(getCarContext().getString(R.string.fourth_item))
+                            .setText(mFourthItemToggleState
+                                    ? getCarContext().getString(R.string.on_action_title)
+                                    : getCarContext().getString(R.string.off_action_title))
                             .setOnClickListener(this::triggerFourthItemLoading)
                             .build();
                 }
@@ -146,14 +155,17 @@
                 // state.
                 return new GridItem.Builder()
                         .setImage(new CarIcon.Builder(mImage).build(), GridItem.IMAGE_TYPE_LARGE)
-                        .setTitle("Fifth Item has a long title set")
+                        .setTitle(getCarContext().getString(R.string.fifth_item))
                         .setOnClickListener(
                                 () -> {
                                     mFifthItemToggleState = !mFifthItemToggleState;
                                     CarToast.makeText(
-                                            getCarContext(),
-                                            "Fifth item checked: " + mFifthItemToggleState,
-                                            LENGTH_SHORT)
+                                                    getCarContext(),
+                                                    getCarContext().getString(
+                                                            R.string.fifth_item_checked_toast_msg)
+                                                            + ": "
+                                                            + mFifthItemToggleState,
+                                                    LENGTH_SHORT)
                                             .show();
                                     invalidate();
                                 })
@@ -165,15 +177,15 @@
                         new GridItem.Builder()
                                 .setImage(new CarIcon.Builder(mIcon).build(),
                                         GridItem.IMAGE_TYPE_ICON)
-                                .setTitle("Sixth Item has a long title set")
-                                .setText("Sixth Item has a long text set")
+                                .setTitle(getCarContext().getString(R.string.sixth_item))
+                                .setText(getCarContext().getString(R.string.sixth_item))
                                 .setOnClickListener(
-                                        () ->
-                                                CarToast.makeText(
+                                        () -> CarToast.makeText(
                                                         getCarContext(),
-                                                        "Clicked sixth item",
+                                                        getCarContext().getString(
+                                                                R.string.sixth_item_toast_msg),
                                                         LENGTH_SHORT)
-                                                        .show())
+                                                .show())
                                 .build();
             default:
                 String titleText = (index + 1) + "th item";
@@ -186,9 +198,9 @@
                         .setOnClickListener(
                                 () ->
                                         CarToast.makeText(
-                                                getCarContext(),
-                                                toastText,
-                                                LENGTH_SHORT)
+                                                        getCarContext(),
+                                                        toastText,
+                                                        LENGTH_SHORT)
                                                 .show())
                         .build();
         }
@@ -211,23 +223,23 @@
             gridItemListBuilder.addItem(createGridItem(i));
         }
 
+        Action settings = new Action.Builder()
+                .setTitle(getCarContext().getString(
+                        R.string.settings_action_title))
+                .setOnClickListener(
+                        () -> CarToast.makeText(
+                                        getCarContext(),
+                                        getCarContext().getString(R.string.settings_toast_msg),
+                                        LENGTH_SHORT)
+                                .show())
+                .build();
         return new GridTemplate.Builder()
                 .setHeaderAction(Action.APP_ICON)
                 .setSingleList(gridItemListBuilder.build())
-                .setTitle("Grid Template Demo")
+                .setTitle(getCarContext().getString(R.string.grid_template_demo_title))
                 .setActionStrip(
                         new ActionStrip.Builder()
-                                .addAction(
-                                        new Action.Builder()
-                                                .setTitle("Settings")
-                                                .setOnClickListener(
-                                                        () ->
-                                                                CarToast.makeText(
-                                                                        getCarContext(),
-                                                                        "Clicked Settings",
-                                                                        LENGTH_SHORT)
-                                                                        .show())
-                                                .build())
+                                .addAction(settings)
                                 .build())
                 .setHeaderAction(BACK)
                 .build();
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/ListTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/ListTemplateDemoScreen.java
index b3a6c76..45d7c52 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/ListTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/ListTemplateDemoScreen.java
@@ -32,6 +32,7 @@
 import androidx.car.app.model.ParkedOnlyOnClickListener;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.versioning.CarAppApiLevels;
 import androidx.lifecycle.DefaultLifecycleObserver;
 
@@ -55,9 +56,10 @@
         listBuilder.addItem(
                 new Row.Builder()
                         .setOnClickListener(
-                                ParkedOnlyOnClickListener.create(() -> onClick("Parked action")))
-                        .setTitle("Parked Only Title")
-                        .addText("More Parked only text.")
+                                ParkedOnlyOnClickListener.create(() -> onClick(
+                                        getCarContext().getString(R.string.parked_toast_msg))))
+                        .setTitle(getCarContext().getString(R.string.parked_only_title))
+                        .addText(getCarContext().getString(R.string.parked_only_text))
                         .build());
 
         // Some hosts may allow more items in the list than others, so create more.
@@ -69,7 +71,7 @@
 
             for (int i = 2; i <= listLimit; ++i) {
                 // For row text, set text variants that fit best in different screen sizes.
-                String secondTextStr = "Second line of text";
+                String secondTextStr = getCarContext().getString(R.string.second_line_text);
                 CarText secondText =
                         new CarText.Builder(
                                 "================= " + secondTextStr + " ================")
@@ -77,34 +79,38 @@
                                         + " ----------------------")
                                 .addVariant(secondTextStr)
                                 .build();
-                final String onClickText = "Clicked row: " + i;
+                final String onClickText = getCarContext().getString(R.string.clicked_row_prefix)
+                        + ": " + i;
                 listBuilder.addItem(
                         new Row.Builder()
                                 .setOnClickListener(() -> onClick(onClickText))
-                                .setTitle("Title " + i)
-                                .addText("First line of text")
+                                .setTitle(
+                                        getCarContext().getString(R.string.title_prefix) + " " + i)
+                                .addText(getCarContext().getString(R.string.first_line_text))
                                 .addText(secondText)
                                 .build());
             }
         }
 
+        Action settings = new Action.Builder()
+                .setTitle(getCarContext().getString(
+                        R.string.settings_action_title))
+                .setOnClickListener(
+                        () -> CarToast.makeText(
+                                        getCarContext(),
+                                        getCarContext().getString(
+                                                R.string.settings_toast_msg),
+                                        LENGTH_LONG)
+                                .show())
+                .build();
+
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("List Template Demo")
+                .setTitle(getCarContext().getString(R.string.list_template_demo_title))
                 .setHeaderAction(BACK)
                 .setActionStrip(
                         new ActionStrip.Builder()
-                                .addAction(
-                                        new Action.Builder()
-                                                .setTitle("Settings")
-                                                .setOnClickListener(
-                                                        () ->
-                                                                CarToast.makeText(
-                                                                        getCarContext(),
-                                                                        "Clicked Settings",
-                                                                        LENGTH_LONG)
-                                                                        .show())
-                                                .build())
+                                .addAction(settings)
                                 .build())
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/LongMessageTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/LongMessageTemplateDemoScreen.java
index 3249e49..b9d310c 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/LongMessageTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/LongMessageTemplateDemoScreen.java
@@ -31,53 +31,11 @@
 import androidx.car.app.model.MessageTemplate;
 import androidx.car.app.model.ParkedOnlyOnClickListener;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.versioning.CarAppApiLevels;
 
 /** A screen that demonstrates the long message template. */
 public class LongMessageTemplateDemoScreen extends Screen {
-    private static final String TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
-            + "Aliquam laoreet ac metus eu commodo. Sed a congue diam, sed dictum lectus. Nam nec"
-            + " tristique dolor, quis sodales arcu. Etiam at metus eu nulla auctor varius. "
-            + "Integer dolor lorem, placerat sit amet lacus in, imperdiet semper dui. Vestibulum "
-            + "ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; "
-            + "Quisque gravida fermentum egestas.\n"
-            + "\n"
-            + "Ut ut sodales mi. Aenean porta vel ipsum sed lacinia. Morbi odio ipsum, hendrerit "
-            + "eu est et, sollicitudin finibus diam. Nunc sit amet felis elit. Orci varius "
-            + "natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed "
-            + "vestibulum, tellus a rutrum auctor, diam arcu vestibulum purus, nec mollis ligula "
-            + "nisi in nisi. Donec sem tortor, pharetra sed fermentum sit amet, ullamcorper nec "
-            + "sapien. Aliquam risus arcu, porttitor eu dui nec, vulputate tempus libero. "
-            + "Curabitur sit amet tristique orci. Suspendisse et odio tempus, tempus turpis quis,"
-            + " euismod est.\n"
-            + "\n"
-            + "Vestibulum mauris ante, luctus viverra nisi eget, blandit facilisis nulla. "
-            + "Phasellus ex lorem, semper in vestibulum nec, aliquet vel elit. Aliquam vitae "
-            + "ligula nec enim dictum lobortis. Sed varius turpis quis nisi tempus varius. Sed "
-            + "non sollicitudin magna, at mattis tortor. Curabitur quis ligula eget lorem mattis "
-            + "tincidunt et in sapien. Curabitur a elit nisi. Aliquam ex arcu, hendrerit eget "
-            + "turpis vitae, bibendum vulputate nibh. Fusce vitae ex aliquet, tristique magna eu,"
-            + " vulputate dui. Aenean tempor viverra tortor non pharetra. Pellentesque convallis "
-            + "nec risus a auctor. Praesent non sem non eros tincidunt ullamcorper efficitur non "
-            + "lacus.\n"
-            + "\n"
-            + "Suspendisse accumsan ultricies egestas. Aenean leo ligula, congue ac erat eu, "
-            + "lobortis ultricies lorem. Nulla finibus, arcu sed tincidunt lobortis, magna justo "
-            + "rutrum ligula, et mattis felis turpis vel ex. Morbi ac auctor ex, at bibendum sem."
-            + " Vestibulum a tortor iaculis, viverra felis vitae, lobortis est. Duis sit amet "
-            + "condimentum sem. Ut molestie, dolor pretium imperdiet maximus, enim orci porta "
-            + "quam, id gravida enim nunc vitae lacus. Pellentesque habitant morbi tristique "
-            + "senectus et netus et malesuada fames ac turpis egestas. Nullam vel justo eu risus "
-            + "lobortis dignissim sit amet ullamcorper nulla. Donec finibus cursus purus "
-            + "porttitor pellentesque.\n"
-            + "\n"
-            + "Donec at vehicula ante. Suspendisse rutrum nisl quis metus faucibus lacinia. "
-            + "Vestibulum eros sapien, eleifend nec accumsan a, interdum sed nisi. Aenean posuere"
-            + " ultrices lorem non pharetra. Nulla non porta ligula. Maecenas at elit diam. "
-            + "Nullam gravida augue et semper eleifend. Fusce venenatis ac arcu et luctus. Mauris"
-            + " ultricies urna non dui interdum, vel hendrerit est aliquam. Fusce id dictum leo, "
-            + "fringilla egestas ipsum.";
-
     protected LongMessageTemplateDemoScreen(@NonNull CarContext carContext) {
         super(carContext);
     }
@@ -86,8 +44,10 @@
     @Override
     public Template onGetTemplate() {
         if (getCarContext().getCarAppApiLevel() < CarAppApiLevels.LEVEL_2) {
-            return new MessageTemplate.Builder("Your host doesn't support Long Message template")
-                    .setTitle("Incompatible host")
+            return new MessageTemplate.Builder(
+                    getCarContext().getString(R.string.long_msg_template_not_supported_text))
+                    .setTitle(getCarContext().getString(
+                            R.string.long_msg_template_not_supported_title))
                     .setHeaderAction(Action.BACK)
                     .build();
         }
@@ -98,36 +58,38 @@
                             getScreenManager().pop();
                             CarToast.makeText(
                                     getCarContext(),
-                                    "Clicked primary button",
+                                    getCarContext().getString(R.string.primary_action_title),
                                     LENGTH_LONG
                             ).show();
                         }))
-                .setTitle("Accept");
+                .setTitle(getCarContext().getString(R.string.accept_action_title));
         if (getCarContext().getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
             primaryActionBuilder.setFlags(FLAG_PRIMARY);
         }
 
-        return new LongMessageTemplate.Builder(TEXT)
-                .setTitle("Long Message Template Demo")
+        return new LongMessageTemplate.Builder(
+                getCarContext().getString(R.string.long_msg_template_text))
+                .setTitle(getCarContext().getString(R.string.long_msg_template_demo_title))
                 .setHeaderAction(BACK)
                 .addAction(primaryActionBuilder.build())
                 .addAction(new Action.Builder()
                         .setBackgroundColor(CarColor.RED)
                         .setOnClickListener(
                                 ParkedOnlyOnClickListener.create(() -> getScreenManager().pop()))
-                        .setTitle("Reject")
+                        .setTitle(getCarContext().getString(R.string.reject_action_title))
                         .build())
                 .setActionStrip(new ActionStrip.Builder()
                         .addAction(new Action.Builder()
-                            .setTitle("More")
-                            .setOnClickListener(
-                                    () ->
-                                            CarToast.makeText(
-                                                    getCarContext(),
-                                                    "Clicked More",
-                                                    LENGTH_LONG)
-                                                    .show())
-                            .build())
+                                .setTitle(getCarContext().getString(R.string.more_action_title))
+                                .setOnClickListener(
+                                        () ->
+                                                CarToast.makeText(
+                                                                getCarContext(),
+                                                                getCarContext().getString(
+                                                                        R.string.more_toast_msg),
+                                                                LENGTH_LONG)
+                                                        .show())
+                                .build())
                         .build())
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/MessageTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/MessageTemplateDemoScreen.java
index a8eb3a7..d2df37f 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/MessageTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/MessageTemplateDemoScreen.java
@@ -48,17 +48,30 @@
                 .setOnClickListener(() -> {
                     CarToast.makeText(
                             getCarContext(),
-                            "Clicked primary button",
+                            getCarContext().getString(R.string.primary_action_title),
                             LENGTH_LONG
                     ).show();
                 })
-                .setTitle("OK");
+                .setTitle(getCarContext().getString(R.string.ok_action_title));
         if (getCarContext().getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
             primaryActionBuilder.setFlags(FLAG_PRIMARY);
         }
 
-        return new MessageTemplate.Builder("Message goes here.\nMore text on second line.")
-                .setTitle("Message Template Demo")
+        Action settings = new Action.Builder()
+                .setTitle(getCarContext().getString(
+                        R.string.settings_action_title))
+                .setOnClickListener(
+                        () -> CarToast.makeText(
+                                        getCarContext(),
+                                        getCarContext().getString(
+                                                R.string.settings_toast_msg),
+                                        LENGTH_LONG)
+                                .show())
+                .build();
+
+        return new MessageTemplate.Builder(
+                getCarContext().getString(R.string.msg_template_demo_text))
+                .setTitle(getCarContext().getString(R.string.msg_template_demo_title))
                 .setIcon(
                         new CarIcon.Builder(
                                 IconCompat.createWithResource(
@@ -71,7 +84,7 @@
                 .addAction(
                         new Action.Builder()
                                 .setBackgroundColor(CarColor.RED)
-                                .setTitle("Throw")
+                                .setTitle(getCarContext().getString(R.string.throw_action_title))
                                 .setOnClickListener(
                                         () -> {
                                             throw new RuntimeException("Error");
@@ -80,17 +93,7 @@
 
                 .setActionStrip(
                         new ActionStrip.Builder()
-                                .addAction(
-                                        new Action.Builder()
-                                                .setTitle("Settings")
-                                                .setOnClickListener(
-                                                        () ->
-                                                                CarToast.makeText(
-                                                                        getCarContext(),
-                                                                        "Clicked Settings",
-                                                                        LENGTH_LONG)
-                                                                        .show())
-                                                .build())
+                                .addAction(settings)
                                 .build())
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PaneTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PaneTemplateDemoScreen.java
index 8a3358c..ea98c9f 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PaneTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PaneTemplateDemoScreen.java
@@ -77,19 +77,19 @@
             case 0:
                 // Row with a large image.
                 return new Row.Builder()
-                        .setTitle("Row with a large image and long text long text long text long "
-                                + "text long text")
-                        .addText("Text text text")
-                        .addText("Text text text")
+                        .setTitle(getCarContext().getString(R.string.first_row_title))
+                        .addText(getCarContext().getString(R.string.first_row_text))
+                        .addText(getCarContext().getString(R.string.first_row_text))
                         .setImage(new CarIcon.Builder(mRowLargeIcon).build())
                         .build();
             default:
                 return new Row.Builder()
-                        .setTitle("Row title " + (index + 1))
-                        .addText("Row text 1")
-                        .addText("Row text 2")
+                        .setTitle(
+                                getCarContext().getString(R.string.other_row_title_prefix) + (index
+                                        + 1))
+                        .addText(getCarContext().getString(R.string.other_row_text))
+                        .addText(getCarContext().getString(R.string.other_row_text))
                         .build();
-
         }
     }
 
@@ -114,13 +114,13 @@
         paneBuilder.setImage(new CarIcon.Builder(mPaneImage).build());
 
         Action.Builder primaryActionBuilder = new Action.Builder()
-                .setTitle("Search")
+                .setTitle(getCarContext().getString(R.string.search_action_title))
                 .setBackgroundColor(CarColor.BLUE)
                 .setOnClickListener(
                         () -> CarToast.makeText(
-                                getCarContext(),
-                                "Search/Primary button pressed",
-                                LENGTH_SHORT)
+                                        getCarContext(),
+                                        getCarContext().getString(R.string.search_toast_msg),
+                                        LENGTH_SHORT)
                                 .show());
         if (getCarContext().getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
             primaryActionBuilder.setFlags(FLAG_PRIMARY);
@@ -130,12 +130,13 @@
                 .addAction(primaryActionBuilder.build())
                 .addAction(
                         new Action.Builder()
-                                .setTitle("Options")
+                                .setTitle(getCarContext().getString(R.string.options_action_title))
                                 .setOnClickListener(
                                         () -> CarToast.makeText(
-                                                getCarContext(),
-                                                "Options button pressed",
-                                                LENGTH_SHORT)
+                                                        getCarContext(),
+                                                        getCarContext().getString(
+                                                                R.string.options_toast_msg),
+                                                        LENGTH_SHORT)
                                                 .show())
                                 .build());
 
@@ -143,23 +144,23 @@
                 .setHeaderAction(Action.BACK)
                 .setActionStrip(
                         new ActionStrip.Builder()
-                                .addAction(
-                                        new Action.Builder()
-                                                .setTitle("Commute")
-                                                .setIcon(
-                                                        new CarIcon.Builder(mCommuteIcon)
-                                                                .setTint(CarColor.BLUE)
-                                                                .build())
-                                                .setOnClickListener(
-                                                        () -> CarToast.makeText(
+                                .addAction(new Action.Builder()
+                                        .setTitle(getCarContext().getString(
+                                                R.string.commute_action_title))
+                                        .setIcon(
+                                                new CarIcon.Builder(mCommuteIcon)
+                                                        .setTint(CarColor.BLUE)
+                                                        .build())
+                                        .setOnClickListener(
+                                                () -> CarToast.makeText(
                                                                 getCarContext(),
-                                                                "Commute button"
-                                                                        + " pressed",
+                                                                getCarContext().getString(
+                                                                        R.string.commute_toast_msg),
                                                                 LENGTH_SHORT)
-                                                                .show())
-                                                .build())
+                                                        .show())
+                                        .build())
                                 .build())
-                .setTitle("Pane Template Demo")
+                .setTitle(getCarContext().getString(R.string.pane_template_demo_title))
                 .build();
     }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateBrowseDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateBrowseDemoScreen.java
index 250b970..1f595be 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateBrowseDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateBrowseDemoScreen.java
@@ -36,6 +36,7 @@
 import androidx.car.app.model.PlaceListMapTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.core.location.LocationListenerCompat;
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
@@ -88,7 +89,7 @@
                             mLocationUpdateHandlerThread.getLooper());
                 } else {
                     CarToast.makeText(carContext,
-                            "Grant location Permission to see current location",
+                            getCarContext().getString(R.string.grant_location_permission_toast_msg),
                             CarToast.LENGTH_LONG).show();
                 }
             }
@@ -108,14 +109,14 @@
         PlaceListMapTemplate.Builder builder = new PlaceListMapTemplate.Builder()
                 .setItemList(new ItemList.Builder()
                         .addItem(new Row.Builder()
-                                .setTitle("Browse Places")
+                                .setTitle(getCarContext().getString(R.string.browse_places_title))
                                 .setBrowsable(true)
                                 .setOnClickListener(
                                         () -> getScreenManager().push(
                                                 new PlaceListTemplateDemoScreen(
                                                         getCarContext()))).build())
                         .build())
-                .setTitle("Place List Template Demo")
+                .setTitle(getCarContext().getString(R.string.place_list_template_demo_title))
                 .setHeaderAction(Action.BACK)
                 .setCurrentLocationEnabled(mHasPermissionLocation);
 
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java
index 67bf423..a64bf4a 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java
@@ -22,6 +22,7 @@
 import androidx.car.app.model.Action;
 import androidx.car.app.model.PlaceListMapTemplate;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 import androidx.car.app.sample.showcase.common.common.SamplePlaces;
 
 /** Creates a screen using the {@link PlaceListMapTemplate} */
@@ -38,7 +39,7 @@
     public Template onGetTemplate() {
         return new PlaceListMapTemplate.Builder()
                 .setItemList(mPlaces.getPlaceList())
-                .setTitle("Place List Template Demo")
+                .setTitle(getCarContext().getString(R.string.place_list_template_demo_title))
                 .setHeaderAction(Action.BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SearchTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SearchTemplateDemoScreen.java
index 6f5a9e1..81e729d 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SearchTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SearchTemplateDemoScreen.java
@@ -29,6 +29,7 @@
 import androidx.car.app.model.SearchTemplate;
 import androidx.car.app.model.SearchTemplate.SearchCallback;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** A screen that demonstrates the search template. */
 public class SearchTemplateDemoScreen extends Screen {
@@ -44,9 +45,9 @@
         for (int i = 1; i <= 6; ++i) {
             listBuilder.addItem(
                     new Row.Builder()
-                            .setTitle("Title " + i)
-                            .addText("First line of text")
-                            .addText("Second line of text")
+                            .setTitle(getCarContext().getString(R.string.title_prefix) + " " + i)
+                            .addText(getCarContext().getString(R.string.first_line_text))
+                            .addText(getCarContext().getString(R.string.second_line_text))
                             .build());
         }
 
@@ -64,19 +65,19 @@
         ActionStrip actionStrip = new ActionStrip.Builder()
                 .addAction(
                         new Action.Builder()
-                                .setTitle("Settings")
+                                .setTitle(getCarContext().getString(R.string.settings_action_title))
                                 .setOnClickListener(
-                                        () ->
-                                                CarToast.makeText(
+                                        () -> CarToast.makeText(
                                                         getCarContext(),
-                                                        "Clicked Settings",
+                                                        getCarContext().getString(
+                                                                R.string.settings_toast_msg),
                                                         LENGTH_LONG)
-                                                        .show())
+                                                .show())
                                 .build())
                 .build();
 
         return new SearchTemplate.Builder(searchListener)
-                .setSearchHint("Search here")
+                .setSearchHint(getCarContext().getString(R.string.search_hint))
                 .setHeaderAction(Action.BACK)
                 .setShowKeyboardByDefault(false)
                 .setItemList(listBuilder.build())
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
index ceebedb..6722f14 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
@@ -45,53 +45,19 @@
 
 /** A screen that demonstrates the sign-in template. */
 public class SignInTemplateDemoScreen extends Screen {
-    private enum State {
-        USERNAME,
-        PASSWORD,
-        PIN,
-        PROVIDER,
-        QR_CODE,
-        SIGNED_IN,
-    }
-
     private static final String EMAIL_REGEXP = "^(.+)@(.+)$";
     private static final String EXPECTED_PASSWORD = "password";
     private static final int MIN_USERNAME_LENGTH = 5;
-
+    private final CharSequence mAdditionalText;
+    private final Action mProviderSignInAction;
+    private final Action mPinSignInAction;
+    private final Action mQRCodeSignInAction;
     // package private to avoid synthetic accessor
     State mState = State.USERNAME;
     String mLastErrorMessage = ""; // last displayed error message
     String mErrorMessage = "";
     String mUsername = null;
 
-    private final CharSequence mAdditionalText = Utils.clickable("Please review our terms of "
-                    + "service", 18, 16,
-            () -> getScreenManager().push(new LongMessageTemplateDemoScreen(getCarContext())));
-
-    private final Action mProviderSignInAction = new Action.Builder()
-            .setTitle("Google sign-in")
-            .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
-                mState = State.PROVIDER;
-                invalidate();
-            }))
-            .build();
-
-    private final Action mPinSignInAction = new Action.Builder()
-            .setTitle("Use PIN")
-            .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
-                mState = State.PIN;
-                invalidate();
-            }))
-            .build();
-
-    private final Action mQRCodeSignInAction = new Action.Builder()
-            .setTitle("QR Code")
-            .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
-                mState = State.QR_CODE;
-                invalidate();
-            }))
-            .build();
-
     public SignInTemplateDemoScreen(@NonNull CarContext carContext) {
         super(carContext);
 
@@ -110,14 +76,44 @@
             }
         };
         carContext.getOnBackPressedDispatcher().addCallback(this, callback);
+
+        mAdditionalText = Utils.clickable(getCarContext().getString(R.string.additional_text), 18,
+                16,
+                () -> getScreenManager().push(new LongMessageTemplateDemoScreen(getCarContext())));
+
+        mProviderSignInAction = new Action.Builder()
+                .setTitle(getCarContext().getString(R.string.google_sign_in))
+                .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
+                    mState = State.PROVIDER;
+                    invalidate();
+                }))
+                .build();
+
+        mPinSignInAction = new Action.Builder()
+                .setTitle(getCarContext().getString(R.string.use_pin))
+                .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
+                    mState = State.PIN;
+                    invalidate();
+                }))
+                .build();
+
+        mQRCodeSignInAction = new Action.Builder()
+                .setTitle(getCarContext().getString(R.string.qr_code))
+                .setOnClickListener(ParkedOnlyOnClickListener.create(() -> {
+                    mState = State.QR_CODE;
+                    invalidate();
+                }))
+                .build();
     }
 
     @NonNull
     @Override
     public Template onGetTemplate() {
         if (getCarContext().getCarAppApiLevel() < CarAppApiLevels.LEVEL_2) {
-            return new MessageTemplate.Builder("Your host doesn't support Sign In template")
-                    .setTitle("Incompatible host")
+            return new MessageTemplate.Builder(
+                    getCarContext().getString(R.string.sign_in_template_not_supported_text))
+                    .setTitle(getCarContext().getString(
+                            R.string.sign_in_template_not_supported_title))
                     .setHeaderAction(Action.BACK)
                     .build();
         }
@@ -168,7 +164,7 @@
         };
 
         InputSignInMethod.Builder builder = new InputSignInMethod.Builder(listener)
-                .setHint("Email")
+                .setHint(getCarContext().getString(R.string.email_hint))
                 .setKeyboardType(InputSignInMethod.KEYBOARD_EMAIL);
         if (mErrorMessage != null) {
             builder.setErrorMessage(mErrorMessage);
@@ -183,8 +179,8 @@
                 .addAction(mProviderSignInAction)
                 .addAction(getCarContext().getCarAppApiLevel() > CarAppApiLevels.LEVEL_3
                         ? mQRCodeSignInAction : mPinSignInAction)
-                .setTitle("Sign in")
-                .setInstructions("Enter your credentials")
+                .setTitle(getCarContext().getString(R.string.sign_in_title))
+                .setInstructions(getCarContext().getString(R.string.sign_in_instructions))
                 .setHeaderAction(Action.BACK)
                 .setAdditionalText(mAdditionalText)
                 .build();
@@ -196,10 +192,10 @@
      */
     String validateUsername() {
         if (mUsername == null || mUsername.length() < MIN_USERNAME_LENGTH) {
-            return "User name must be at least " + MIN_USERNAME_LENGTH + " characters "
-                    + "long";
+            return getCarContext().getString(R.string.invalid_length_error_msg,
+                    Integer.toString(MIN_USERNAME_LENGTH));
         } else if (!mUsername.matches(EMAIL_REGEXP)) {
-            return "User name must be a valid email address";
+            return getCarContext().getString(R.string.invalid_email_error_msg);
         } else {
             return "";
         }
@@ -228,7 +224,7 @@
             public void onInputSubmitted(@NonNull String text) {
                 // Mocked password validation
                 if (!EXPECTED_PASSWORD.equals(text)) {
-                    mErrorMessage = "Invalid password";
+                    mErrorMessage = getCarContext().getString(R.string.invalid_password_error_msg);
                 } else {
                     mErrorMessage = "";
                     mState = State.SIGNED_IN;
@@ -237,7 +233,7 @@
             }
         };
         InputSignInMethod.Builder builder = new InputSignInMethod.Builder(callback)
-                .setHint("Password")
+                .setHint(getCarContext().getString(R.string.password_hint))
                 .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD);
         if (mErrorMessage != null) {
             builder.setErrorMessage(mErrorMessage);
@@ -248,8 +244,10 @@
                 .addAction(mProviderSignInAction)
                 .addAction(getCarContext().getCarAppApiLevel() > CarAppApiLevels.LEVEL_3
                         ? mQRCodeSignInAction : mPinSignInAction)
-                .setTitle("Sign in")
-                .setInstructions("Username: " + mUsername)
+                .setTitle(getCarContext().getString(R.string.sign_in_title))
+                .setInstructions(
+                        getCarContext().getString(R.string.password_sign_in_instruction_prefix)
+                                + ": " + mUsername)
                 .setHeaderAction(Action.BACK)
                 .setAdditionalText(mAdditionalText)
                 .build();
@@ -258,8 +256,8 @@
     private Template getPinSignInTemplate() {
         PinSignInMethod pinSignInMethod = new PinSignInMethod("123456789ABC");
         return new SignInTemplate.Builder(pinSignInMethod)
-                .setTitle("Sign in")
-                .setInstructions("Type this PIN in your phone")
+                .setTitle(getCarContext().getString(R.string.sign_in_title))
+                .setInstructions(getCarContext().getString(R.string.pin_sign_in_instruction))
                 .setHeaderAction(Action.BACK)
                 .setAdditionalText(mAdditionalText)
                 .build();
@@ -269,7 +267,7 @@
         QRCodeSignInMethod qrCodeSignInMethod = new QRCodeSignInMethod(Uri.parse("https://www"
                 + ".youtube.com/watch?v=dQw4w9WgXcQ"));
         return new SignInTemplate.Builder(qrCodeSignInMethod)
-                .setTitle("Scan QR Code to sign in")
+                .setTitle(getCarContext().getString(R.string.qr_code_sign_in_title))
                 .setHeaderAction(Action.BACK)
                 .setAdditionalText(mAdditionalText)
                 .addAction(mPinSignInAction)
@@ -284,7 +282,8 @@
 
         ProviderSignInMethod providerSignInMethod = new ProviderSignInMethod(
                 new Action.Builder()
-                        .setTitle(Utils.colorize("Sign in with Google",
+                        .setTitle(Utils.colorize(
+                                getCarContext().getString(R.string.sign_in_with_google_title),
                                 CarColor.createCustom(Color.BLACK, Color.BLACK), 0, 19))
                         .setBackgroundColor(CarColor.createCustom(Color.WHITE, Color.WHITE))
                         .setIcon(new CarIcon.Builder(providerIcon)
@@ -294,8 +293,8 @@
                                 this::performSignInWithGoogleFlow)).build());
 
         return new SignInTemplate.Builder(providerSignInMethod)
-                .setTitle("Sign in")
-                .setInstructions("Use this button to complete your Google sign-in")
+                .setTitle(getCarContext().getString(R.string.sign_in_title))
+                .setInstructions(getCarContext().getString(R.string.provider_sign_in_instruction))
                 .setHeaderAction(Action.BACK)
                 .setAdditionalText(mAdditionalText)
                 .build();
@@ -324,16 +323,19 @@
 //                        .setClass(getCarContext(), SignInWithGoogleActivity.class)
 //                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
 //                        .putExtras(extras));
-        CarToast.makeText(getCarContext(), "Sign-in with Google starts here", LENGTH_LONG)
+        CarToast.makeText(getCarContext(),
+                        getCarContext().getString(R.string.sign_in_with_google_toast_msg),
+                        LENGTH_LONG)
                 .show();
     }
 
     private MessageTemplate getSignInCompletedMessageTemplate() {
-        return new MessageTemplate.Builder("You are signed in!")
-                .setTitle("Sign in completed")
+        return new MessageTemplate.Builder(
+                getCarContext().getString(R.string.sign_in_complete_text))
+                .setTitle(getCarContext().getString(R.string.sign_in_complete_title))
                 .setHeaderAction(Action.BACK)
                 .addAction(new Action.Builder()
-                        .setTitle("Sign out")
+                        .setTitle(getCarContext().getString(R.string.sign_out_action_title))
                         .setOnClickListener(() -> {
                             mState = State.USERNAME;
                             invalidate();
@@ -342,4 +344,13 @@
                 .build();
     }
 
+    private enum State {
+        USERNAME,
+        PASSWORD,
+        PIN,
+        PROVIDER,
+        QR_CODE,
+        SIGNED_IN,
+    }
+
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/ContentProviderIconsDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/ContentProviderIconsDemoScreen.java
index 82c327c..cc9a480 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/ContentProviderIconsDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/ContentProviderIconsDemoScreen.java
@@ -35,13 +35,12 @@
 
 /** Creates a screen that demonstrate the image loading in the library using a content provider. */
 public final class ContentProviderIconsDemoScreen extends Screen {
-    @Nullable
-    private final String mHostPackageName;
-
     private static final int[] ICON_DRAWABLES = {
             R.drawable.arrow_right_turn, R.drawable.arrow_straight, R.drawable.ic_i5,
             R.drawable.ic_520
     };
+    @Nullable
+    private final String mHostPackageName;
 
     public ContentProviderIconsDemoScreen(@NonNull CarContext carContext) {
         super(carContext);
@@ -58,7 +57,8 @@
         String hostPackageName = mHostPackageName;
         if (hostPackageName == null) {
             // Cannot get the host package name, show an error message.
-            listBuilder.setNoItemsMessage("Images cannot be displayed for an unknown host");
+            listBuilder.setNoItemsMessage(
+                    getCarContext().getString(R.string.images_unknown_host_error));
         } else {
             for (int i = 0; i < ICON_DRAWABLES.length; i++) {
                 int resId = ICON_DRAWABLES[i];
@@ -70,7 +70,9 @@
                                         new CarIcon.Builder(
                                                 IconCompat.createWithContentUri(uri))
                                                 .build())
-                                .setTitle("Icon " + i)
+                                .setTitle(
+                                        getCarContext().getString(R.string.icon_title_prefix) + " "
+                                                + i)
                                 .build());
             }
         }
@@ -78,7 +80,7 @@
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Content Provider Icons Demo")
+                .setTitle(getCarContext().getString(R.string.content_provider_icons_demo_title))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/IconsDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/IconsDemoScreen.java
index d3802d9..dbd49b9 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/IconsDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/IconsDemoScreen.java
@@ -46,7 +46,7 @@
         listBuilder.addItem(
                 new Row.Builder()
                         .setImage(new CarIcon.Builder(CarIcon.APP_ICON).build())
-                        .setTitle("The app icon")
+                        .setTitle(getCarContext().getString(R.string.app_icon_title))
                         .build());
 
         listBuilder.addItem(
@@ -58,7 +58,7 @@
                                                 R.drawable.ic_fastfood_white_48dp))
                                         .build(),
                                 Row.IMAGE_TYPE_ICON)
-                        .setTitle("A vector drawable, without a tint")
+                        .setTitle(getCarContext().getString(R.string.vector_no_tint_title))
                         .build());
 
         listBuilder.addItem(
@@ -70,7 +70,7 @@
                                                 R.drawable.ic_fastfood_white_48dp))
                                         .setTint(GREEN)
                                         .build())
-                        .setTitle("A vector drawable, with a tint")
+                        .setTitle(getCarContext().getString(R.string.vector_with_tint_title))
                         .build());
 
         listBuilder.addItem(
@@ -81,7 +81,8 @@
                                                 getCarContext(),
                                                 R.drawable.ic_themed_icon_48dp))
                                         .build())
-                        .setTitle("A vector drawable, with an app's theme attribute for its color")
+                        .setTitle(getCarContext()
+                                .getString(R.string.vector_with_app_theme_attr_title))
                         .build());
 
         listBuilder.addItem(
@@ -91,7 +92,7 @@
                                         IconCompat.createWithResource(
                                                 getCarContext(), R.drawable.banana))
                                         .build())
-                        .setTitle("A PNG, sent as a resource")
+                        .setTitle(getCarContext().getString(R.string.png_res_title))
                         .build());
 
         listBuilder.addItem(
@@ -103,12 +104,12 @@
                                                         getCarContext().getResources(),
                                                         R.drawable.banana)))
                                         .build())
-                        .setTitle("A PNG, sent as a bitmap")
+                        .setTitle(getCarContext().getString(R.string.png_bitmap_title))
                         .build());
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Icons Demo")
+                .setTitle(getCarContext().getString(R.string.icons_demo_title))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/RowDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/RowDemoScreen.java
index 9c074f3..643a8fb 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/RowDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/RowDemoScreen.java
@@ -44,21 +44,37 @@
         getLifecycle().addObserver(this);
     }
 
+    private static CharSequence getRatingsString(Double ratings) {
+        String s;
+        double r;
+        for (s = "", r = ratings; r > 0; --r) {
+            s += r < 1 ? HALF_STAR : FULL_STAR;
+        }
+        SpannableString ss = new SpannableString(s + " ratings: " + ratings);
+        if (!s.isEmpty()) {
+            Utils.colorize(ss, YELLOW, 0, s.length());
+        }
+        return ss;
+    }
+
     @NonNull
     @Override
     public Template onGetTemplate() {
         ItemList.Builder listBuilder = new ItemList.Builder();
 
-        listBuilder.addItem(new Row.Builder().setTitle("Just a title").build());
+        listBuilder.addItem(new Row.Builder()
+                .setTitle(getCarContext().getString(R.string.just_row_title))
+                .build());
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Title with app icon")
+                        .setTitle(getCarContext().getString(R.string.title_with_app_icon_row_title))
                         .setImage(CarIcon.APP_ICON)
                         .build());
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Title with resource ID image")
+                        .setTitle(getCarContext().getString(
+                                R.string.title_with_res_id_image_row_title))
                         .setImage(
                                 new CarIcon.Builder(
                                         IconCompat.createWithResource(
@@ -70,7 +86,8 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Title with SVG image")
+                        .setTitle(
+                                getCarContext().getString(R.string.title_with_svg_image_row_title))
                         .setImage(
                                 new CarIcon.Builder(
                                         IconCompat.createWithResource(
@@ -83,34 +100,24 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Title with multiple secondary text lines")
-                        .addText("Err and err and err again, but less and less and less.")
-                        .addText("- Piet Hein")
+                        .setTitle(getCarContext().getString(
+                                R.string.title_with_secondary_lines_row_title))
+                        .addText(getCarContext().getString(
+                                R.string.title_with_secondary_lines_row_text_1))
+                        .addText(getCarContext().getString(
+                                R.string.title_with_secondary_lines_row_text_2))
                         .build());
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Colored secondary text")
+                        .setTitle(getCarContext().getString(R.string.colored_secondary_row_title))
                         .addText(getRatingsString(3.5))
                         .build());
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Rows Demo")
+                .setTitle(getCarContext().getString(R.string.rows_demo_title))
                 .setHeaderAction(BACK)
                 .build();
     }
-
-    private static CharSequence getRatingsString(Double ratings) {
-        String s;
-        double r;
-        for (s = "", r = ratings; r > 0; --r) {
-            s += r < 1 ? HALF_STAR : FULL_STAR;
-        }
-        SpannableString ss = new SpannableString(s + " ratings: " + ratings);
-        if (!s.isEmpty()) {
-            Utils.colorize(ss, YELLOW, 0, s.length());
-        }
-        return ss;
-    }
 }
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/TextAndIconsDemosScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/TextAndIconsDemosScreen.java
index 028defe..39b81ba 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/TextAndIconsDemosScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/textandicons/TextAndIconsDemosScreen.java
@@ -25,6 +25,7 @@
 import androidx.car.app.model.ListTemplate;
 import androidx.car.app.model.Row;
 import androidx.car.app.model.Template;
+import androidx.car.app.sample.showcase.common.R;
 
 /** Creates a screen that shows different types of texts and icons. */
 public final class TextAndIconsDemosScreen extends Screen {
@@ -39,14 +40,15 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Icons Demo")
+                        .setTitle(getCarContext().getString(R.string.icons_demo_title))
                         .setOnClickListener(
                                 () -> getScreenManager().push(new IconsDemoScreen(getCarContext())))
                         .build());
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Content Provider Icons Demo")
+                        .setTitle(getCarContext().getString(
+                                R.string.content_provider_icons_demo_title))
                         .setOnClickListener(
                                 () ->
                                         getScreenManager()
@@ -57,14 +59,14 @@
 
         listBuilder.addItem(
                 new Row.Builder()
-                        .setTitle("Rows with Text and Icons Demo")
+                        .setTitle(getCarContext().getString(R.string.row_text_icons_demo_title))
                         .setOnClickListener(
                                 () -> getScreenManager().push(new RowDemoScreen(getCarContext())))
                         .build());
 
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
-                .setTitle("Text and Icons Demos")
+                .setTitle(getCarContext().getString(R.string.text_icons_demo_title))
                 .setHeaderAction(BACK)
                 .build();
     }
diff --git a/car/app/app-samples/showcase/common/src/main/res/values/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values/strings.xml
index 8a919bd..4b593a6 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values/strings.xml
@@ -16,4 +16,377 @@
 -->
 <resources>
   <string name="app_name" translatable="false">Showcase</string>
+
+  <!-- Action Titles -->
+  <string name="back_caps_action_title">BACK</string>
+  <string name="home_caps_action_title">HOME</string>
+  <string name="exit_action_title">Exit</string>
+  <string name="refresh_action_title">Refresh</string>
+  <string name="close_action_title">Close</string>
+  <string name="grant_access_action_title">Grant Access</string>
+  <string name="enable_location_action_title">Enable Location</string>
+  <string name="cancel_action_title">Cancel</string>
+  <string name="stop_action_title">Stop</string>
+  <string name="more_action_title">More</string>
+  <string name="call_action_title">Call</string>
+  <string name="primary_action_title">Primary</string>
+  <string name="options_action_title">Options</string>
+  <string name="search_action_title">Search</string>
+  <string name="checked_action_title">Checked</string>
+  <string name="unchecked_action_title">Unchecked</string>
+  <string name="on_action_title">On</string>
+  <string name="off_action_title">Off</string>
+  <string name="settings_action_title">Settings</string>
+  <string name="accept_action_title">Settings</string>
+  <string name="reject_action_title">Reject</string>
+  <string name="ok_action_title">OK</string>
+  <string name="throw_action_title">Throw</string>
+  <string name="commute_action_title">Commute</string>
+  <string name="sign_out_action_title">Sign out</string>
+  <string name="try_anyway_action_title">Try Anyway</string>
+
+  <!-- Toast Messages -->
+  <string name="bug_reported_toast_msg">Bug reported!</string>
+  <string name="zoomed_in_toast_msg">Zoomed in</string>
+  <string name="zoomed_out_toast_msg">Zoomed out</string>
+  <string name="triggered_toast_msg">Triggered</string>
+  <string name="primary_toast_msg">Primary button pressed</string>
+  <string name="search_toast_msg">Search button pressed</string>
+  <string name="options_toast_msg">Options button pressed</string>
+  <string name="favorite_toast_msg">Favorite!</string>
+  <string name="not_favorite_toast_msg">Not a favorite!</string>
+  <string name="nav_requested_toast_msg">Navigation Requested</string>
+  <string name="selected_route_toast_msg">Selected route</string>
+  <string name="visible_routes_toast_msg">Visible routes</string>
+  <string name="second_item_toast_msg">Clicked second item</string>
+  <string name="third_item_checked_toast_msg">Third item checked</string>
+  <string name="fifth_item_checked_toast_msg">Fifth item checked</string>
+  <string name="sixth_item_toast_msg">Clicked sixth item</string>
+  <string name="settings_toast_msg">Clicked Settings</string>
+  <string name="parked_toast_msg">Parked action</string>
+  <string name="more_toast_msg">Clicked More</string>
+  <string name="commute_toast_msg">Commute button pressed</string>
+  <string name="grant_location_permission_toast_msg">Grant location Permission to see current location</string>
+  <string name="sign_in_with_google_toast_msg">Sign-in with Google starts here</string>
+  <string name="changes_selection_to_index_toast_msg_prefix">Changed selection to index</string>
+
+  <!-- Row text -->
+  <string name="first_row_title">Row with a large image and long text long text long text long text long text</string>
+  <string name="first_row_text">Text text text</string>
+  <string name="other_row_title_prefix">Row title </string>
+  <string name="other_row_text">Row text</string>
+
+  <!-- Place Details Screen -->
+  <string name="navigate">Navigate</string>
+  <string name="dial">Dial</string>
+  <string name="address">Address</string>
+  <string name="phone">Phone</string>
+
+  <!-- CarHardwareDemoScreen -->
+  <string name="fail_start_nav">Failure starting navigation</string>
+  <string name="fail_start_dialer">Failure starting dialer</string>
+  <string name="car_hardware_demo_title">Car Hardware Demo</string>
+
+  <!-- CarHardwareInfoScreen -->
+  <string name="car_hardware_info">Car Hardware Information</string>
+  <string name="model_info">Model Information</string>
+  <string name="no_model_permission">No Model Permission</string>
+  <string name="manufacturer_unavailable">Manufacturer unavailable</string>
+  <string name="model_unavailable">Model unavailable</string>
+  <string name="year_unavailable">Year unavailable</string>
+  <string name="energy_profile">Energy Profile</string>
+  <string name="no_energy_profile_permission">No Energy Profile Permission</string>
+  <string name="fuel_types">Fuel Types</string>
+  <string name="unavailable">Unavailable</string>
+  <string name="ev_connector_types">EV Connector Types</string>
+
+  <!-- ColorDemoScreen -->
+  <string name="example_title">Example %d</string>
+  <string name="example_1_text">This text has a red color</string>
+  <string name="example_2_text">This text has a green color</string>
+  <string name="example_3_text">This text has a blue color</string>
+  <string name="example_4_text">This text has a yellow color</string>
+  <string name="example_5_text">This text uses the primary colo</string>
+  <string name="example_6_text">This text uses the secondary color</string>
+  <string name="color_demo">Color Demo</string>
+
+  <!-- ContentLimitsDemoScreen -->
+  <string name="list_limit">List Limit</string>
+  <string name="grid_limit">Grid Limit</string>
+  <string name="pane_limit">Pane Limit</string>
+  <string name="place_list_limit">Place List Limit</string>
+  <string name="route_list_limit">Route List Limit</string>
+  <string name="content_limits">Content Limits</string>
+  <string name="content_limits_demo_title">Content Limits Demo</string>
+
+  <!-- FinishAppScreen -->
+  <string name="finish_app_msg">This will finish the app, and when you return it will pre-seed a permission screen</string>
+  <string name="finish_app_title">Finish App Demo</string>
+  <string name="finish_app_demo_title">Pre-seed the Screen backstack on next run Demo</string>
+
+  <!-- LoadingDemoScreen -->
+  <string name="loading_demo_title">Loading Demo</string>
+  <string name="loading_demo_row_title">Loading Complete!</string>
+
+  <!-- PopToDemoScreen -->
+  <string name="pop_to_root">Pop to root</string>
+  <string name="pop_to_marker">Pop to Misc Demo Marker</string>
+  <string name="push_stack">Push further in stack</string>
+  <string name="pop_to_prefix">Pop To </string>
+  <string name="pop_to_title">PopTo Demo</string>
+
+  <!-- RequestPermissionScreen -->
+  <string name="package_not_found_error_msg">Package Not found.</string>
+  <string name="permissions_granted_msg">All permissions have been granted. Please revoke permissions from Settings.</string>
+  <string name="needs_access_msg_prefix">The app needs access to the following permissions:\n</string>
+  <string name="phone_screen_permission_msg">Grant Permission on the phone screen</string>
+  <string name="enable_location_permission_on_device_msg">Enable Location Permissions on device</string>
+  <string name="enable_location_permission_on_phone_msg">Enable location on the phone screen</string>
+  <string name="required_permissions_title">Required Permissions</string>
+  <string name="request_permissions_title">Request Permission Demo</string>
+
+  <!-- ReservationCancelledScreen -->
+  <string name="cancel_reservation_title">Cancel Reservation Screen</string>
+  <string name="reservation_cancelled_msg">Reservation canceled</string>
+
+  <!-- ResultDemoScreen -->
+  <string name="result_demo_title">Result demo</string>
+  <string name="not_started_for_result_msg">This app was not started for result</string>
+  <string name="started_for_result_msg">This app was called for result from %s. Please select the result to send back to the caller</string>
+
+  <!-- ArrivedDemoScreen -->
+  <string name="arrived_exclamation_msg">Arrived!</string>
+  <string name="arrived_address_msg">Google Bellevue Office\n1120 112th Ave NE</string>
+
+  <!-- RoutingDemoModels -->
+  <string name="current_step_cue">Roy st 520</string>
+  <string name="next_step_cue">I5 Aurora Ave N</string>
+  <string name="travel_est_trip_text">Pick Up Alice</string>
+
+  <!-- NotificationDemoScreen -->
+  <string name="send_notification_title">Send a notification</string>
+  <string name="start_notifications_title">Start notifications</string>
+  <string name="stop_notifications_title">Stop notifications</string>
+  <string name="notification_title">Notification</string>
+  <string name="importance_title">Importance</string>
+  <string name="category_title">Category</string>
+  <string name="ongoing_title">Ongoing</string>
+  <string name="notification_demo">Notification Demo</string>
+
+  <!-- MiscDemoScreen -->
+  <string name="misc_demo_title">Misc Demos</string>
+
+  <!-- NavigationTemplateDemoScreen -->
+  <string name="navigating_demo_title">Navigating Demo</string>
+  <string name="arrived_demo_title">Arrived Demo</string>
+  <string name="junction_image_demo_title">Junction Image Demo</string>
+  <string name="nav_template_demos_title">Navigation Template Demos</string>
+
+  <!-- MapTemplateDemoScreen -->
+  <string name="map_template_pane_demo_title">Map Template with Pane Demo</string>
+
+  <!-- NavigationNotificationsDemoScreen -->
+  <string name="start_notification_title">Start Notification</string>
+  <string name="stop_notification_title">Stop Notification</string>
+  <string name="nav_notification_demo_title">Navigation Notification Demo</string>
+
+  <!-- NavigationNotificationService -->
+  <string name="go_straight">Go Straight</string>
+  <string name="turn_right">Turn Right</string>
+  <string name="take_520">Take 520</string>
+  <string name="gas_station">Gas Station</string>
+
+  <!-- RoutePreviewDemoScreen -->
+  <string name="short_route">Short route</string>
+  <string name="less_busy">Less busy</string>
+  <string name="hov_friendly">HOV friendly</string>
+  <string name="long_route">Long route</string>
+  <string name="continue_start_nav">Continue to start navigation</string>
+  <string name="continue_route">Continue to route</string>
+  <string name="routes_title">Routes</string>
+
+  <!-- NavigationDemosScreen -->
+  <string name="place_list_nav_template_demo_title">Place List Navigation Template Demo</string>
+  <string name="route_preview_template_demo_title">Route Preview Template Demo</string>
+  <string name="notification_template_demo_title">Notification Template Demo</string>
+  <string name="nav_map_template_demo_title">Navigation Template with map only Demo</string>
+  <string name="nav_demos_title">Navigation Demos</string>
+
+  <!-- CarHardwareRenderer -->
+  <string name="no_toll_card_permission">No TollCard Permission.</string>
+  <string name="no_energy_level_permission">No EnergyLevel Permission.</string>
+  <string name="no_speed_permission">No Speed Permission.</string>
+  <string name="no_mileage_permission">No Mileage Permission.</string>
+  <string name="no_ev_status_permission">No EV status Permission.</string>
+  <string name="no_accelerometer_permission">No Accelerometer Permission.</string>
+  <string name="no_gyroscope_permission">No Gyroscope Permission.</string>
+  <string name="no_compass_permission">No Compass Permission.</string>
+  <string name="no_car_hardware_location">No CarHardwareLocation Permission.</string>
+  <string name="fetch_toll_info">Fetching Toll information.</string>
+  <string name="fetch_energy_level">Fetching Energy Level.</string>
+  <string name="fetch_speed">Fetching Speed.</string>
+  <string name="fetch_mileage">Fetching Mileage.</string>
+  <string name="fetch_ev_status">Fetching EV status.</string>
+  <string name="fetch_accelerometer">Fetching Accelerometer.</string>
+  <string name="fetch_gyroscope">Fetching Gyroscope.</string>
+  <string name="fetch_compass">Fetching Compass.</string>
+  <string name="fetch_location">Fetching Location.</string>
+  <string name="toll_card_state">Toll card state</string>
+  <string name="low_energy">Low energy</string>
+  <string name="range">Range</string>
+  <string name="fuel">Fuel</string>
+  <string name="battery">Battery</string>
+  <string name="display_speed">Display Speed</string>
+  <string name="raw_speed">Raw Speed</string>
+  <string name="unit">Unit</string>
+  <string name="odometer">Odometer</string>
+  <string name="ev_connected">Ev Charge Port Connected</string>
+  <string name="ev_open">Ev Charge Port Open</string>
+  <string name="accelerometer">Accelerometer</string>
+  <string name="gyroscope">Gyroscope</string>
+  <string name="compass">Compass</string>
+  <string name="car_hardware_location">Car Hardware Location</string>
+
+  <!-- GridTemplateDemoScreen -->
+  <string name="non_actionable">Non-actionable</string>
+  <string name="second_item">Second Item</string>
+  <string name="third_item">Third Item</string>
+  <string name="fourth_item">Fourth Item</string>
+  <string name="fifth_item">Fifth Item has a long title set</string>
+  <string name="sixth_item">Sixth Item has a long title set</string>
+  <string name="grid_template_demo_title">Grid Template Demo</string>
+
+  <!-- ListTemplateDemoScreen -->
+  <string name="parked_only_title">Parked Only Title</string>
+  <string name="parked_only_text">More Parked only text.</string>
+  <string name="clicked_row_prefix">Clicked row</string>
+  <string name="first_line_text">First line of text</string>
+  <string name="second_line_text">Second line of text</string>
+  <string name="title_prefix">Title</string>
+  <string name="list_template_demo_title">List Template Demo</string>
+
+  <!-- LongMessageTemplateDemoScreen -->
+  <string name="long_msg_template_demo_title">Long Message Template Demo</string>
+  <string name="long_msg_template_text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. \nAliquam laoreet ac metus eu commodo. Sed a congue diam, sed dictum lectus. Nam nec\ntristique dolor, quis sodales arcu. Etiam at metus eu nulla auctor varius. \nInteger dolor lorem, placerat sit amet lacus in, imperdiet semper dui. Vestibulum \nante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \nQuisque gravida fermentum egestas.\n\n\n\nUt ut sodales mi. Aenean porta vel ipsum sed lacinia. Morbi odio ipsum, hendrerit \neu est et, sollicitudin finibus diam. Nunc sit amet felis elit. Orci varius \nnatoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed \nvestibulum, tellus a rutrum auctor, diam arcu vestibulum purus, nec mollis ligula \nnisi in nisi. Donec sem tortor, pharetra sed fermentum sit amet, ullamcorper nec \nsapien. Aliquam risus arcu, porttitor eu dui nec, vulputate tempus libero. \nCurabitur sit amet tristique orci. Suspendisse et odio tempus, tempus turpis quis,\n euismod est.\n\n\n\nVestibulum mauris ante, luctus viverra nisi eget, blandit facilisis nulla. \nPhasellus ex lorem, semper in vestibulum nec, aliquet vel elit. Aliquam vitae \nligula nec enim dictum lobortis. Sed varius turpis quis nisi tempus varius. Sed \nnon sollicitudin magna, at mattis tortor. Curabitur quis ligula eget lorem mattis \ntincidunt et in sapien. Curabitur a elit nisi. Aliquam ex arcu, hendrerit eget \nturpis vitae, bibendum vulputate nibh. Fusce vitae ex aliquet, tristique magna eu,\n vulputate dui. Aenean tempor viverra tortor non pharetra. Pellentesque convallis \nnec risus a auctor. Praesent non sem non eros tincidunt ullamcorper efficitur non \nlacus.\n\n\n\nSuspendisse accumsan ultricies egestas. Aenean leo ligula, congue ac erat eu, \nlobortis ultricies lorem. Nulla finibus, arcu sed tincidunt lobortis, magna justo \nrutrum ligula, et mattis felis turpis vel ex. Morbi ac auctor ex, at bibendum sem.\n Vestibulum a tortor iaculis, viverra felis vitae, lobortis est. Duis sit amet \ncondimentum sem. Ut molestie, dolor pretium imperdiet maximus, enim orci porta \nquam, id gravida enim nunc vitae lacus. Pellentesque habitant morbi tristique \nsenectus et netus et malesuada fames ac turpis egestas. Nullam vel justo eu risus \nlobortis dignissim sit amet ullamcorper nulla. Donec finibus cursus purus \nporttitor pellentesque.\n\n\n\nDonec at vehicula ante. Suspendisse rutrum nisl quis metus faucibus lacinia. \nVestibulum eros sapien, eleifend nec accumsan a, interdum sed nisi. Aenean posuere\n ultrices lorem non pharetra. Nulla non porta ligula. Maecenas at elit diam. \nNullam gravida augue et semper eleifend. Fusce venenatis ac arcu et luctus. Mauris\n ultricies urna non dui interdum, vel hendrerit est aliquam. Fusce id dictum leo, \nfringilla egestas ipsum.</string>
+  <string name="long_msg_template_not_supported_text">Your host doesn\'t support Long Message template</string>
+  <string name="long_msg_template_not_supported_title">Incompatible host</string>
+
+  <!-- MessageTemplateDemoScreen -->
+  <string name="msg_template_demo_title">Message Template Demo</string>
+  <string name="msg_template_demo_text">Message goes here.\nMore text on second line.</string>
+
+  <!-- PaneTemplateDemoScreen -->
+  <string name="pane_template_demo_title">Pane Template Demo</string>
+
+  <!-- PlaceListTemplateBrowseDemoScreen -->
+  <string name="place_list_template_demo_title">Place List Template Demo</string>
+  <string name="browse_places_title">Browse Places</string>
+
+  <!-- SearchTemplateDemoScreen -->
+  <string name="search_hint">Search here</string>
+
+  <!-- SignInTemplateDemoScreen -->
+  <string name="additional_text">Please review our terms of service</string>
+  <string name="google_sign_in">Google sign-in</string>
+  <string name="use_pin">Use PIN</string>
+  <string name="qr_code">QR Code</string>
+  <string name="sign_in_template_not_supported_text">Your host doesn\'t support Sign In template</string>
+  <string name="sign_in_template_not_supported_title">Incompatible host</string>
+  <string name="email_hint">Email</string>
+  <string name="sign_in_title">Sign in</string>
+  <string name="sign_in_instructions">Enter your credentials</string>
+  <string name="invalid_email_error_msg">User name must be a valid email address</string>
+  <string name="invalid_length_error_msg">User name must be at least %s characters long</string>
+  <string name="invalid_password_error_msg">Invalid password</string>
+  <string name="password_hint">password</string>
+  <string name="password_sign_in_instruction_prefix">Username</string>
+  <string name="pin_sign_in_instruction">Type this PIN in your phone</string>
+  <string name="qr_code_sign_in_title">Scan QR Code to sign in</string>
+  <string name="sign_in_with_google_title">Sign in with Google</string>
+  <string name="provider_sign_in_instruction">Use this button to complete your Google sign-in</string>
+  <string name="sign_in_complete_text">You are signed in!</string>
+  <string name="sign_in_complete_title">Sign in completed</string>
+
+  <!-- ContentProviderIconsDemoScreen -->
+  <string name="images_unknown_host_error">Images cannot be displayed for an unknown host</string>
+  <string name="icon_title_prefix">Icon</string>
+  <string name="content_provider_icons_demo_title">Content Provider Icons Demo</string>
+
+  <!-- IconsDemoScreen -->
+  <string name="icons_demo_title">Icons Demo</string>
+  <string name="app_icon_title">The app icon</string>
+  <string name="vector_no_tint_title">A vector drawable, without a tint</string>
+  <string name="vector_with_tint_title">A vector drawable, with a tint</string>
+  <string name="vector_with_app_theme_attr_title">A vector drawable, with an app\'s theme attribute for its color</string>
+  <string name="png_res_title">A PNG, sent as a resource</string>
+  <string name="png_bitmap_title">A PNG, sent as a resource</string>
+
+  <!-- RowDemoScreen -->
+  <string name="just_row_title">Just a title</string>
+  <string name="title_with_app_icon_row_title">Title with app icon</string>
+  <string name="title_with_res_id_image_row_title">Title with resource ID image</string>
+  <string name="title_with_svg_image_row_title">Title with SVG image</string>
+  <string name="colored_secondary_row_title">Colored secondary text</string>
+  <string name="title_with_secondary_lines_row_title">Title with multiple secondary text lines</string>
+  <string name="title_with_secondary_lines_row_text_1">Err and err and err again, but less and less and less.</string>
+  <string name="title_with_secondary_lines_row_text_2">- Piet Hein</string>
+  <string name="rows_demo_title">Rows Demo</string>
+
+  <!-- TextAndIconsDemosScreen -->
+  <string name="text_icons_demo_title">Text and Icons Demos</string>
+  <string name="row_text_icons_demo_title">Rows with Text and Icons Demo</string>
+
+  <!-- SelectableListsDemoScreen -->
+  <string name="selectable_lists_demo_title">Selectable Lists Demo</string>
+  <string name="option_1_title">Option 1</string>
+  <string name="option_2_title">Option 2</string>
+  <string name="option_3_title">Option 3</string>
+  <string name="some_additional_text">Some additional text</string>
+  <string name="sample_additional_list">Sample selectable list</string>
+
+  <!-- TaskRestrictionDemoScreen -->
+  <string name="task_restriction_demo_title">Task Restriction Demo</string>
+  <string name="task_limit_reached_msg">Task limit reached\nGoing forward will force stop the app</string>
+  <string name="task_step_of_title">Task step %1$d of %2$d</string>
+  <string name="task_step_of_text">Click to go forward</string>
+  <string name="toggle_test_title">Toggle test</string>
+  <string name="toggle_test_text">Stateful changes are allowed</string>
+  <string name="image_test_title">Image test</string>
+  <string name="image_test_text">Image changes are allowed</string>
+  <string name="additional_data_title">Additional Data</string>
+  <string name="additional_data_text">Updates allows on back operations.</string>
+
+  <!-- StartScreen -->
+  <string name="misc_templates_demos_title">Misc Templates Demos</string>
+  <string name="showcase_demos_title">Showcase Demos</string>
+
+  <!-- Location Strings -->
+  <string name="location_1_title">Google Kirkland</string>
+  <string name="location_1_address" translatable="false">747 6th St South, Kirkland, WA 98033</string>
+  <string name="location_1_description">Tinted resource vector</string>
+  <string name="location_1_phone" translatable="false">+14257395600</string>
+  <string name="location_2_title">Google Bellevue</string>
+  <string name="location_2_address" translatable="false">1120 112th Ave NE, Bellevue, WA 98004</string>
+  <string name="location_2_description">Image resource bitmap</string>
+  <string name="location_2_phone" translatable="false">+14252301301</string>
+  <string name="location_3_title">Google South Lake Union</string>
+  <string name="location_3_address" translatable="false">1021 Valley St, Seattle, WA 98109</string>
+  <string name="location_3_description">Colored text marker</string>
+  <string name="location_3_phone" translatable="false">+12065311800</string>
+  <string name="location_4_title">Google Seattle</string>
+  <string name="location_4_address" translatable="false">601 N 34th St, Seattle, WA 98103</string>
+  <string name="location_4_description">Image bitmap</string>
+  <string name="location_4_phone" translatable="false">+12068761800</string>
+  <string name="location_5_address" translatable="false">1600 Amphitheatre Pkwy, Mountain View, CA 94043</string>
+  <string name="location_5_phone" translatable="false">+16502530000</string>
+  <string name="location_6_title">Google Bothell</string>
+  <string name="location_6_address" translatable="false">11831 North Creek Pkwy, Bothell, WA 98011</string>
+  <string name="location_7_title">Seward Park</string>
+  <string name="location_7_address" translatable="false">5900 Lake Washington Blvd S, Seattle, WA 98118</string>
+  <string name="location_8_title">Luther Burbank Park</string>
+  <string name="location_8_address" translatable="false">2040 84th Ave SE, Mercer Island, WA 98040</string>
+  <string name="location_9_title">Heritage Park</string>
+  <string name="location_9_address" translatable="false">111 Waverly Way, Kirkland, WA 98033</string>
+  <string name="location_description_text_label">Text label</string>
+  <string name="location_phone_not_available" translatable="false">n/a</string>
 </resources>
diff --git a/collection/collection/build.gradle b/collection/collection/build.gradle
index bb4dead..eedae0f 100644
--- a/collection/collection/build.gradle
+++ b/collection/collection/build.gradle
@@ -16,16 +16,35 @@
 
 
 import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
 
 plugins {
     id("AndroidXPlugin")
     id("org.jetbrains.kotlin.multiplatform")
 }
 
+// This should be true when building from GitHub, and false when building
+// from AOSP.  Use this to block out any features or code that we're not
+// ready to build yet in AOSP
+
+def boolProperty(name) {
+    return project.providers.gradleProperty(name).getOrNull()?.toBoolean()
+}
+
+def playground = androidx.build.StudioType.isPlayground(project)
+//Native on by default in playground
+def enableNative = boolProperty('androidx.kmp.native.enabled') ?: playground
+
 kotlin {
     jvm {
         withJava()
     }
+    if (enableNative) {
+        macosX64()
+        macosArm64()
+        linuxX64()
+        mingwX64()
+    }
 
     sourceSets {
         commonMain {
@@ -40,6 +59,19 @@
             }
         }
 
+        if (enableNative) {
+            nativeMain
+
+            configure([linuxX64Main, macosX64Main, macosArm64Main, mingwX64Main]) {
+                dependsOn nativeMain
+            }
+
+            nativeTest
+            configure([linuxX64Test, macosX64Test, macosArm64Test, mingwX64Test]) {
+                dependsOn nativeTest
+            }
+        }
+
         jvmMain {
             dependencies {
                 api(libs.kotlinStdlib)
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
similarity index 87%
rename from collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt
rename to collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
index 80a7b91..6230ddb 100644
--- a/collection/collection/src/jvmMain/kotlin/androidx/collection/CircularArray.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/CircularArray.kt
@@ -16,6 +16,9 @@
 
 package androidx.collection
 
+import androidx.collection.CollectionPlatformUtils.createIndexOutOfBoundsException
+import kotlin.jvm.JvmOverloads
+
 /**
  * CircularArray is a generic circular array data structure that provides O(1) random read, O(1)
  * prepend and O(1) append. The CircularArray automatically grows its capacity when number of added
@@ -40,8 +43,8 @@
 
         // If minCapacity isn't a power of 2, round up to the next highest
         // power of 2.
-        val arrayCapacity: Int = if (Integer.bitCount(minCapacity) != 1) {
-            Integer.highestOneBit(minCapacity - 1) shl 1
+        val arrayCapacity: Int = if (minCapacity.countOneBits() != 1) {
+            (minCapacity - 1).takeHighestOneBit() shl 1
         } else {
             minCapacity
         }
@@ -97,11 +100,11 @@
      * Remove first element from front of the [CircularArray] and return it.
      *
      * @return The element removed.
-     * @throws ArrayIndexOutOfBoundsException if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty (on jvm)
      */
     public fun popFirst(): E {
         if (head == tail) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         val result = elements[head]
         elements[head] = null
@@ -115,11 +118,11 @@
      * Remove last element from end of the [CircularArray] and return it.
      *
      * @return The element removed.
-     * @throws ArrayIndexOutOfBoundsException if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public fun popLast(): E {
         if (head == tail) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         val t = (tail - 1) and capacityBitmask
         val result = elements[t]
@@ -142,14 +145,14 @@
      * is less than or equal to 0.
      *
      * @param count Number of elements to remove.
-     * @throws ArrayIndexOutOfBoundsException if [count] is larger than [size]
+     * @throws [ArrayIndexOutOfBoundsException] if [count] is larger than [size]
      */
     public fun removeFromStart(count: Int) {
         if (count <= 0) {
             return
         }
         if (count > size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
 
         var numOfElements = count
@@ -177,14 +180,14 @@
      * is less than or equals to 0.
      *
      * @param count Number of elements to remove.
-     * @throws ArrayIndexOutOfBoundsException if [count] is larger than [size]
+     * @throws [ArrayIndexOutOfBoundsException] if [count] is larger than [size]
      */
     public fun removeFromEnd(count: Int) {
         if (count <= 0) {
             return
         }
         if (count > size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
 
         var numOfElements = count
@@ -213,12 +216,12 @@
      * Get first element of the [CircularArray].
      *
      * @return The first element.
-     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public val first: E
         get() {
             if (head == tail) {
-                throw ArrayIndexOutOfBoundsException()
+                throw createIndexOutOfBoundsException()
             }
             return elements[head]!!
         }
@@ -227,12 +230,12 @@
      * Get last element of the [CircularArray].
      *
      * @return The last element.
-     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty.
+     * @throws [ArrayIndexOutOfBoundsException] if [CircularArray] is empty
      */
     public val last: E
         get() {
             if (head == tail) {
-                throw ArrayIndexOutOfBoundsException()
+                throw createIndexOutOfBoundsException()
             }
             return elements[tail - 1 and capacityBitmask]!!
         }
@@ -242,11 +245,11 @@
      *
      * @param index The zero based element index in the [CircularArray].
      * @return The nth element.
-     * @throws [ArrayIndexOutOfBoundsException] if n < 0 or n >= size().
+     * @throws [ArrayIndexOutOfBoundsException] if n < 0 or n >= size()
      */
     public operator fun get(index: Int): E {
         if (index < 0 || index >= size()) {
-            throw ArrayIndexOutOfBoundsException()
+            throw createIndexOutOfBoundsException()
         }
         return elements[(head + index) and capacityBitmask]!!
     }
@@ -266,4 +269,4 @@
      * @return `true` if [size] is 0.
      */
     public fun isEmpty(): Boolean = head == tail
-}
+}
\ No newline at end of file
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
new file mode 100644
index 0000000..f3cec22
--- /dev/null
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+/**
+ * Internal utils for handling implementation differences for the various targets of Collections.
+ */
+internal expect object CollectionPlatformUtils {
+
+    /**
+     * IndexOutOfBoundsException is the nearest kotlin common ancestor for the native and jvm
+     * specific implementations of ArrayIndexOutOfBoundsException.  Actuals should throw an
+     * exception specific to their target platform.
+     */
+    internal inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException
+}
diff --git a/collection/collection/src/jvmTest/java/androidx/collection/CircularArrayTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/CircularArrayTest.kt
similarity index 100%
rename from collection/collection/src/jvmTest/java/androidx/collection/CircularArrayTest.kt
rename to collection/collection/src/commonTest/kotlin/androidx/collection/CircularArrayTest.kt
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt b/collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
new file mode 100644
index 0000000..0233729
--- /dev/null
+++ b/collection/collection/src/jvmMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+/**
+ * JVM actual of internal utils for handling target differences in collection code.
+ */
+internal actual object CollectionPlatformUtils {
+
+    @Suppress("NOTHING_TO_INLINE")
+    internal actual inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException {
+        return ArrayIndexOutOfBoundsException()
+    }
+}
diff --git a/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java b/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java
deleted file mode 100644
index 6e14244..0000000
--- a/collection/collection/src/jvmTest/java/androidx/collection/LruCacheTest.java
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.collection;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-@RunWith(JUnit4.class)
-public class LruCacheTest {
-
-    private int mExpectedCreateCount;
-    private int mExpectedPutCount;
-    private int mExpectedHitCount;
-    private int mExpectedMissCount;
-    private int mExpectedEvictionCount;
-
-    @Test
-    public void testStatistics() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        assertStatistics(cache);
-        assertEquals(null, cache.put("a", "A"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertSnapshot(cache, "a", "A");
-        assertEquals(null, cache.put("b", "B"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertHit(cache, "b", "B");
-        assertSnapshot(cache, "a", "A", "b", "B");
-        assertEquals(null, cache.put("c", "C"));
-        mExpectedPutCount++;
-        assertStatistics(cache);
-        assertHit(cache, "a", "A");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "a", "A", "b", "B", "c", "C");
-        assertEquals(null, cache.put("d", "D"));
-        mExpectedPutCount++;
-        mExpectedEvictionCount++; // a should have been evicted
-        assertStatistics(cache);
-        assertMiss(cache, "a");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertHit(cache, "d", "D");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "d", "D", "b", "B", "c", "C");
-        assertEquals(null, cache.put("e", "E"));
-        mExpectedPutCount++;
-        mExpectedEvictionCount++; // d should have been evicted
-        assertStatistics(cache);
-        assertMiss(cache, "d");
-        assertMiss(cache, "a");
-        assertHit(cache, "e", "E");
-        assertHit(cache, "b", "B");
-        assertHit(cache, "c", "C");
-        assertSnapshot(cache, "e", "E", "b", "B", "c", "C");
-    }
-
-    @Test
-    public void testStatisticsWithCreate() {
-        LruCache<String, String> cache = newCreatingCache();
-        assertStatistics(cache);
-        assertCreated(cache, "aa", "created-aa");
-        assertHit(cache, "aa", "created-aa");
-        assertSnapshot(cache, "aa", "created-aa");
-        assertCreated(cache, "bb", "created-bb");
-        assertMiss(cache, "c");
-        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb");
-        assertCreated(cache, "cc", "created-cc");
-        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc");
-        mExpectedEvictionCount++; // aa will be evicted
-        assertCreated(cache, "dd", "created-dd");
-        assertSnapshot(cache, "bb", "created-bb",  "cc", "created-cc", "dd", "created-dd");
-        mExpectedEvictionCount++; // bb will be evicted
-        assertCreated(cache, "aa", "created-aa");
-        assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa");
-    }
-
-    @Test
-    public void testCreateOnCacheMiss() {
-        LruCache<String, String> cache = newCreatingCache();
-        String created = cache.get("aa");
-        assertEquals("created-aa", created);
-    }
-
-    @Test
-    public void testNoCreateOnCacheHit() {
-        LruCache<String, String> cache = newCreatingCache();
-        cache.put("aa", "put-aa");
-        assertEquals("put-aa", cache.get("aa"));
-    }
-
-    @Test
-    public void testConstructorDoesNotAllowZeroCacheSize() {
-        try {
-            new LruCache<String, String>(0);
-            fail();
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testCannotPutNullKey() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        try {
-            cache.put(null, "A");
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testCannotPutNullValue() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        try {
-            cache.put("a", null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testToString() {
-        LruCache<String, String> cache = new LruCache<String, String>(3);
-        assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString());
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("d", "D");
-        cache.get("a"); // miss
-        cache.get("b"); // hit
-        cache.get("c"); // hit
-        cache.get("d"); // hit
-        cache.get("e"); // miss
-        assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString());
-    }
-
-    @Test
-    public void testEvictionWithSingletonCache() {
-        LruCache<String, String> cache = new LruCache<String, String>(1);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        assertSnapshot(cache, "b", "B");
-    }
-
-    @Test
-    public void testEntryEvictedWhenFull() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        assertEquals(Collections.<String>emptyList(), log);
-        cache.put("d", "D");
-        assertEquals(Arrays.asList("a=A"), log);
-    }
-
-    /**
-     * Replacing the value for a key doesn't cause an eviction but it does bring
-     * the replaced entry to the front of the queue.
-     */
-    @Test
-    public void testPutCauseEviction() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("b", "B2");
-        assertEquals(Arrays.asList("b=B>B2"), log);
-        assertSnapshot(cache, "a", "A", "c", "C", "b", "B2");
-    }
-
-    @Test
-    public void testCustomSizesImpactsSize() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return key.length() + value.length();
-            }
-        };
-        assertEquals(0, cache.size());
-        cache.put("a", "AA");
-        assertEquals(3, cache.size());
-        cache.put("b", "BBBB");
-        assertEquals(8, cache.size());
-        cache.put("a", "");
-        assertEquals(6, cache.size());
-    }
-
-    @Test
-    public void testEvictionWithCustomSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(4) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "AAAA");
-        assertSnapshot(cache, "a", "AAAA");
-        cache.put("b", "BBBB"); // should evict a
-        assertSnapshot(cache, "b", "BBBB");
-        cache.put("c", "CC"); // should evict b
-        assertSnapshot(cache, "c", "CC");
-        cache.put("d", "DD");
-        assertSnapshot(cache, "c", "CC", "d", "DD");
-        cache.put("e", "E"); // should evict c
-        assertSnapshot(cache, "d", "DD", "e", "E");
-        cache.put("f", "F");
-        assertSnapshot(cache, "d", "DD", "e", "E", "f", "F");
-        cache.put("g", "G"); // should evict d
-        assertSnapshot(cache, "e", "E", "f", "F", "g", "G");
-        cache.put("h", "H");
-        assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H");
-        cache.put("i", "III"); // should evict e, f, and g
-        assertSnapshot(cache, "h", "H", "i", "III");
-        cache.put("j", "JJJ"); // should evict h and i
-        assertSnapshot(cache, "j", "JJJ");
-    }
-
-    @Test
-    public void testEvictionThrowsWhenSizesAreInconsistent() {
-        LruCache<String, int[]> cache = new LruCache<String, int[]>(4) {
-            @Override protected int sizeOf(String key, int[] value) {
-                return value[0];
-            }
-        };
-        int[] a = { 4 };
-        cache.put("a", a);
-        // get the cache size out of sync
-        a[0] = 1;
-        assertEquals(4, cache.size());
-        // evict something
-        try {
-            cache.put("b", new int[] { 2 });
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    @Test
-    public void testEvictionThrowsWhenSizesAreNegative() {
-        LruCache<String, String> cache = new LruCache<String, String>(4) {
-            @Override protected int sizeOf(String key, String value) {
-                return -1;
-            }
-        };
-        try {
-            cache.put("a", "A");
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    /**
-     * Naive caches evict at most one element at a time. This is problematic
-     * because evicting a small element may be insufficient to make room for a
-     * large element.
-     */
-    @Test
-    public void testDifferentElementSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "1");
-        cache.put("b", "12345678");
-        cache.put("c", "1");
-        assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1");
-        cache.put("d", "12345678"); // should evict a and b
-        assertSnapshot(cache, "c", "1", "d", "12345678");
-        cache.put("e", "12345678"); // should evict c and d
-        assertSnapshot(cache, "e", "12345678");
-    }
-
-    @Test
-    public void testEvictAll() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.evictAll();
-        assertEquals(0, cache.size());
-        assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log);
-    }
-
-    @Test
-    public void testEvictAllEvictsSizeZeroElements() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return 0;
-            }
-        };
-        cache.put("a", "A");
-        cache.put("b", "B");
-        cache.evictAll();
-        assertSnapshot(cache);
-    }
-
-    @Test
-    public void testRemoveWithCustomSizes() {
-        LruCache<String, String> cache = new LruCache<String, String>(10) {
-            @Override protected int sizeOf(String key, String value) {
-                return value.length();
-            }
-        };
-        cache.put("a", "123456");
-        cache.put("b", "1234");
-        cache.remove("a");
-        assertEquals(4, cache.size());
-    }
-
-    @Test
-    public void testRemoveAbsentElement() {
-        LruCache<String, String> cache = new LruCache<String, String>(10);
-        cache.put("a", "A");
-        cache.put("b", "B");
-        assertEquals(null, cache.remove("c"));
-        assertEquals(2, cache.size());
-    }
-
-    @Test
-    public void testRemoveNullThrows() {
-        LruCache<String, String> cache = new LruCache<String, String>(10);
-        try {
-            cache.remove(null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
-    }
-
-    @Test
-    public void testRemoveCallsEntryRemoved() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.remove("a");
-        assertEquals(Arrays.asList("a=A>null"), log);
-    }
-
-    @Test
-    public void testPutCallsEntryRemoved() {
-        List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = newRemovalLogCache(log);
-        cache.put("a", "A");
-        cache.put("a", "A2");
-        assertEquals(Arrays.asList("a=A>A2"), log);
-    }
-
-    @Test
-    public void testEntryRemovedIsCalledWithoutSynchronization() {
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                assertFalse(Thread.holdsLock(this));
-            }
-        };
-        cache.put("a", "A");
-        cache.put("a", "A2"); // replaced
-        cache.put("b", "B");
-        cache.put("c", "C");
-        cache.put("d", "D");  // single eviction
-        cache.remove("a");    // removed
-        cache.evictAll();     // multiple eviction
-    }
-
-    @Test
-    public void testCreateIsCalledWithoutSynchronization() {
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                assertFalse(Thread.holdsLock(this));
-                return null;
-            }
-        };
-        cache.get("a");
-    }
-
-    /**
-     * Test what happens when a value is added to the map while create is
-     * working. The map value should be returned by get(), and the created value
-     * should be released with entryRemoved().
-     */
-    @Test
-    public void testCreateWithConcurrentPut() {
-        final List<String> log = new ArrayList<String>();
-        LruCache<String, String> cache = new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                put(key, "B");
-                return "A";
-            }
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                log.add(key + "=" + oldValue + ">" + newValue);
-            }
-        };
-        assertEquals("B", cache.get("a"));
-        assertEquals(Arrays.asList("a=A>B"), log);
-    }
-
-    /**
-     * Test what happens when two creates happen concurrently. The result from
-     * the first create to return is returned by both gets. The other created
-     * values should be released with entryRemove().
-     */
-    @Test
-    public void testCreateWithConcurrentCreate() {
-        final List<String> log = new ArrayList<String>();
-        LruCache<String, Integer> cache = new LruCache<String, Integer>(3) {
-            int mCallCount = 0;
-            @Override protected Integer create(String key) {
-                if (mCallCount++ == 0) {
-                    assertEquals(2, get(key).intValue());
-                    return 1;
-                } else {
-                    return 2;
-                }
-            }
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, Integer oldValue, Integer newValue) {
-                log.add(key + "=" + oldValue + ">" + newValue);
-            }
-        };
-        assertEquals(2, cache.get("a").intValue());
-        assertEquals(Arrays.asList("a=1>2"), log);
-    }
-
-    /** Makes sure that LruCache operations are correctly synchronized to guarantee consistency. */
-    @Test
-    public void consistentMultithreadedAccess() {
-        class Tally {
-            int mNonNullValues;
-            int mNullValues;
-            int mValuesPut;
-            int mConflicts;
-            int mRemoved;
-        }
-
-        final Tally tally = new Tally();
-        final int rounds = 10000;
-        final String key = "key";
-        final int value = 42;
-        final LruCache<String, Integer> cache  = new LruCache<String, Integer>(1) {
-            @Override
-            protected Integer create(String key) {
-                return value;
-            }
-        };
-
-        Runnable r0 = new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < rounds; i++) {
-                    if (cache.get(key) != null) {
-                        tally.mNonNullValues++;
-                    } else {
-                        tally.mNullValues++;
-                    }
-                }
-            }
-        };
-
-        Runnable r1 = new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < rounds; i++) {
-                    if (i % 2 == 0) {
-                        if (cache.put(key, value) != null) {
-                            tally.mConflicts++;
-                        } else {
-                            tally.mValuesPut++;
-                        }
-                    } else {
-                        cache.remove(key);
-                        tally.mRemoved++;
-                    }
-                }
-            }
-        };
-
-
-        Thread t0 = new Thread(r0);
-        Thread t1 = new Thread(r1);
-
-        t0.start();
-        t1.start();
-        try {
-            t0.join();
-            t1.join();
-        } catch (InterruptedException e) {
-            fail();
-        }
-
-        assertEquals(rounds, tally.mNonNullValues);
-        assertEquals(0, tally.mNullValues);
-        assertEquals(rounds, tally.mValuesPut + tally.mConflicts + tally.mRemoved);
-    }
-
-    private LruCache<String, String> newCreatingCache() {
-        return new LruCache<String, String>(3) {
-            @Override protected String create(String key) {
-                return (key.length() > 1) ? ("created-" + key) : null;
-            }
-        };
-    }
-
-    private LruCache<String, String> newRemovalLogCache(final List<String> log) {
-        return new LruCache<String, String>(3) {
-            @Override protected void entryRemoved(
-                    boolean evicted, String key, String oldValue, String newValue) {
-                String message = evicted
-                        ? (key + "=" + oldValue)
-                        : (key + "=" + oldValue + ">" + newValue);
-                log.add(message);
-            }
-        };
-    }
-
-    private void assertHit(LruCache<String, String> cache, String key, String value) {
-        assertEquals(value, cache.get(key));
-        mExpectedHitCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertMiss(LruCache<String, String> cache, String key) {
-        assertEquals(null, cache.get(key));
-        mExpectedMissCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertCreated(LruCache<String, String> cache, String key, String value) {
-        assertEquals(value, cache.get(key));
-        mExpectedMissCount++;
-        mExpectedCreateCount++;
-        assertStatistics(cache);
-    }
-
-    private void assertStatistics(LruCache<?, ?> cache) {
-        assertEquals("create count", mExpectedCreateCount, cache.createCount());
-        assertEquals("put count", mExpectedPutCount, cache.putCount());
-        assertEquals("hit count", mExpectedHitCount, cache.hitCount());
-        assertEquals("miss count", mExpectedMissCount, cache.missCount());
-        assertEquals("eviction count", mExpectedEvictionCount, cache.evictionCount());
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T> void assertSnapshot(LruCache<T, T> cache, T... keysAndValues) {
-        List<T> actualKeysAndValues = new ArrayList<T>();
-        for (Map.Entry<T, T> entry : cache.snapshot().entrySet()) {
-            actualKeysAndValues.add(entry.getKey());
-            actualKeysAndValues.add(entry.getValue());
-        }
-        // assert using lists because order is important for LRUs
-        assertEquals(Arrays.asList(keysAndValues), actualKeysAndValues);
-    }
-}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt
new file mode 100644
index 0000000..8c0dc29
--- /dev/null
+++ b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheJvmTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+import kotlin.concurrent.thread
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+
+internal class LruCacheJvmTest {
+
+    @Test
+    fun testEntryRemovedIsCalledWithoutSynchronization() {
+        val cache =
+            object : LruCache<String, String>(3) {
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: String,
+                    newValue: String?
+                ) {
+                    assertFalse(Thread.holdsLock(this))
+                }
+            }
+        cache.put("a", "A")
+        cache.put("a", "A2") // replaced
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("d", "D") // single eviction
+        cache.remove("a") // removed
+        cache.evictAll() // multiple eviction
+    }
+
+    /** Makes sure that LruCache operations are correctly synchronized to guarantee consistency.  */
+    @Test
+    fun consistentMultithreadedAccess() {
+        var nonNullValues = 0
+        var nullValues = 0
+        var valuesPut = 0
+        var conflicts = 0
+        var removed = 0
+
+        val rounds = 10000
+        val key = "key"
+        val value = 42
+        val cache =
+            object : LruCache<String, Int>(1) {
+                override fun create(key: String): Int = value
+            }
+
+        val t0 =
+            thread {
+                repeat(rounds) {
+                    if (cache[key] != null) {
+                        nonNullValues++
+                    } else {
+                        nullValues++
+                    }
+                }
+            }
+
+        val t1 =
+            thread {
+                repeat(rounds) { i ->
+                    if (i % 2 == 0) {
+                        if (cache.put(key, value) != null) {
+                            conflicts++
+                        } else {
+                            valuesPut++
+                        }
+                    } else {
+                        cache.remove(key)
+                        removed++
+                    }
+                }
+            }
+
+        t0.join()
+        t1.join()
+
+        assertEquals(rounds, nonNullValues)
+        assertEquals(0, nullValues)
+        assertEquals(rounds, valuesPut + conflicts + removed)
+    }
+}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt
new file mode 100644
index 0000000..98d7ee6
--- /dev/null
+++ b/collection/collection/src/jvmTest/kotlin/androidx/collection/LruCacheTest.kt
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.collection
+
+import kotlin.test.Test
+import kotlin.test.assertContentEquals
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNull
+
+internal class LruCacheTest {
+
+    private var expectedCreateCount = 0
+    private var expectedPutCount = 0
+    private var expectedHitCount = 0
+    private var expectedMissCount = 0
+    private var expectedEvictionCount = 0
+
+    @Test
+    fun testStatistics() {
+        val cache = LruCache<String, String>(3)
+        assertStatistics(cache)
+        assertNull(cache.put("a", "A"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertSnapshot(cache, "a", "A")
+        assertNull(cache.put("b", "B"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertHit(cache, "b", "B")
+        assertSnapshot(cache, "a", "A", "b", "B")
+        assertNull(cache.put("c", "C"))
+        expectedPutCount++
+        assertStatistics(cache)
+        assertHit(cache, "a", "A")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "a", "A", "b", "B", "c", "C")
+        assertNull(cache.put("d", "D"))
+        expectedPutCount++
+        expectedEvictionCount++ // a should have been evicted
+        assertStatistics(cache)
+        assertMiss(cache, "a")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertHit(cache, "d", "D")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "d", "D", "b", "B", "c", "C")
+        assertNull(cache.put("e", "E"))
+        expectedPutCount++
+        expectedEvictionCount++ // d should have been evicted
+        assertStatistics(cache)
+        assertMiss(cache, "d")
+        assertMiss(cache, "a")
+        assertHit(cache, "e", "E")
+        assertHit(cache, "b", "B")
+        assertHit(cache, "c", "C")
+        assertSnapshot(cache, "e", "E", "b", "B", "c", "C")
+    }
+
+    @Test
+    fun testStatisticsWithCreate() {
+        val cache = newCreatingCache()
+        assertStatistics(cache)
+        assertCreated(cache, "aa", "created-aa")
+        assertHit(cache, "aa", "created-aa")
+        assertSnapshot(cache, "aa", "created-aa")
+        assertCreated(cache, "bb", "created-bb")
+        assertMiss(cache, "c")
+        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb")
+        assertCreated(cache, "cc", "created-cc")
+        assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc")
+        expectedEvictionCount++ // aa will be evicted
+        assertCreated(cache, "dd", "created-dd")
+        assertSnapshot(cache, "bb", "created-bb", "cc", "created-cc", "dd", "created-dd")
+        expectedEvictionCount++ // bb will be evicted
+        assertCreated(cache, "aa", "created-aa")
+        assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa")
+    }
+
+    @Test
+    fun testCreateOnCacheMiss() {
+        val cache = newCreatingCache()
+        val created = cache["aa"]
+        assertEquals("created-aa", created)
+    }
+
+    @Test
+    fun testNoCreateOnCacheHit() {
+        val cache = newCreatingCache()
+        cache.put("aa", "put-aa")
+        assertEquals("put-aa", cache["aa"])
+    }
+
+    @Test
+    fun testConstructorDoesNotAllowZeroCacheSize() {
+        assertFailsWith<IllegalArgumentException> {
+            LruCache<String, String>(0)
+        }
+    }
+
+    @Test
+    fun testToString() {
+        val cache = LruCache<String, String>(3)
+        assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString())
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("d", "D")
+        cache["a"] // miss
+        cache["b"] // hit
+        cache["c"] // hit
+        cache["d"] // hit
+        cache["e"] // miss
+        assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString())
+    }
+
+    @Test
+    fun testEvictionWithSingletonCache() {
+        val cache = LruCache<String, String>(1)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        assertSnapshot(cache, "b", "B")
+    }
+
+    @Test
+    fun testEntryEvictedWhenFull() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        assertContentEquals(emptyList(), log)
+        cache.put("d", "D")
+        assertContentEquals(listOf("a=A"), log)
+    }
+
+    /**
+     * Replacing the value for a key doesn't cause an eviction but it does bring
+     * the replaced entry to the front of the queue.
+     */
+    @Test
+    fun testPutCauseEviction() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.put("b", "B2")
+        assertContentEquals(listOf("b=B>B2"), log)
+        assertSnapshot(cache, "a", "A", "c", "C", "b", "B2")
+    }
+
+    @Test
+    fun testCustomSizesImpactsSize() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int =
+                    key.length + value.length
+            }
+        assertEquals(0, cache.size())
+        cache.put("a", "AA")
+        assertEquals(3, cache.size())
+        cache.put("b", "BBBB")
+        assertEquals(8, cache.size())
+        cache.put("a", "")
+        assertEquals(6, cache.size())
+    }
+
+    @Test
+    fun testEvictionWithCustomSizes() {
+        val cache =
+            object : LruCache<String, String>(4) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "AAAA")
+        assertSnapshot(cache, "a", "AAAA")
+        cache.put("b", "BBBB") // should evict a
+        assertSnapshot(cache, "b", "BBBB")
+        cache.put("c", "CC") // should evict b
+        assertSnapshot(cache, "c", "CC")
+        cache.put("d", "DD")
+        assertSnapshot(cache, "c", "CC", "d", "DD")
+        cache.put("e", "E") // should evict c
+        assertSnapshot(cache, "d", "DD", "e", "E")
+        cache.put("f", "F")
+        assertSnapshot(cache, "d", "DD", "e", "E", "f", "F")
+        cache.put("g", "G") // should evict d
+        assertSnapshot(cache, "e", "E", "f", "F", "g", "G")
+        cache.put("h", "H")
+        assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H")
+        cache.put("i", "III") // should evict e, f, and g
+        assertSnapshot(cache, "h", "H", "i", "III")
+        cache.put("j", "JJJ") // should evict h and i
+        assertSnapshot(cache, "j", "JJJ")
+    }
+
+    @Test
+    fun testEvictionThrowsWhenSizesAreInconsistent() {
+        val cache = object : LruCache<String, IntArray>(4) {
+            override fun sizeOf(key: String, value: IntArray): Int = value[0]
+        }
+        val a = intArrayOf(4)
+        cache.put("a", a)
+        // get the cache size out of sync
+        a[0] = 1
+        assertEquals(4, cache.size())
+        // evict something
+        assertFailsWith<IllegalStateException> {
+            cache.put("b", intArrayOf(2))
+        }
+    }
+
+    @Test
+    fun testEvictionThrowsWhenSizesAreNegative() {
+        val cache =
+            object : LruCache<String, String>(4) {
+                override fun sizeOf(key: String, value: String): Int = -1
+            }
+        assertFailsWith<IllegalStateException> {
+            cache.put("a", "A")
+        }
+    }
+
+    /**
+     * Naive caches evict at most one element at a time. This is problematic
+     * because evicting a small element may be insufficient to make room for a
+     * large element.
+     */
+    @Test
+    fun testDifferentElementSizes() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "1")
+        cache.put("b", "12345678")
+        cache.put("c", "1")
+        assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1")
+        cache.put("d", "12345678") // should evict a and b
+        assertSnapshot(cache, "c", "1", "d", "12345678")
+        cache.put("e", "12345678") // should evict c and d
+        assertSnapshot(cache, "e", "12345678")
+    }
+
+    @Test
+    fun testEvictAll() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.put("c", "C")
+        cache.evictAll()
+        assertEquals(0, cache.size())
+        assertContentEquals(listOf("a=A", "b=B", "c=C"), log)
+    }
+
+    @Test
+    fun testEvictAllEvictsSizeZeroElements() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = 0
+            }
+        cache.put("a", "A")
+        cache.put("b", "B")
+        cache.evictAll()
+        assertSnapshot(cache)
+    }
+
+    @Test
+    fun testRemoveWithCustomSizes() {
+        val cache =
+            object : LruCache<String, String>(10) {
+                override fun sizeOf(key: String, value: String): Int = value.length
+            }
+        cache.put("a", "123456")
+        cache.put("b", "1234")
+        cache.remove("a")
+        assertEquals(4, cache.size())
+    }
+
+    @Test
+    fun testRemoveAbsentElement() {
+        val cache = LruCache<String, String>(10)
+        cache.put("a", "A")
+        cache.put("b", "B")
+        assertNull(cache.remove("c"))
+        assertEquals(2, cache.size())
+    }
+
+    @Test
+    fun testRemoveCallsEntryRemoved() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.remove("a")
+        assertContentEquals(listOf("a=A>null"), log)
+    }
+
+    @Test
+    fun testPutCallsEntryRemoved() {
+        val log = ArrayList<String>()
+        val cache = newRemovalLogCache(log)
+        cache.put("a", "A")
+        cache.put("a", "A2")
+        assertContentEquals(listOf("a=A>A2"), log)
+    }
+
+    /**
+     * Test what happens when a value is added to the map while create is
+     * working. The map value should be returned by get(), and the created value
+     * should be released with entryRemoved().
+     */
+    @Test
+    fun testCreateWithConcurrentPut() {
+        val log = java.util.ArrayList<String>()
+        val cache =
+            object : LruCache<String, String>(3) {
+                override fun create(key: String): String {
+                    put(key, "B")
+                    return "A"
+                }
+
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: String,
+                    newValue: String?
+                ) {
+                    log.add("$key=$oldValue>$newValue")
+                }
+            }
+        assertEquals("B", cache["a"])
+        assertContentEquals(listOf("a=A>B"), log)
+    }
+
+    /**
+     * Test what happens when two creates happen concurrently. The result from
+     * the first create to return is returned by both gets. The other created
+     * values should be released with entryRemove().
+     */
+    @Test
+    fun testCreateWithConcurrentCreate() {
+        val log = ArrayList<String>()
+        val cache =
+            object : LruCache<String, Int>(3) {
+                var mCallCount = 0
+
+                override fun create(key: String): Int =
+                    if (mCallCount++ == 0) {
+                        assertEquals(2, get(key))
+                        1
+                    } else {
+                        2
+                    }
+
+                override fun entryRemoved(
+                    evicted: Boolean,
+                    key: String,
+                    oldValue: Int,
+                    newValue: Int?
+                ) {
+                    log.add("$key=$oldValue>$newValue")
+                }
+            }
+        assertEquals(2, cache["a"])
+        assertContentEquals(listOf("a=1>2"), log)
+    }
+
+    private fun newCreatingCache(): LruCache<String, String> =
+        object : LruCache<String, String>(3) {
+            override fun create(key: String): String? =
+                if (key.length > 1) "created-$key" else null
+        }
+
+    private fun newRemovalLogCache(log: MutableList<String>): LruCache<String, String> =
+        object : LruCache<String, String>(3) {
+            override fun entryRemoved(
+                evicted: Boolean,
+                key: String,
+                oldValue: String,
+                newValue: String?
+            ) {
+                log += if (evicted) "$key=$oldValue" else "$key=$oldValue>$newValue"
+            }
+        }
+
+    private fun assertHit(cache: LruCache<String, String>, key: String, value: String) {
+        assertEquals(value, cache[key])
+        expectedHitCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertMiss(cache: LruCache<String, String>, key: String) {
+        assertEquals(null, cache[key])
+        expectedMissCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertCreated(cache: LruCache<String, String>, key: String, value: String) {
+        assertEquals(value, cache[key])
+        expectedMissCount++
+        expectedCreateCount++
+        assertStatistics(cache)
+    }
+
+    private fun assertStatistics(cache: LruCache<*, *>) {
+        assertEquals(expectedCreateCount, cache.createCount(), "create count")
+        assertEquals(expectedPutCount, cache.putCount(), "put count")
+        assertEquals(expectedHitCount, cache.hitCount(), "hit count")
+        assertEquals(expectedMissCount, cache.missCount(), "miss count")
+        assertEquals(expectedEvictionCount, cache.evictionCount(), "eviction count")
+    }
+
+    private fun <T : Any> assertSnapshot(cache: LruCache<T, T>, vararg keysAndValues: T) {
+        val actualKeysAndValues = cache.snapshot().flatMap { (key, value) -> listOf(key, value) }
+        // assert using lists because order is important for LRUs
+        assertContentEquals(keysAndValues.asList(), actualKeysAndValues)
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt b/collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
similarity index 60%
copy from health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
copy to collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
index e2d1362..678d982 100644
--- a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
+++ b/collection/collection/src/nativeMain/kotlin/androidx/collection/CollectionPlatformUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.platform.client.error
+package androidx.collection
 
 /**
- * Exception thrown by Health Platform. Contains one of [ErrorCode]s and message with details on the
- * error.
+ * Native actual of internal utils for handling target differences in collection code.
  */
-open class HealthDataException(val errorCode: Int, errorMessage: String? = "") :
-    Exception("$errorCode: $errorMessage")
+internal actual object CollectionPlatformUtils {
+
+    internal actual inline fun createIndexOutOfBoundsException(): IndexOutOfBoundsException {
+        return ArrayIndexOutOfBoundsException()
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/gestures/AndroidScrollable.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/gestures/AndroidScrollable.android.kt
index 063ce02..dfff476 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/gestures/AndroidScrollable.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/gestures/AndroidScrollable.android.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.fastFold
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.PointerEvent
 import androidx.compose.ui.unit.Density
@@ -28,7 +27,6 @@
 @Composable
 internal actual fun platformScrollConfig(): ScrollConfig = AndroidConfig
 
-@OptIn(ExperimentalComposeUiApi::class)
 private object AndroidConfig : ScrollConfig {
     override fun Density.calculateMouseWheelScroll(event: PointerEvent, bounds: IntSize): Offset {
         // 64 dp value is taken from ViewConfiguration.java, replace with better solution
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
index 2e23bf6..1f25b23 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
@@ -17,7 +17,6 @@
 package androidx.compose.foundation
 
 import androidx.compose.runtime.remember
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.layout.LayoutCoordinates
@@ -45,7 +44,6 @@
  * Note that there may be some cases where the focused bounds change but the callback is _not_
  * invoked, but the last [LayoutCoordinates] will always return the most up-to-date bounds.
  */
-@OptIn(ExperimentalComposeUiApi::class)
 @ExperimentalFoundationApi
 fun Modifier.onFocusedBoundsChanged(onPositioned: (LayoutCoordinates?) -> Unit): Modifier =
     composed(
@@ -57,7 +55,6 @@
         remember(onPositioned) { FocusedBoundsObserverModifier(onPositioned) }
     }
 
-@OptIn(ExperimentalFoundationApi::class)
 private class FocusedBoundsObserverModifier(
     private val handler: (LayoutCoordinates?) -> Unit
 ) : ModifierLocalConsumer,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
index 9beb190..531f018 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionMagnifier.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.geometry.Offset
@@ -61,7 +60,6 @@
  * The text magnifier follows horizontal dragging exactly, but is vertically clamped to the current
  * line, so when it changes lines we animate it.
  */
-@OptIn(ExperimentalComposeUiApi::class)
 @Suppress("ModifierInspectorInfo")
 internal fun Modifier.animatedSelectionMagnifier(
     magnifierCenter: () -> Offset,
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/gestures/DesktopScrollable.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/gestures/DesktopScrollable.desktop.kt
index f7e47e9..6314814 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/gestures/DesktopScrollable.desktop.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/gestures/DesktopScrollable.desktop.kt
@@ -20,7 +20,6 @@
 import androidx.compose.foundation.fastFold
 import androidx.compose.foundation.DesktopPlatform
 import androidx.compose.runtime.compositionLocalOf
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.geometry.Offset
@@ -103,6 +102,5 @@
     get() =
         (mouseEvent as? MouseWheelEvent)?.scrollType == MouseWheelEvent.WHEEL_BLOCK_SCROLL
 
-@OptIn(ExperimentalComposeUiApi::class)
 private val PointerEvent.totalScrollDelta
     get() = this.changes.fastFold(Offset.Zero) { acc, c -> acc + c.scrollDelta }
\ No newline at end of file
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index 05448b4..5239032 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -96,10 +96,10 @@
 import androidx.compose.material3.samples.TextButtonSample
 import androidx.compose.material3.samples.TextFieldSample
 import androidx.compose.material3.samples.TextFieldWithErrorState
-import androidx.compose.material3.samples.TextFieldWithHelperMessage
 import androidx.compose.material3.samples.TextFieldWithHideKeyboardOnImeAction
 import androidx.compose.material3.samples.TextFieldWithIcons
 import androidx.compose.material3.samples.TextFieldWithPlaceholder
+import androidx.compose.material3.samples.TextFieldWithSupportingText
 import androidx.compose.material3.samples.TextTabs
 import androidx.compose.material3.samples.TriStateCheckboxSample
 import androidx.compose.runtime.Composable
@@ -684,11 +684,11 @@
         TextFieldWithErrorState()
     },
     Example(
-        name = ::TextFieldWithHelperMessage.name,
+        name = ::TextFieldWithSupportingText.name,
         description = TextFieldsExampleDescription,
         sourceUrl = TextFieldsExampleSourceUrl
     ) {
-        TextFieldWithHelperMessage()
+        TextFieldWithSupportingText()
     },
     Example(
         name = ::PasswordTextField.name,
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
index 4bd25b0..ec9f8e4 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
@@ -48,6 +48,7 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.vector.ImageVector
@@ -117,33 +118,43 @@
 @Sampled
 @Composable
 fun TextFieldWithErrorState() {
+    val errorMessage = "Email format is invalid"
     var text by rememberSaveable { mutableStateOf("") }
     var isError by rememberSaveable { mutableStateOf(false) }
 
     fun validate(text: String) {
-        isError = text.count() < 5
+        isError = !text.contains('@')
     }
 
-    TextField(
-        value = text,
-        onValueChange = {
-            text = it
-            isError = false
-        },
-        singleLine = true,
-        label = { Text(if (isError) "Email*" else "Email") },
-        isError = isError,
-        keyboardActions = KeyboardActions { validate(text) },
-        modifier = Modifier.semantics {
-            // Provide localized description of the error
-            if (isError) error("Email format is invalid.")
-        }
-    )
+    Column {
+        TextField(
+            value = text,
+            onValueChange = {
+                text = it
+                isError = false
+            },
+            singleLine = true,
+            label = { Text(if (isError) "Email*" else "Email") },
+            isError = isError,
+            keyboardActions = KeyboardActions { validate(text) },
+            modifier = Modifier.semantics {
+                // Provide localized description of the error
+                if (isError) error(errorMessage)
+            }
+        )
+        // Supporting text for error message.
+        Text(
+            text = errorMessage,
+            color = MaterialTheme.colorScheme.error,
+            style = MaterialTheme.typography.bodySmall,
+            modifier = Modifier.padding(start = 16.dp, top = 4.dp).alpha(if (isError) 1f else 0f)
+        )
+    }
 }
 
 @Sampled
 @Composable
-fun TextFieldWithHelperMessage() {
+fun TextFieldWithSupportingText() {
     var text by rememberSaveable { mutableStateOf("") }
 
     Column {
@@ -153,10 +164,10 @@
             label = { Text("Label") }
         )
         Text(
-            text = "Helper message",
+            text = "Supporting text",
             color = MaterialTheme.colorScheme.onSurface,
             style = MaterialTheme.typography.bodySmall,
-            modifier = Modifier.padding(start = 16.dp)
+            modifier = Modifier.padding(start = 16.dp, top = 4.dp)
         )
     }
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index 9759be1..262b681 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -94,7 +94,7 @@
  *
  * Additionally, you may provide additional message at the bottom:
  *
- * @sample androidx.compose.material3.samples.TextFieldWithHelperMessage
+ * @sample androidx.compose.material3.samples.TextFieldWithSupportingText
  *
  * Password text field example:
  *
diff --git a/compose/ui/ui-text-google-fonts/src/androidTest/java/androidx/compose/ui/text/googlefonts/GoogleFontTest.kt b/compose/ui/ui-text-google-fonts/src/androidTest/java/androidx/compose/ui/text/googlefonts/GoogleFontTest.kt
index befcaaa..c90b100 100644
--- a/compose/ui/ui-text-google-fonts/src/androidTest/java/androidx/compose/ui/text/googlefonts/GoogleFontTest.kt
+++ b/compose/ui/ui-text-google-fonts/src/androidTest/java/androidx/compose/ui/text/googlefonts/GoogleFontTest.kt
@@ -104,7 +104,7 @@
     @Test
     fun GoogleFontImpl_fontRequest_containsName() {
         val font = Font(GoogleFont("Test Name"), TestProvider) as GoogleFontImpl
-        assertThat(font.toFontRequest().query).contains("name=Test+Name")
+        assertThat(font.toFontRequest().query).contains("name=Test Name")
     }
 
     @Test
diff --git a/compose/ui/ui-text-google-fonts/src/main/java/androidx/compose/ui/text/googlefonts/GoogleFont.kt b/compose/ui/ui-text-google-fonts/src/main/java/androidx/compose/ui/text/googlefonts/GoogleFont.kt
index 37b891f..fad21c6 100644
--- a/compose/ui/ui-text-google-fonts/src/main/java/androidx/compose/ui/text/googlefonts/GoogleFont.kt
+++ b/compose/ui/ui-text-google-fonts/src/main/java/androidx/compose/ui/text/googlefonts/GoogleFont.kt
@@ -154,9 +154,7 @@
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
-            if (javaClass != other?.javaClass) return false
-
-            other as Provider
+            if (other !is Provider) return false
 
             if (providerAuthority != other.providerAuthority) return false
             if (providerPackage != other.providerPackage) return false
@@ -199,19 +197,20 @@
     val bestEffort: Boolean
 ) : AndroidFont(FontLoadingStrategy.Async, GoogleFontTypefaceLoader) {
     fun toFontRequest(): FontRequest {
-        val query = "name=${name.encode()}&weight=${weight.weight}" +
+        // note: name is not encoded or quoted per spec
+        val query = "name=$name&weight=${weight.weight}" +
             "&italic=${style.toQueryParam()}&besteffort=${bestEffortQueryParam()}"
 
         val certs = fontProvider.certificates
-        if (certs != null) {
-            return FontRequest(
+        return if (certs != null) {
+            FontRequest(
                 fontProvider.providerAuthority,
                 fontProvider.providerPackage,
                 query,
                 certs
             )
         } else {
-            return FontRequest(
+            FontRequest(
                 fontProvider.providerAuthority,
                 fontProvider.providerPackage,
                 query,
@@ -239,6 +238,28 @@
         return "Font(GoogleFont(\"$name\", bestEffort=$bestEffort), weight=$weight, " +
             "style=$style)"
     }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is GoogleFontImpl) return false
+
+        if (name != other.name) return false
+        if (fontProvider != other.fontProvider) return false
+        if (weight != other.weight) return false
+        if (style != other.style) return false
+        if (bestEffort != other.bestEffort) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = name.hashCode()
+        result = 31 * result + fontProvider.hashCode()
+        result = 31 * result + weight.hashCode()
+        result = 31 * result + style.hashCode()
+        result = 31 * result + bestEffort.hashCode()
+        return result
+    }
 }
 
 @ExperimentalTextApi
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index b88ba41..6f31cea 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2583,8 +2583,6 @@
   }
 
   public final class StringResources_androidKt {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String![] stringArrayResource(@ArrayRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id, java.lang.Object... formatArgs);
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 491844a50..9f886e0 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2776,8 +2776,8 @@
   }
 
   public final class StringResources_androidKt {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable @androidx.compose.ui.ExperimentalComposeUiApi public static String pluralStringResource(@PluralsRes int id, int count);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable @androidx.compose.ui.ExperimentalComposeUiApi public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String![] stringArrayResource(@ArrayRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id, java.lang.Object... formatArgs);
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index cec1877..aee9a4a 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2619,8 +2619,6 @@
   }
 
   public final class StringResources_androidKt {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String pluralStringResource(@PluralsRes int id, int count, java.lang.Object... formatArgs);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String![] stringArrayResource(@ArrayRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static String stringResource(@StringRes int id, java.lang.Object... formatArgs);
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/res/StringResourcesTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/res/StringResourcesTest.kt
index 3f84304..4b67de4e 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/res/StringResourcesTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/res/StringResourcesTest.kt
@@ -17,6 +17,7 @@
 package androidx.compose.ui.res
 
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.test.R
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -175,6 +176,7 @@
         }
     }
 
+    @OptIn(ExperimentalComposeUiApi::class)
     @Test
     fun pluralStringResource_withoutArguments() {
         val context = InstrumentationRegistry.getInstrumentation().targetContext
@@ -189,6 +191,7 @@
         }
     }
 
+    @OptIn(ExperimentalComposeUiApi::class)
     @Test
     fun pluralStringResource_withArguments() {
         val context = InstrumentationRegistry.getInstrumentation().targetContext
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/StringResources.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/StringResources.android.kt
index 98f0e0b..57f3561 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/StringResources.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/StringResources.android.kt
@@ -22,6 +22,7 @@
 import androidx.annotation.StringRes
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalContext
 
@@ -72,6 +73,7 @@
  * @param count the count
  * @return the pluralized string data associated with the resource
  */
+@ExperimentalComposeUiApi
 @Composable
 @ReadOnlyComposable
 fun pluralStringResource(@PluralsRes id: Int, count: Int): String {
@@ -87,6 +89,7 @@
  * @param formatArgs arguments used in the format string
  * @return the pluralized string data associated with the resource
  */
+@ExperimentalComposeUiApi
 @Composable
 @ReadOnlyComposable
 fun pluralStringResource(@PluralsRes id: Int, count: Int, vararg formatArgs: Any): String {
diff --git a/fragment/fragment/api/1.5.0-beta01.txt b/fragment/fragment/api/1.5.0-beta01.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/1.5.0-beta01.txt
+++ b/fragment/fragment/api/1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt b/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
+++ b/fragment/fragment/api/public_plus_experimental_1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index 0a55a9e..32377c9 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/restricted_1.5.0-beta01.txt b/fragment/fragment/api/restricted_1.5.0-beta01.txt
index 9e7cc35..7f0aa7c 100644
--- a/fragment/fragment/api/restricted_1.5.0-beta01.txt
+++ b/fragment/fragment/api/restricted_1.5.0-beta01.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 9e7cc35..7f0aa7c 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -6,6 +6,7 @@
     ctor public DialogFragment(@LayoutRes int);
     method public void dismiss();
     method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
     method public android.app.Dialog? getDialog();
     method public boolean getShowsDialog();
     method @StyleRes public int getTheme();
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
index c582362..8ae92e1 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentDismissTest.kt
@@ -66,6 +66,12 @@
     }
 }
 
+object FragmentDismissNow : Operation() {
+    override fun run(dialogFragment: DialogFragment) {
+        dialogFragment.dismissNow()
+    }
+}
+
 @LargeTest
 @RunWith(Parameterized::class)
 class DialogFragmentDismissTest(
@@ -87,6 +93,8 @@
                 // Run the operation off the main thread
                 add(arrayOf(operation, false))
             }
+            // dismissNow can only be run on the main thread
+            add(arrayOf(FragmentDismissNow, true))
         }
     }
 
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
index 92ec098..dfd3fbc 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
@@ -113,6 +113,27 @@
 
     @UiThreadTest
     @Test
+    fun testDialogFragmentDismissNow() {
+        val fragment = TestDialogFragment()
+        fragment.show(activityTestRule.activity.supportFragmentManager, null)
+        activityTestRule.runOnUiThread {
+            activityTestRule.activity.supportFragmentManager.executePendingTransactions()
+        }
+
+        val dialog = fragment.dialog
+        assertWithMessage("Dialog was not being shown")
+            .that(dialog?.isShowing)
+            .isTrue()
+
+        fragment.dismissNow()
+
+        assertWithMessage("Dialog should be removed")
+            .that(dialog?.isShowing)
+            .isFalse()
+    }
+
+    @UiThreadTest
+    @Test
     fun testDialogFragmentDismissAllowingStateLoss() {
         val viewModelStore = ViewModelStore()
         val fc = activityTestRule.startupFragmentController(viewModelStore)
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
index 1477da4..7cf9874 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
@@ -307,7 +307,16 @@
      * the fragment.
      */
     public void dismiss() {
-        dismissInternal(false, false);
+        dismissInternal(false, false, false);
+    }
+
+    /**
+     * Version of {@link #dismiss()} that uses {@link FragmentTransaction#commitNow()}.
+     * See linked documentation for further details.
+     */
+    @MainThread
+    public void dismissNow() {
+        dismissInternal(false, false, true);
     }
 
     /**
@@ -317,10 +326,10 @@
      * documentation for further details.
      */
     public void dismissAllowingStateLoss() {
-        dismissInternal(true, false);
+        dismissInternal(true, false, false);
     }
 
-    private void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss) {
+    private void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss, boolean immediate) {
         if (mDismissed) {
             return;
         }
@@ -346,14 +355,22 @@
         }
         mViewDestroyed = true;
         if (mBackStackId >= 0) {
-            getParentFragmentManager().popBackStack(mBackStackId,
-                    FragmentManager.POP_BACK_STACK_INCLUSIVE, allowStateLoss);
+            if (immediate) {
+                getParentFragmentManager().popBackStackImmediate(mBackStackId,
+                        FragmentManager.POP_BACK_STACK_INCLUSIVE);
+            } else {
+                getParentFragmentManager().popBackStack(mBackStackId,
+                        FragmentManager.POP_BACK_STACK_INCLUSIVE, allowStateLoss);
+            }
             mBackStackId = -1;
         } else {
             FragmentTransaction ft = getParentFragmentManager().beginTransaction();
             ft.setReorderingAllowed(true);
             ft.remove(this);
-            if (allowStateLoss) {
+            // allowStateLoss and immediate should not both be true
+            if (immediate) {
+                ft.commitNow();
+            } else if (allowStateLoss) {
                 ft.commitAllowingStateLoss();
             } else {
                 ft.commit();
@@ -633,7 +650,7 @@
             if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                 Log.d(TAG, "onDismiss called for DialogFragment " + this);
             }
-            dismissInternal(true, true);
+            dismissInternal(true, true, false);
         }
     }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 5c424fe..f598eae 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -105,6 +105,8 @@
  */
 public abstract class FragmentManager implements FragmentResultOwner {
     static final String SAVED_STATE_TAG = "android:support:fragments";
+    static final String FRAGMENT_MANAGER_STATE_TAG = "state";
+    static final String RESULT_NAME_PREFIX = "result_";
     private static boolean DEBUG = false;
 
     /** @hide */
@@ -2347,10 +2349,13 @@
             throwException(new IllegalStateException("You cannot use saveAllState when your "
                     + "FragmentHostCallback implements SavedStateRegistryOwner."));
         }
-        return saveAllStateInternal();
+        Bundle savedState = saveAllStateInternal();
+        return savedState.isEmpty() ? null : savedState;
     }
 
-    Parcelable saveAllStateInternal() {
+    @NonNull
+    Bundle saveAllStateInternal() {
+        Bundle bundle = new Bundle();
         // Make sure all pending operations have now been executed to get
         // our state update-to-date.
         forcePostponedTransactions();
@@ -2365,46 +2370,50 @@
 
         // And grab all FragmentState objects
         ArrayList<FragmentState> savedState = mFragmentStore.getAllSavedState();
-
         if (savedState.isEmpty()) {
-            if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "saveAllState: no fragments!");
-            return null;
-        }
+            if (isLoggingEnabled(Log.VERBOSE)) {
+                Log.v(TAG, "saveAllState: no fragments!");
+            }
+        } else {
+            // Build list of currently added fragments.
+            ArrayList<String> added = mFragmentStore.saveAddedFragments();
 
-        // Build list of currently added fragments.
-        ArrayList<String> added = mFragmentStore.saveAddedFragments();
-
-        // Now save back stack.
-        BackStackRecordState[] backStack = null;
-        if (mBackStack != null) {
-            int size = mBackStack.size();
-            if (size > 0) {
-                backStack = new BackStackRecordState[size];
-                for (int i = 0; i < size; i++) {
-                    backStack[i] = new BackStackRecordState(mBackStack.get(i));
-                    if (isLoggingEnabled(Log.VERBOSE)) {
-                        Log.v(TAG, "saveAllState: adding back stack #" + i
-                                + ": " + mBackStack.get(i));
+            // Now save back stack.
+            BackStackRecordState[] backStack = null;
+            if (mBackStack != null) {
+                int size = mBackStack.size();
+                if (size > 0) {
+                    backStack = new BackStackRecordState[size];
+                    for (int i = 0; i < size; i++) {
+                        backStack[i] = new BackStackRecordState(mBackStack.get(i));
+                        if (isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(TAG, "saveAllState: adding back stack #" + i
+                                    + ": " + mBackStack.get(i));
+                        }
                     }
                 }
             }
+
+            FragmentManagerState fms = new FragmentManagerState();
+            fms.mSavedState = savedState;
+            fms.mActive = active;
+            fms.mAdded = added;
+            fms.mBackStack = backStack;
+            fms.mBackStackIndex = mBackStackIndex.get();
+            if (mPrimaryNav != null) {
+                fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
+            }
+            fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
+            fms.mBackStackStates.addAll(mBackStackStates.values());
+            fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
+            bundle.putParcelable(FRAGMENT_MANAGER_STATE_TAG, fms);
+
+            for (String resultName : mResults.keySet()) {
+                bundle.putBundle(RESULT_NAME_PREFIX + resultName, mResults.get(resultName));
+            }
         }
 
-        FragmentManagerState fms = new FragmentManagerState();
-        fms.mSavedState = savedState;
-        fms.mActive = active;
-        fms.mAdded = added;
-        fms.mBackStack = backStack;
-        fms.mBackStackIndex = mBackStackIndex.get();
-        if (mPrimaryNav != null) {
-            fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
-        }
-        fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
-        fms.mBackStackStates.addAll(mBackStackStates.values());
-        fms.mResultKeys.addAll(mResults.keySet());
-        fms.mResults.addAll(mResults.values());
-        fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
-        return fms;
+        return bundle;
     }
 
     @SuppressWarnings("deprecation")
@@ -2425,11 +2434,25 @@
         restoreSaveStateInternal(state);
     }
 
+    @SuppressWarnings("deprecation")
     void restoreSaveStateInternal(@Nullable Parcelable state) {
         // If there is no saved state at all, then there's nothing else to do
         if (state == null) return;
-        FragmentManagerState fms = (FragmentManagerState) state;
-        if (fms.mSavedState == null) return;
+        Bundle bundle = (Bundle) state;
+
+        for (String bundleKey : bundle.keySet()) {
+            if (bundleKey.startsWith(RESULT_NAME_PREFIX)) {
+                Bundle savedResult = bundle.getBundle(bundleKey);
+                if (savedResult != null) {
+                    savedResult.setClassLoader(mHost.getContext().getClassLoader());
+                    String resultKey = bundleKey.substring(RESULT_NAME_PREFIX.length());
+                    mResults.put(resultKey, savedResult);
+                }
+            }
+        }
+
+        FragmentManagerState fms = bundle.getParcelable(FRAGMENT_MANAGER_STATE_TAG);
+        if (fms == null || fms.mSavedState == null) return;
 
         // Restore the saved state of all fragments
         mFragmentStore.restoreSaveState(fms.mSavedState);
@@ -2526,14 +2549,6 @@
             }
         }
 
-        ArrayList<String> savedResultKeys = fms.mResultKeys;
-        if (savedResultKeys != null) {
-            for (int i = 0; i < savedResultKeys.size(); i++) {
-                Bundle savedResult = fms.mResults.get(i);
-                savedResult.setClassLoader(mHost.getContext().getClassLoader());
-                mResults.put(savedResultKeys.get(i), savedResult);
-            }
-        }
         mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
     }
 
@@ -2614,20 +2629,14 @@
             SavedStateRegistry registry =
                     ((SavedStateRegistryOwner) mHost).getSavedStateRegistry();
             registry.registerSavedStateProvider(SAVED_STATE_TAG, () -> {
-                        Bundle outState = new Bundle();
-                        Parcelable p = saveAllStateInternal();
-                        if (p != null) {
-                            outState.putParcelable(SAVED_STATE_TAG, p);
-                        }
-                        return outState;
+                        return saveAllStateInternal();
                     }
             );
 
             Bundle savedInstanceState = registry
                     .consumeRestoredStateForKey(SAVED_STATE_TAG);
             if (savedInstanceState != null) {
-                Parcelable p = savedInstanceState.getParcelable(SAVED_STATE_TAG);
-                restoreSaveStateInternal(p);
+                restoreSaveStateInternal(savedInstanceState);
             }
         }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
index a90909a..117e31c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManagerState.java
@@ -17,7 +17,6 @@
 package androidx.fragment.app;
 
 import android.annotation.SuppressLint;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -33,8 +32,6 @@
     String mPrimaryNavActiveWho = null;
     ArrayList<String> mBackStackStateKeys = new ArrayList<>();
     ArrayList<BackStackState> mBackStackStates = new ArrayList<>();
-    ArrayList<String> mResultKeys = new ArrayList<>();
-    ArrayList<Bundle> mResults = new ArrayList<>();
     ArrayList<FragmentManager.LaunchedFragmentInfo> mLaunchedFragments;
 
     public FragmentManagerState() {
@@ -49,8 +46,6 @@
         mPrimaryNavActiveWho = in.readString();
         mBackStackStateKeys = in.createStringArrayList();
         mBackStackStates = in.createTypedArrayList(BackStackState.CREATOR);
-        mResultKeys = in.createStringArrayList();
-        mResults = in.createTypedArrayList(Bundle.CREATOR);
         mLaunchedFragments = in.createTypedArrayList(FragmentManager.LaunchedFragmentInfo.CREATOR);
     }
 
@@ -69,8 +64,6 @@
         dest.writeString(mPrimaryNavActiveWho);
         dest.writeStringList(mBackStackStateKeys);
         dest.writeTypedList(mBackStackStates);
-        dest.writeStringList(mResultKeys);
-        dest.writeTypedList(mResults);
         dest.writeTypedList(mLaunchedFragments);
     }
 
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index f426772..431a244 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -13,6 +13,7 @@
          <trust group="^com[.]android($|([.].*))" regex="true"/> <!-- b/215430394 -->
          <trust group="com.google.testing.platform"/> <!-- b/215430394 -->
          <trust group="com.google.android.gms"/> <!-- b/215442095 -->
+         <trust file=".*kotlin-native-prebuilt-macos-.*" regex="true"/> <!-- b/228184608 -->
       </trusted-artifacts>
       <trusted-keys>
          <trusted-key id="00089ee8c3afa95a854d0f1df800dd0933ecf7f7" group="com.google.guava" name="guava"/>
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
index 0cb371e..29f46ee 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
@@ -33,7 +33,7 @@
 import androidx.health.data.client.records.Distance
 import androidx.health.data.client.records.ElevationGained
 import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
+import androidx.health.data.client.records.HeartRateSeries
 import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
 import androidx.health.data.client.records.HeartRateVariabilityRmssd
 import androidx.health.data.client.records.HeartRateVariabilityS
@@ -52,6 +52,7 @@
 import androidx.health.data.client.records.OvulationTest
 import androidx.health.data.client.records.OxygenSaturation
 import androidx.health.data.client.records.Power
+import androidx.health.data.client.records.Record
 import androidx.health.data.client.records.Repetitions
 import androidx.health.data.client.records.RespiratoryRate
 import androidx.health.data.client.records.RestingHeartRate
@@ -67,6 +68,7 @@
 import androidx.health.data.client.records.WaistCircumference
 import androidx.health.data.client.records.Weight
 import androidx.health.data.client.records.WheelchairPushes
+import kotlin.reflect.KClass
 
 private val ALL_RECORDS_TYPES =
     setOf(
@@ -88,7 +90,7 @@
         Distance::class,
         ElevationGained::class,
         FloorsClimbed::class,
-        HeartRate::class,
+        HeartRateSeries::class,
         HeartRateVariabilityDifferentialIndex::class,
         HeartRateVariabilityRmssd::class,
         HeartRateVariabilityS::class,
@@ -124,4 +126,5 @@
         Weight::class,
     )
 
-val RECORDS_TYPE_NAME_MAP = ALL_RECORDS_TYPES.associateBy { it.simpleName!! }
+val RECORDS_TYPE_NAME_MAP: Map<String, KClass<out Record>> =
+    ALL_RECORDS_TYPES.associateBy { it.simpleName!! }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
index 7eed099..bfefa93 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
@@ -34,6 +34,7 @@
 import androidx.health.data.client.records.ElevationGained
 import androidx.health.data.client.records.FloorsClimbed
 import androidx.health.data.client.records.HeartRate
+import androidx.health.data.client.records.HeartRateSeries
 import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
 import androidx.health.data.client.records.HeartRateVariabilityRmssd
 import androidx.health.data.client.records.HeartRateVariabilityS
@@ -69,11 +70,11 @@
 import androidx.health.data.client.records.Weight
 import androidx.health.data.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
-import java.lang.RuntimeException
+import java.time.Instant
 
 /** Converts public API object into internal proto for ipc. */
-fun toRecord(proto: DataProto.DataPoint): Record {
-    return with(proto) {
+fun toRecord(proto: DataProto.DataPoint): Record =
+    with(proto) {
         when (dataType.name) {
             "BasalBodyTemperature" ->
                 BasalBodyTemperature(
@@ -163,12 +164,20 @@
                     zoneOffset = zoneOffset,
                     metadata = metadata
                 )
-            "HeartRate" ->
-                HeartRate(
-                    beatsPerMinute = getLong("bpm"),
-                    time = time,
-                    zoneOffset = zoneOffset,
-                    metadata = metadata
+            "HeartRateSeries" ->
+                HeartRateSeries(
+                    startTime = startTime,
+                    startZoneOffset = startZoneOffset,
+                    endTime = endTime,
+                    endZoneOffset = endZoneOffset,
+                    samples =
+                        seriesValuesList.map { value ->
+                            HeartRate(
+                                time = Instant.ofEpochMilli(value.instantTimeMillis),
+                                beatsPerMinute = value.getLong("bpm"),
+                            )
+                        },
+                    metadata = metadata,
                 )
             "Height" ->
                 Height(
@@ -533,4 +542,3 @@
             else -> throw RuntimeException("Unknown data type ${dataType.name}")
         }
     }
-}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt
index 4ad70d8..bbd4a24 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordUtils.kt
@@ -19,52 +19,60 @@
 import androidx.health.data.client.metadata.Device
 import androidx.health.data.client.metadata.Metadata
 import androidx.health.platform.client.proto.DataProto
+import androidx.health.platform.client.proto.DataProto.DataPointOrBuilder
+import androidx.health.platform.client.proto.DataProto.SeriesValueOrBuilder
 import java.time.Instant
 import java.time.ZoneOffset
 
 /** Internal helper functions to convert proto to records. */
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.startTime: Instant
     get() = Instant.ofEpochMilli(startTimeMillis)
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.endTime: Instant
     get() = Instant.ofEpochMilli(endTimeMillis)
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.time: Instant
     get() = Instant.ofEpochMilli(instantTimeMillis)
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.startZoneOffset: ZoneOffset?
     get() =
         if (hasStartZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(startZoneOffsetSeconds) else null
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.endZoneOffset: ZoneOffset?
     get() = if (hasEndZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(endZoneOffsetSeconds) else null
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+@get:SuppressWarnings("GoodTime") // HealthDataClientImplSafe to use for deserialization
 internal val DataProto.DataPoint.zoneOffset: ZoneOffset?
     get() = if (hasZoneOffsetSeconds()) ZoneOffset.ofTotalSeconds(zoneOffsetSeconds) else null
 
-internal fun DataProto.DataPoint.getLong(key: String, defaultVal: Long = 0): Long {
-    return valuesMap[key]?.longVal ?: defaultVal
-}
+internal fun DataPointOrBuilder.getLong(key: String, defaultVal: Long = 0): Long =
+    valuesMap[key]?.longVal ?: defaultVal
 
-internal fun DataProto.DataPoint.getDouble(key: String, defaultVal: Double = 0.0): Double {
-    return valuesMap[key]?.doubleVal ?: defaultVal
-}
+internal fun DataPointOrBuilder.getDouble(key: String, defaultVal: Double = 0.0): Double =
+    valuesMap[key]?.doubleVal ?: defaultVal
 
-internal fun DataProto.DataPoint.getString(key: String): String? {
-    return valuesMap[key]?.stringVal
-}
+internal fun DataPointOrBuilder.getString(key: String): String? = valuesMap[key]?.stringVal
 
-internal fun DataProto.DataPoint.getEnum(key: String): String? {
+internal fun DataPointOrBuilder.getEnum(key: String): String? {
     return valuesMap[key]?.enumVal
 }
 
-@get:SuppressWarnings("GoodTime", "NewApi") // Safe to use for deserialization
+internal fun SeriesValueOrBuilder.getLong(key: String, defaultVal: Long = 0): Long =
+    valuesMap[key]?.longVal ?: defaultVal
+
+internal fun SeriesValueOrBuilder.getDouble(key: String, defaultVal: Double = 0.0): Double =
+    valuesMap[key]?.doubleVal ?: defaultVal
+
+internal fun SeriesValueOrBuilder.getString(key: String): String? = valuesMap[key]?.stringVal
+
+internal fun SeriesValueOrBuilder.getEnum(key: String): String? = valuesMap[key]?.enumVal
+
+@get:SuppressWarnings("GoodTime") // Safe to use for deserialization
 internal val DataProto.DataPoint.metadata: Metadata
     get() =
         Metadata(
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
index 2b78f78..0d59e11 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
@@ -33,7 +33,7 @@
 import androidx.health.data.client.records.Distance
 import androidx.health.data.client.records.ElevationGained
 import androidx.health.data.client.records.FloorsClimbed
-import androidx.health.data.client.records.HeartRate
+import androidx.health.data.client.records.HeartRateSeries
 import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
 import androidx.health.data.client.records.HeartRateVariabilityRmssd
 import androidx.health.data.client.records.HeartRateVariabilityS
@@ -56,6 +56,7 @@
 import androidx.health.data.client.records.Repetitions
 import androidx.health.data.client.records.RespiratoryRate
 import androidx.health.data.client.records.RestingHeartRate
+import androidx.health.data.client.records.SeriesRecord
 import androidx.health.data.client.records.SexualActivity
 import androidx.health.data.client.records.SleepSession
 import androidx.health.data.client.records.SleepStage
@@ -69,12 +70,10 @@
 import androidx.health.data.client.records.Weight
 import androidx.health.data.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
-import java.lang.RuntimeException
 
 /** Converts public API object into internal proto for ipc. */
-@SuppressWarnings("NewApi") // Safe to use with java8 desugar
-fun Record.toProto(): DataProto.DataPoint {
-    return when (this) {
+fun Record.toProto(): DataProto.DataPoint =
+    when (this) {
         is BasalBodyTemperature ->
             instantaneousProto()
                 .setDataType(protoDataType("BasalBodyTemperature"))
@@ -153,11 +152,13 @@
                 .setDataType(protoDataType("CyclingPedalingCadence"))
                 .apply { putValues("rpm", doubleVal(revolutionsPerMinute)) }
                 .build()
-        is HeartRate ->
-            instantaneousProto()
-                .setDataType(protoDataType("HeartRate"))
-                .apply { putValues("bpm", longVal(beatsPerMinute)) }
-                .build()
+        is HeartRateSeries ->
+            toProto(dataTypeName = "HeartRateSeries") { sample ->
+                DataProto.SeriesValue.newBuilder()
+                    .putValues("bpm", longVal(sample.beatsPerMinute))
+                    .setInstantTimeMillis(sample.time.toEpochMilli())
+                    .build()
+            }
         is Height ->
             instantaneousProto()
                 .setDataType(protoDataType("Height"))
@@ -508,4 +509,16 @@
                 .build()
         else -> throw RuntimeException("Unsupported yet!")
     }
-}
+
+private fun <T : Any> SeriesRecord<T>.toProto(
+    dataTypeName: String,
+    getSeriesValue: (sample: T) -> DataProto.SeriesValue,
+): DataProto.DataPoint =
+    intervalProto()
+        .setDataType(protoDataType(dataTypeName = dataTypeName))
+        .apply {
+            for (sample in samples) {
+                addSeriesValues(getSeriesValue(sample))
+            }
+        }
+        .build()
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt
index a882c33..bb2802b 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoUtils.kt
@@ -25,7 +25,7 @@
 internal fun protoDataType(dataTypeName: String): DataProto.DataType =
     DataProto.DataType.newBuilder().setName(dataTypeName).build()
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 internal fun InstantaneousRecord.instantaneousProto(): DataProto.DataPoint.Builder {
     val builder =
         DataProto.DataPoint.newBuilder()
@@ -35,7 +35,7 @@
     return builder
 }
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 internal fun IntervalRecord.intervalProto(): DataProto.DataPoint.Builder {
     val builder =
         DataProto.DataPoint.newBuilder()
@@ -47,7 +47,7 @@
     return builder
 }
 
-@SuppressWarnings("GoodTime", "NewApi") // Suppress GoodTime for serialize/de-serialize.
+@SuppressWarnings("GoodTime") // Suppress GoodTime for serialize/de-serialize.
 private fun DataProto.DataPoint.Builder.setMetadata(metadata: Metadata) = apply {
     metadata.uid?.let { setUid(it) }
     if (metadata.dataOrigin.packageName.isNotEmpty()) {
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt
deleted file mode 100644
index 562d5e5..0000000
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRate.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.data.client.records
-
-import androidx.annotation.RestrictTo
-import androidx.health.data.client.aggregate.LongAggregateMetric
-import androidx.health.data.client.metadata.Metadata
-import java.time.Instant
-import java.time.ZoneOffset
-
-/** Captures the user's heart rate. Each record represents a single instantaneous measurement. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class HeartRate(
-    /** Heart beats per minute. Required field. Validation range: 1-300. */
-    public val beatsPerMinute: Long,
-    override val time: Instant,
-    override val zoneOffset: ZoneOffset?,
-    override val metadata: Metadata = Metadata.EMPTY,
-) : InstantaneousRecord {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is HeartRate) return false
-
-        if (beatsPerMinute != other.beatsPerMinute) return false
-        if (time != other.time) return false
-        if (zoneOffset != other.zoneOffset) return false
-        if (metadata != other.metadata) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + beatsPerMinute.hashCode()
-        result = 31 * result + time.hashCode()
-        result = 31 * result + (zoneOffset?.hashCode() ?: 0)
-        result = 31 * result + metadata.hashCode()
-        return result
-    }
-
-    companion object {
-        /** Metric identifier to retrieve average heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_AVG: LongAggregateMetric = LongAggregateMetric("HeartRate", "avg", "bpm")
-
-        /** Metric identifier to retrieve minimum heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_MIN: LongAggregateMetric = LongAggregateMetric("HeartRate", "min", "bpm")
-
-        /** Metric identifier to retrieve maximum heart rate from [AggregateDataRow]. */
-        @JvmStatic
-        val HEART_RATE_BPM_MAX: LongAggregateMetric = LongAggregateMetric("HeartRate", "max", "bpm")
-    }
-}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateSeries.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateSeries.kt
new file mode 100644
index 0000000..46a784f
--- /dev/null
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/HeartRateSeries.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.data.client.records
+
+import androidx.annotation.RestrictTo
+import androidx.health.data.client.aggregate.LongAggregateMetric
+import androidx.health.data.client.metadata.Metadata
+import java.time.Instant
+import java.time.ZoneOffset
+
+/** Captures the user's heart rate. Each record represents a series of measurements. */
+@RestrictTo(RestrictTo.Scope.LIBRARY) // Will be made public after API reviews
+public class HeartRateSeries(
+    override val startTime: Instant,
+    override val startZoneOffset: ZoneOffset?,
+    override val endTime: Instant,
+    override val endZoneOffset: ZoneOffset?,
+    override val samples: List<HeartRate>,
+    override val metadata: Metadata = Metadata.EMPTY,
+) : SeriesRecord<HeartRate> {
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is HeartRateSeries) return false
+
+        if (startTime != other.startTime) return false
+        if (startZoneOffset != other.startZoneOffset) return false
+        if (endTime != other.endTime) return false
+        if (endZoneOffset != other.endZoneOffset) return false
+        if (samples != other.samples) return false
+        if (metadata != other.metadata) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        var result = startTime.hashCode()
+        result = 31 * result + (startZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + endTime.hashCode()
+        result = 31 * result + (endZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + samples.hashCode()
+        result = 31 * result + metadata.hashCode()
+        return result
+    }
+
+    companion object {
+        /** Metric identifier to retrieve average heart rate from [AggregateDataRow]. */
+        @JvmStatic val BPM_AVG: LongAggregateMetric = LongAggregateMetric("HeartRate", "avg", "bpm")
+
+        /** Metric identifier to retrieve minimum heart rate from [AggregateDataRow]. */
+        @JvmStatic val BPM_MIN: LongAggregateMetric = LongAggregateMetric("HeartRate", "min", "bpm")
+
+        /** Metric identifier to retrieve maximum heart rate from [AggregateDataRow]. */
+        @JvmStatic val BPM_MAX: LongAggregateMetric = LongAggregateMetric("HeartRate", "max", "bpm")
+    }
+}
+
+/**
+ * Represents a single measurement of the heart rate.
+ *
+ * @param beatsPerMinute Heart beats per minute. Validation range: 1-300.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY) // Will be made public after API reviews
+public class HeartRate(
+    val time: Instant,
+    val beatsPerMinute: Long,
+) {
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is HeartRate) return false
+
+        if (time != other.time) return false
+        if (beatsPerMinute != other.beatsPerMinute) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        var result = time.hashCode()
+        result = 31 * result + beatsPerMinute.hashCode()
+        return result
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/SeriesRecord.kt
similarity index 67%
rename from health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
rename to health/health-data-client/src/main/java/androidx/health/data/client/records/SeriesRecord.kt
index e2d1362..e3c3a81 100644
--- a/health/health-data-client/src/main/java/androidx/health/platform/client/error/HealthDataException.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/SeriesRecord.kt
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.health.platform.client.error
+package androidx.health.data.client.records
 
-/**
- * Exception thrown by Health Platform. Contains one of [ErrorCode]s and message with details on the
- * error.
- */
-open class HealthDataException(val errorCode: Int, errorMessage: String? = "") :
-    Exception("$errorCode: $errorMessage")
+/** A record that contains a series of measurements. */
+// Consider exposing this one and other similar interfaces!
+internal interface SeriesRecord<out T : Any> : IntervalRecord {
+
+    val samples: List<T>
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt b/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
index e9e1d48..8bd1300 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
@@ -146,4 +146,25 @@
 
     internal fun isOpenEnded(): Boolean =
         (localStartTime == null || localEndTime == null) && (startTime == null || endTime == null)
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is TimeRangeFilter) return false
+
+        if (startTime != other.startTime) return false
+        if (endTime != other.endTime) return false
+        if (localStartTime != other.localStartTime) return false
+        if (localEndTime != other.localEndTime) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = 0
+        result = 31 * result + (startTime?.hashCode() ?: 0)
+        result = 31 * result + (endTime?.hashCode() ?: 0)
+        result = 31 * result + (localStartTime?.hashCode() ?: 0)
+        result = 31 * result + (localEndTime?.hashCode() ?: 0)
+        return result
+    }
 }
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
index 1f8ea4c..665c57e 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
@@ -42,6 +42,7 @@
 import androidx.health.data.client.records.ElevationGained
 import androidx.health.data.client.records.FloorsClimbed
 import androidx.health.data.client.records.HeartRate
+import androidx.health.data.client.records.HeartRateSeries
 import androidx.health.data.client.records.HeartRateVariabilityDifferentialIndex
 import androidx.health.data.client.records.HeartRateVariabilityRmssd
 import androidx.health.data.client.records.HeartRateVariabilityS
@@ -272,13 +273,29 @@
     }
 
     @Test
-    fun testHeartRate() {
+    fun testHeartRateSeries() {
         val data =
-            HeartRate(
-                beatsPerMinute = 1,
-                time = START_TIME,
-                zoneOffset = END_ZONE_OFFSET,
-                metadata = TEST_METADATA
+            HeartRateSeries(
+                startTime = START_TIME,
+                startZoneOffset = START_ZONE_OFFSET,
+                endTime = END_TIME,
+                endZoneOffset = END_ZONE_OFFSET,
+                samples =
+                    listOf(
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 100L,
+                        ),
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 110L,
+                        ),
+                        HeartRate(
+                            time = START_TIME,
+                            beatsPerMinute = 120L,
+                        ),
+                    ),
+                metadata = TEST_METADATA,
             )
 
         assertThat(toRecord(data.toProto())).isEqualTo(data)
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt
index 893e039..353f050 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/time/TimeRangeFilterTest.kt
@@ -18,7 +18,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import java.time.Instant
 import java.time.LocalDateTime
+import kotlin.test.assertEquals
 import kotlin.test.assertFailsWith
+import kotlin.test.assertNotEquals
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -64,4 +66,49 @@
             endTime = LocalDateTime.parse("2021-02-01T02:00:00")
         )
     }
+
+    @Test
+    fun equals() {
+        assertEquals(
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            ),
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            )
+        )
+        assertEquals(
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            ),
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            )
+        )
+
+        assertNotEquals(
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5678L),
+            ),
+            TimeRangeFilter.between(
+                startTime = Instant.ofEpochMilli(1234L),
+                endTime = Instant.ofEpochMilli(5679L),
+            )
+        )
+        assertNotEquals(
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:00:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            ),
+            TimeRangeFilter.between(
+                startTime = LocalDateTime.parse("2021-02-01T01:30:00"),
+                endTime = LocalDateTime.parse("2021-02-01T02:00:00")
+            )
+        )
+    }
 }
diff --git a/interpolator/interpolator/api/current.txt b/interpolator/interpolator/api/current.txt
index fa47381..26c15b9 100644
--- a/interpolator/interpolator/api/current.txt
+++ b/interpolator/interpolator/api/current.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.interpolator.view.animation {
 
+  public class FastOutExtraSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutExtraSlowInInterpolator();
+    method public float getInterpolation(float);
+  }
+
   public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
     ctor public FastOutLinearInInterpolator();
     method public float getInterpolation(float);
diff --git a/interpolator/interpolator/api/public_plus_experimental_current.txt b/interpolator/interpolator/api/public_plus_experimental_current.txt
index fa47381..26c15b9 100644
--- a/interpolator/interpolator/api/public_plus_experimental_current.txt
+++ b/interpolator/interpolator/api/public_plus_experimental_current.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.interpolator.view.animation {
 
+  public class FastOutExtraSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutExtraSlowInInterpolator();
+    method public float getInterpolation(float);
+  }
+
   public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
     ctor public FastOutLinearInInterpolator();
     method public float getInterpolation(float);
diff --git a/interpolator/interpolator/api/restricted_current.txt b/interpolator/interpolator/api/restricted_current.txt
index fa47381..26c15b9 100644
--- a/interpolator/interpolator/api/restricted_current.txt
+++ b/interpolator/interpolator/api/restricted_current.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.interpolator.view.animation {
 
+  public class FastOutExtraSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutExtraSlowInInterpolator();
+    method public float getInterpolation(float);
+  }
+
   public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
     ctor public FastOutLinearInInterpolator();
     method public float getInterpolation(float);
diff --git a/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutExtraSlowInInterpolator.java b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutExtraSlowInInterpolator.java
new file mode 100644
index 0000000..8c584e3
--- /dev/null
+++ b/interpolator/interpolator/src/main/java/androidx/interpolator/view/animation/FastOutExtraSlowInInterpolator.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.interpolator.view.animation;
+
+import android.view.animation.Interpolator;
+
+/**
+ * Interpolator corresponding to {@link android.R.interpolator#fast_out_extra_slow_in}.
+ *
+ * Uses a lookup table for a path consisting of two Bezier curves from (0,0) to (1,1).
+ *
+ * The first curve has control points:
+ * P0 (0, 0)
+ * P1 (0.05, 0)
+ * P2 (0.133333, 0.06)
+ * P3 (0.166666, 0.4)
+ *
+ * The second curve has control points:
+ * P0 (0.166666, 0.4)
+ * P1 (0.208333, 0.82)
+ * P2 (0.25, 1)
+ * P3 (1, 1)
+ *
+ * Values were generated with the following Kotlin code:
+ * <code><pre>
+ * val output = StringBuilder()
+ * if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ *     val p = Path()
+ *     p.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f)
+ *     p.cubicTo(0.208333f, 0.82f, 0.25f, 1.0f, 1.0f, 1.0f)
+ *     val interpolator = PathInterpolator(p)
+ *     val xDiff = 1.0f / 200
+ *     for (i in 0..200) {
+ *         val interpolatedValue = interpolator.getInterpolation(xDiff * i)
+ *         output.append(String.format("%.4f", interpolatedValue))
+ *         output.append("f, ")
+ *     }
+ *     println(output)
+ * }
+ * </pre></code>
+ */
+public class FastOutExtraSlowInInterpolator implements Interpolator {
+
+    /**
+     * Lookup table values sampled with x at regular intervals between 0 and 1 for a total of
+     * 201 points.
+     */
+    private static final float[] VALUES = new float[] {
+            0.0000f, 0.0008f, 0.0016f, 0.0024f, 0.0032f, 0.0057f, 0.0083f,
+            0.0109f, 0.0134f, 0.0171f, 0.0218f, 0.0266f, 0.0313f, 0.0360f,
+            0.0431f, 0.0506f, 0.0581f, 0.0656f, 0.0733f, 0.0835f, 0.0937f,
+            0.1055f, 0.1179f, 0.1316f, 0.1466f, 0.1627f, 0.1810f, 0.2003f,
+            0.2226f, 0.2468f, 0.2743f, 0.3060f, 0.3408f, 0.3852f, 0.4317f,
+            0.4787f, 0.5177f, 0.5541f, 0.5834f, 0.6123f, 0.6333f, 0.6542f,
+            0.6739f, 0.6887f, 0.7035f, 0.7183f, 0.7308f, 0.7412f, 0.7517f,
+            0.7621f, 0.7725f, 0.7805f, 0.7879f, 0.7953f, 0.8027f, 0.8101f,
+            0.8175f, 0.8230f, 0.8283f, 0.8336f, 0.8388f, 0.8441f, 0.8494f,
+            0.8546f, 0.8592f, 0.8630f, 0.8667f, 0.8705f, 0.8743f, 0.8780f,
+            0.8818f, 0.8856f, 0.8893f, 0.8927f, 0.8953f, 0.8980f, 0.9007f,
+            0.9034f, 0.9061f, 0.9087f, 0.9114f, 0.9141f, 0.9168f, 0.9194f,
+            0.9218f, 0.9236f, 0.9255f, 0.9274f, 0.9293f, 0.9312f, 0.9331f,
+            0.9350f, 0.9368f, 0.9387f, 0.9406f, 0.9425f, 0.9444f, 0.9460f,
+            0.9473f, 0.9486f, 0.9499f, 0.9512f, 0.9525f, 0.9538f, 0.9551f,
+            0.9564f, 0.9577f, 0.9590f, 0.9603f, 0.9616f, 0.9629f, 0.9642f,
+            0.9654f, 0.9663f, 0.9672f, 0.9680f, 0.9689f, 0.9697f, 0.9706f,
+            0.9715f, 0.9723f, 0.9732f, 0.9741f, 0.9749f, 0.9758f, 0.9766f,
+            0.9775f, 0.9784f, 0.9792f, 0.9801f, 0.9808f, 0.9813f, 0.9819f,
+            0.9824f, 0.9829f, 0.9835f, 0.9840f, 0.9845f, 0.9850f, 0.9856f,
+            0.9861f, 0.9866f, 0.9872f, 0.9877f, 0.9882f, 0.9887f, 0.9893f,
+            0.9898f, 0.9903f, 0.9909f, 0.9914f, 0.9917f, 0.9920f, 0.9922f,
+            0.9925f, 0.9928f, 0.9931f, 0.9933f, 0.9936f, 0.9939f, 0.9942f,
+            0.9944f, 0.9947f, 0.9950f, 0.9953f, 0.9955f, 0.9958f, 0.9961f,
+            0.9964f, 0.9966f, 0.9969f, 0.9972f, 0.9975f, 0.9977f, 0.9979f,
+            0.9981f, 0.9982f, 0.9983f, 0.9984f, 0.9986f, 0.9987f, 0.9988f,
+            0.9989f, 0.9991f, 0.9992f, 0.9993f, 0.9994f, 0.9995f, 0.9995f,
+            0.9996f, 0.9996f, 0.9997f, 0.9997f, 0.9997f, 0.9998f, 0.9998f,
+            0.9998f, 0.9999f, 0.9999f, 1.0000f, 1.0000f
+    };
+    private static final float STEP = 1f / (VALUES.length - 1);
+
+    @Override
+    public float getInterpolation(float input) {
+        return LookupTableInterpolator.interpolate(VALUES, STEP, input);
+    }
+}
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
index 47151f7..e2285f3 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateHandleSupport.kt
@@ -52,7 +52,7 @@
     if (savedStateRegistry.getSavedStateProvider(SAVED_STATE_KEY) == null) {
         val provider = SavedStateHandlesProvider(savedStateRegistry, this)
         savedStateRegistry.registerSavedStateProvider(SAVED_STATE_KEY, provider)
-        savedStateRegistry.runOnNextRecreation(SavedStateHandleAttacher::class.java)
+        lifecycle.addObserver(SavedStateHandleAttacher(provider))
     }
 }
 
@@ -184,11 +184,15 @@
 }
 
 // it reconnects existent SavedStateHandles to SavedStateRegistryOwner when it is recreated
-internal class SavedStateHandleAttacher : SavedStateRegistry.AutoRecreated {
-    override fun onRecreated(owner: SavedStateRegistryOwner) {
-        // if SavedStateHandlesProvider wasn't added previously, there's nothing for us to do
-        val provider = owner.savedStateRegistry
-            .getSavedStateProvider(SAVED_STATE_KEY) as? SavedStateHandlesProvider ?: return
+internal class SavedStateHandleAttacher(
+    private val provider: SavedStateHandlesProvider
+) : LifecycleEventObserver {
+
+    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+        check(event == Lifecycle.Event.ON_CREATE) {
+            "Next event must be ON_CREATE, it was $event"
+        }
+        source.lifecycle.removeObserver(this)
         // onRecreated() is called after the Lifecycle reaches CREATED, so we
         // eagerly restore the state as part of this call to ensure it consumed
         // even if no ViewModels are actually created during this cycle of the Lifecycle
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt
index 98b57cb..adab446 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt
@@ -20,9 +20,12 @@
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
+import androidx.lifecycle.viewmodel.compose.viewModel
+import androidx.navigation.NavHostController
 import androidx.navigation.testing.TestNavigatorState
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -77,4 +80,33 @@
 
         rule.onNodeWithText(defaultText).assertDoesNotExist()
     }
+
+    @Test
+    fun testNestedNavHostInDialogDismissed() {
+        lateinit var navController: NavHostController
+
+        rule.setContent {
+            navController = rememberNavController()
+            NavHost(navController, "first") {
+                composable("first") { }
+                dialog("second") {
+                    viewModel<TestViewModel>(it)
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            navController.navigate("second")
+        }
+
+        // Now trigger the back button
+        rule.runOnIdle {
+            navController.navigatorProvider.getNavigator(DialogNavigator::class.java).dismiss(
+                navController.getBackStackEntry("second")
+            )
+        }
+
+        rule.waitForIdle()
+        assertThat(navController.currentDestination?.route).isEqualTo("first")
+    }
 }
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt
index bfac256..9de4e8f 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt
@@ -43,7 +43,7 @@
      * Dismiss the dialog destination associated with the given [backStackEntry].
      */
     internal fun dismiss(backStackEntry: NavBackStackEntry) {
-        state.pop(backStackEntry, false)
+        state.popWithTransition(backStackEntry, false)
     }
 
     override fun navigate(
diff --git a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
index a6a16d1..085686c 100644
--- a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
+++ b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
@@ -37,7 +37,9 @@
 import androidx.paging.PagingSource
 import androidx.paging.TestPagingSource
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
+
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -458,6 +460,7 @@
             .assertTopPositionInRootIsEqualTo(itemSize * 2)
     }
 
+    @FlakyTest(bugId = 229089541)
     @Test
     fun removingItem() {
         val items = mutableListOf(1, 2, 3)
diff --git a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
index f495ae1..86cea78 100644
--- a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
+++ b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
@@ -60,16 +60,10 @@
         // A processing step that just ensures we're run every round.
         object : XProcessingStep {
             override fun annotations(): Set<String> = setOf("*")
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> = emptySet()
         }
     )
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
index fb3b93c..97a8b97 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
@@ -57,17 +57,14 @@
     fun xProcessingStep() {
         val annotatedElements = mutableMapOf<KClass<out Annotation>, String>()
         val processingStep = object : XProcessingStep {
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByAnnotation[OtherAnnotation::class.qualifiedName]
                     ?.filterIsInstance<XTypeElement>()
                     ?.forEach {
@@ -136,17 +133,14 @@
         val otherAnnotatedElements = mutableListOf<TypeName>()
         // create a scenario where we run multi-step processing so that we can test caching
         val processingStep = object : XProcessingStep {
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 // for each element annotated with Main annotation, create a class with Other
                 // annotation to trigger another round
                 elementsByAnnotation[MainAnnotation::class.qualifiedName]
@@ -214,17 +208,14 @@
         // create a scenario where we run multi-step processing so that we can test caching
         val processingStep = object : XProcessingStep {
             var roundCounter = 0
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementPerRound[roundCounter++] = listOf(
                     env.requireTypeElement("foo.bar.Main"),
                     env.requireTypeElement("foo.bar.Main")
@@ -315,17 +306,14 @@
         val processingEnvPerRound = mutableMapOf<Int, XProcessingEnv>()
         val processingStep = object : XProcessingStep {
             var roundCounter = 0
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 processingEnvPerRound[roundCounter++] = env
                 // trigger another round
                 elementsByAnnotation[MainAnnotation::class.qualifiedName]
@@ -400,17 +388,14 @@
         // create a scenario where we run multi-step processing so that we can test caching
         val processingStep = object : XProcessingStep {
             var roundCounter = 0
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 processingEnvPerRound[roundCounter++] = env
                 // trigger another round
                 elementsByAnnotation[MainAnnotation::class.qualifiedName]
@@ -498,34 +483,28 @@
         // create a scenario where we can test caching between steps
         val mainStep = object : XProcessingStep {
             override fun annotations(): Set<String> = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = env.requireTypeElement("foo.bar.Main")
                 return emptySet()
             }
         }
         val otherStep = object : XProcessingStep {
             override fun annotations(): Set<String> = setOf(OtherAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XTypeElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = env.requireTypeElement("foo.bar.Main")
                 return emptySet()
             }
@@ -547,17 +526,14 @@
     @Test
     fun javacReturnsUnprocessed() {
         val processingStep = object : XProcessingStep {
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 return elementsByAnnotation.values.flatten().toSet()
             }
             override fun annotations(): Set<String> {
@@ -596,17 +572,14 @@
         CompilationTestCapabilities.assumeKspIsEnabled()
         var returned: Set<XElement>? = null
         val processingStep = object : XProcessingStep {
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 return elementsByAnnotation.values
                     .flatten()
                     .toSet()
@@ -691,17 +664,14 @@
         val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
         val mainStep = object : XProcessingStep {
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = elementsByAnnotation.values.flatten()
                     .map { (it as XTypeElement).qualifiedName }
                 return emptySet()
@@ -709,17 +679,14 @@
         }
         val otherStep = object : XProcessingStep {
             override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = elementsByAnnotation.values.flatten()
                     .map { (it as XTypeElement).qualifiedName }
                 return emptySet()
@@ -762,17 +729,15 @@
         val mainStep = object : XProcessingStep {
             var round = 0
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    invokedLifecycles.add("processOver")
+                    return emptySet()
+                }
                 invokedLifecycles.add("process")
                 stepsProcessed.add(this)
                 val deferredElements = if (round++ == 0) {
@@ -790,20 +755,6 @@
                 }
                 return deferredElements
             }
-
-            @Deprecated(
-                "We're combining processOver() and the original process().",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
-            override fun processOver(
-                env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
-            ) {
-                invokedLifecycles.add("processOver")
-            }
         }
         val invokedPostRound = mutableListOf<Boolean>()
         assertAbout(
@@ -878,17 +829,14 @@
         val genClassName = ClassName.get("foo.bar", "GeneratedType")
         val mainStep = object : XProcessingStep {
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 if (round++ == 0) {
                     // Generate the interface, should not be resolvable in 1st round
                     val spec = TypeSpec.interfaceBuilder(genClassName).build()
@@ -950,34 +898,28 @@
         val stepsProcessed = mutableListOf<XProcessingStep>()
         val mainStep = object : XProcessingStep {
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 stepsProcessed.add(this)
                 return emptySet()
             }
         }
         val otherStep = object : XProcessingStep {
             override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 stepsProcessed.add(this)
                 return emptySet()
             }
@@ -1017,17 +959,14 @@
         val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
         val mainStep = object : XProcessingStep {
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = elementsByAnnotation.values.flatten()
                     .map { (it as XTypeElement).qualifiedName }
                 return emptySet()
@@ -1035,17 +974,14 @@
         }
         val otherStep = object : XProcessingStep {
             override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByStep[this] = elementsByAnnotation.values.flatten()
                     .map { (it as XTypeElement).qualifiedName }
                 return emptySet()
@@ -1093,17 +1029,15 @@
         val mainStep = object : XProcessingStep {
             var round = 0
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    invokedLifecycles.add("processOver")
+                    return emptySet()
+                }
                 invokedLifecycles.add("process")
                 stepsProcessed.add(this)
                 val deferredElements = if (round++ == 0) {
@@ -1121,20 +1055,6 @@
                 }
                 return deferredElements
             }
-
-            @Deprecated(
-                "We're combining processOver() and the original process().",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
-            override fun processOver(
-                env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
-            ) {
-                invokedLifecycles.add("processOver")
-            }
         }
         val invokedPostRound = mutableListOf<Boolean>()
         val processorProvider = object : SymbolProcessorProvider {
@@ -1205,34 +1125,28 @@
         val stepsProcessed = mutableListOf<XProcessingStep>()
         val mainStep = object : XProcessingStep {
             override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 stepsProcessed.add(this)
                 return emptySet()
             }
         }
         val otherStep = object : XProcessingStep {
             override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 stepsProcessed.add(this)
                 return emptySet()
             }
@@ -1297,17 +1211,14 @@
         val mainStep = object : XProcessingStep {
             var round = 0
             override fun annotations() = setOf(AnywhereAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByAnnotation.values.flatten().let {
                     assertRound(round, it)
                     roundReceivedElementsHashes.add(it.map { it.hashCode() }.toSet())
@@ -1356,17 +1267,14 @@
     fun javacDisableValidatingAnnotatedElements() {
         val processingStep = object : XProcessingStep {
             var round = 0
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 if (round++ == 0) {
                     val className = ClassName.get("foo.bar", "ToBeGenerated")
                     val spec = TypeSpec.classBuilder(className).build()
@@ -1410,17 +1318,14 @@
         CompilationTestCapabilities.assumeKspIsEnabled()
         val processingStep = object : XProcessingStep {
             var round = 0
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 if (round++ == 0) {
                     val className = ClassName.get("foo.bar", "ToBeGenerated")
                     val spec = TypeSpec.classBuilder(className).build()
@@ -1513,17 +1418,14 @@
         val mainStep = object : XProcessingStep {
             var round = 0
             override fun annotations() = setOf(AnywhereAnnotation::class.qualifiedName!!)
-            @Deprecated(
-                "We're combining processOver() and this process() overload.",
-                replaceWith = ReplaceWith(
-                    "process(XProcessingEnv, Map<String, Set<XElement>>, Boolean)"
-                ),
-                level = DeprecationLevel.WARNING
-            )
             override fun process(
                 env: XProcessingEnv,
-                elementsByAnnotation: Map<String, Set<XElement>>
+                elementsByAnnotation: Map<String, Set<XElement>>,
+                isLastRound: Boolean
             ): Set<XElement> {
+                if (isLastRound) {
+                    return emptySet()
+                }
                 elementsByAnnotation.values.flatten().let {
                     assertRound(round, it)
                     roundReceivedElementsHashes.add(it.map { it.hashCode() }.toSet())
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
index bff6b0a..dc53a13 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedContainer.kt
@@ -35,10 +35,6 @@
     internal fun add(node: CurvedChild, modifier: CurvedModifier) {
         nodes.add(modifier.wrap(node))
     }
-    internal fun initialize(contentBuilder: CurvedScope.() -> Unit) {
-        nodes.clear()
-        apply(contentBuilder)
-    }
 }
 
 /**
@@ -47,9 +43,9 @@
 internal abstract class ContainerChild(
     curvedLayoutDirection: CurvedLayoutDirection,
     internal val reverseLayout: Boolean,
-    private val contentBuilder: CurvedScope.() -> Unit
+    contentBuilder: CurvedScope.() -> Unit
 ) : CurvedChild() {
-    private val curvedContainerScope = CurvedScope(curvedLayoutDirection)
+    private val curvedContainerScope = CurvedScope(curvedLayoutDirection).apply(contentBuilder)
     internal val children get() = curvedContainerScope.nodes
 
     internal val childrenInLayoutOrder get() = children.indices.map { ix ->
@@ -58,9 +54,6 @@
 
     @Composable
     override fun SubComposition() {
-        // Ensure we subscribe this composition to any state reads on contentBuilder,
-        // and we keep our internal tree in sync with compose's tree.
-        curvedContainerScope.initialize(contentBuilder)
         children.forEach {
             it.SubComposition()
         }
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
index 199a7da..76a591d 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedLayout.kt
@@ -19,10 +19,8 @@
 import androidx.compose.foundation.layout.Row
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
@@ -109,11 +107,11 @@
     // Note that all angles in the function are in radians, and the anchor parameter is in degrees
 
     val curvedLayoutDirection = initialCurvedLayoutDirection(angularDirection)
-    val curvedRowChild by remember(curvedLayoutDirection, radialAlignment, contentBuilder) {
-        derivedStateOf {
-            CurvedRowChild(curvedLayoutDirection, radialAlignment, contentBuilder)
-        }
-    }
+
+    // Create the curved tree and subscribe to be recomposed when any part changes, this may not be
+    // optimal but since we have only one measure block (the one here) for all the curved layout,
+    // we still need to do most of the work when content changes.
+    val curvedRowChild = CurvedRowChild(curvedLayoutDirection, radialAlignment, contentBuilder)
 
     Layout(
         modifier = modifier.drawWithContent {
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index e9ed421..5536fb6 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -48,22 +52,22 @@
   @androidx.compose.runtime.Stable public interface ChipColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconTintColor(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
   }
 
   public final class ChipDefaults {
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconColor);
     method public androidx.compose.foundation.layout.PaddingValues getCompactChipContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method public float getIconSize();
     method public float getLargeIconSize();
     method public float getSmallIconSize();
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
     property public final androidx.compose.foundation.layout.PaddingValues CompactChipContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -328,7 +332,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -475,7 +479,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> splitBackgroundOverlay(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class StepperDefaults {
@@ -487,8 +491,8 @@
   }
 
   public final class StepperKt {
-    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
 
   public final class SwipeToDismissBoxDefaults {
@@ -515,10 +519,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
@@ -586,7 +586,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class ToggleChipDefaults {
@@ -598,9 +598,9 @@
     method public androidx.compose.ui.graphics.vector.ImageVector getRadioOn();
     method @androidx.compose.runtime.Composable public long getSwitchUncheckedIconColor();
     method public androidx.compose.ui.graphics.vector.ImageVector radioIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedToggleControlTintColor, optional long splitBackgroundOverlayColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedToggleControlColor, optional long splitBackgroundOverlayColor);
     method public androidx.compose.ui.graphics.vector.ImageVector switchIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
     property public final androidx.compose.ui.graphics.vector.ImageVector CheckboxOn;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -686,9 +686,9 @@
   }
 
   public final class DialogKt {
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   public final class Dialog_androidKt {
diff --git a/wear/compose/compose-material/api/public_plus_experimental_current.txt b/wear/compose/compose-material/api/public_plus_experimental_current.txt
index 4f46d28..d1d0f94 100644
--- a/wear/compose/compose-material/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-material/api/public_plus_experimental_current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -48,22 +52,22 @@
   @androidx.compose.runtime.Stable public interface ChipColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconTintColor(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
   }
 
   public final class ChipDefaults {
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconColor);
     method public androidx.compose.foundation.layout.PaddingValues getCompactChipContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method public float getIconSize();
     method public float getLargeIconSize();
     method public float getSmallIconSize();
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
     property public final androidx.compose.foundation.layout.PaddingValues CompactChipContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -354,7 +358,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -501,7 +505,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> splitBackgroundOverlay(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class StepperDefaults {
@@ -513,8 +517,8 @@
   }
 
   public final class StepperKt {
-    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeProgress<T> {
@@ -551,10 +555,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
@@ -665,7 +665,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class ToggleChipDefaults {
@@ -677,9 +677,9 @@
     method public androidx.compose.ui.graphics.vector.ImageVector getRadioOn();
     method @androidx.compose.runtime.Composable public long getSwitchUncheckedIconColor();
     method public androidx.compose.ui.graphics.vector.ImageVector radioIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedToggleControlTintColor, optional long splitBackgroundOverlayColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedToggleControlColor, optional long splitBackgroundOverlayColor);
     method public androidx.compose.ui.graphics.vector.ImageVector switchIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
     property public final androidx.compose.ui.graphics.vector.ImageVector CheckboxOn;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -765,9 +765,9 @@
   }
 
   public final class DialogKt {
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   public final class Dialog_androidKt {
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index e9ed421..5536fb6 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -1,6 +1,10 @@
 // Signature format: 4.0
 package androidx.wear.compose.material {
 
+  @androidx.compose.runtime.Immutable public final class AutoCenteringParams {
+    ctor public AutoCenteringParams(optional int itemIndex, optional int itemOffset);
+  }
+
   @androidx.compose.runtime.Stable public interface ButtonColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
@@ -48,22 +52,22 @@
   @androidx.compose.runtime.Stable public interface ChipColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconTintColor(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
   }
 
   public final class ChipDefaults {
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors childChipColors(optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors chipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional long disabledBackgroundColor, optional long disabledContentColor, optional long disabledSecondaryContentColor, optional long disabledIconColor);
     method public androidx.compose.foundation.layout.PaddingValues getCompactChipContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method public float getIconSize();
     method public float getLargeIconSize();
     method public float getSmallIconSize();
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconTintColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors gradientBackgroundChipColors(optional long startBackgroundColor, optional long endBackgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors imageBackgroundChipColors(androidx.compose.ui.graphics.painter.Painter backgroundImagePainter, optional androidx.compose.ui.graphics.Brush backgroundImageScrimBrush, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors primaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ChipColors secondaryChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long iconColor);
     property public final androidx.compose.foundation.layout.PaddingValues CompactChipContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -328,7 +332,7 @@
   }
 
   public final class ScalingLazyColumnKt {
-    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional boolean autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ScalingLazyColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.ScalingLazyListState state, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional boolean reverseLayout, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, optional androidx.wear.compose.material.ScalingParams scalingParams, optional int anchorType, optional androidx.wear.compose.material.AutoCenteringParams? autoCentering, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void items(androidx.wear.compose.material.ScalingLazyListScope, T![] items, optional kotlin.jvm.functions.Function1<? super T,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super T,kotlin.Unit> itemContent);
     method public static inline <T> void itemsIndexed(androidx.wear.compose.material.ScalingLazyListScope, java.util.List<? extends T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
@@ -475,7 +479,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> splitBackgroundOverlay(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class StepperDefaults {
@@ -487,8 +491,8 @@
   }
 
   public final class StepperKt {
-    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconTintColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, int steps, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Stepper(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onValueChange, kotlin.ranges.IntProgression valueProgression, kotlin.jvm.functions.Function0<kotlin.Unit> decreaseIcon, kotlin.jvm.functions.Function0<kotlin.Unit> increaseIcon, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional long iconColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
 
   public final class SwipeToDismissBoxDefaults {
@@ -515,10 +519,6 @@
     property public final androidx.wear.compose.material.SwipeToDismissValue currentValue;
     property public final boolean isAnimationRunning;
     property public final androidx.wear.compose.material.SwipeToDismissValue targetValue;
-    field public static final androidx.wear.compose.material.SwipeToDismissBoxState.Companion Companion;
-  }
-
-  public static final class SwipeToDismissBoxState.Companion {
   }
 
   public enum SwipeToDismissKeys {
@@ -586,7 +586,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.painter.Painter> background(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled, boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlTintColor(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> toggleControlColor(boolean enabled, boolean checked);
   }
 
   public final class ToggleChipDefaults {
@@ -598,9 +598,9 @@
     method public androidx.compose.ui.graphics.vector.ImageVector getRadioOn();
     method @androidx.compose.runtime.Composable public long getSwitchUncheckedIconColor();
     method public androidx.compose.ui.graphics.vector.ImageVector radioIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedToggleControlTintColor, optional long splitBackgroundOverlayColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SplitToggleChipColors splitToggleChipColors(optional long backgroundColor, optional long contentColor, optional long secondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedToggleControlColor, optional long splitBackgroundOverlayColor);
     method public androidx.compose.ui.graphics.vector.ImageVector switchIcon(boolean checked);
-    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlTintColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlTintColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleChipColors toggleChipColors(optional long checkedStartBackgroundColor, optional long checkedEndBackgroundColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedToggleControlColor, optional long uncheckedStartBackgroundColor, optional long uncheckedEndBackgroundColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedToggleControlColor, optional androidx.compose.ui.unit.LayoutDirection gradientDirection);
     property public final androidx.compose.ui.graphics.vector.ImageVector CheckboxOn;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public final float IconSize;
@@ -686,9 +686,9 @@
   }
 
   public final class DialogKt {
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
-    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconTintColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, kotlin.jvm.functions.Function0<kotlin.Unit> negativeButton, kotlin.jvm.functions.Function0<kotlin.Unit> positiveButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long contentColor, optional long titleColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? content);
+    method @androidx.compose.runtime.Composable public static void Alert(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? message, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long backgroundColor, optional long titleColor, optional long messageColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Confirmation(kotlin.jvm.functions.Function0<kotlin.Unit> onTimeout, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? icon, optional androidx.wear.compose.material.ScalingLazyListState scrollState, optional long durationMillis, optional long backgroundColor, optional long contentColor, optional long iconColor, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   public final class Dialog_androidKt {
diff --git a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
index f38a020..976c4ce2 100644
--- a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
+++ b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ScalingLazyColumnSample.kt
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material.AutoCenteringParams
 import androidx.wear.compose.material.Chip
 import androidx.wear.compose.material.ChipDefaults
 import androidx.wear.compose.material.ListHeader
@@ -92,7 +93,8 @@
     ScalingLazyColumn(
         anchorType = ScalingLazyListAnchorType.ItemStart,
         verticalArrangement = Arrangement.spacedBy(itemSpacing),
-        state = state
+        state = state,
+        autoCentering = AutoCenteringParams(itemOffset = scrollOffset)
     ) {
         item {
             ListHeader {
@@ -119,7 +121,7 @@
 fun SimpleScalingLazyColumnWithContentPadding() {
     ScalingLazyColumn(
         contentPadding = PaddingValues(top = 20.dp, bottom = 20.dp),
-        autoCentering = false
+        autoCentering = null
     ) {
         item {
             ListHeader {
diff --git a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ToggleChipSample.kt b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ToggleChipSample.kt
index da29135..7ee5288 100644
--- a/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ToggleChipSample.kt
+++ b/wear/compose/compose-material/samples/src/main/java/androidx/wear/compose/material/samples/ToggleChipSample.kt
@@ -51,7 +51,7 @@
         // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
         // rather than the default.
         colors = ToggleChipDefaults.toggleChipColors(
-            uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+            uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
         ),
         toggleControl = {
             Icon(
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
index ee291e2..5cd37a2 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipTest.kt
@@ -638,27 +638,27 @@
     fun allows_custom_primary_enabled_icon_tint_color_override() {
         val overrideColor = Color.Red
         var actualContentColor = Color.Transparent
-        var actualIconTintColor = Color.Transparent
+        var actualIconColor = Color.Transparent
         var expectedContent = Color.Transparent
         rule.setContentWithTheme {
             expectedContent = MaterialTheme.colors.onPrimary
             Chip(
                 onClick = {},
                 colors = ChipDefaults.chipColors(
-                    iconTintColor = overrideColor
+                    iconColor = overrideColor
                 ),
                 label = {
                     actualContentColor = LocalContentColor.current
                 },
                 icon = {
-                    actualIconTintColor = LocalContentColor.current
+                    actualIconColor = LocalContentColor.current
                 },
                 enabled = true,
                 modifier = Modifier.testTag("test-item")
             )
         }
         assertEquals(expectedContent, actualContentColor)
-        assertEquals(overrideColor, actualIconTintColor)
+        assertEquals(overrideColor, actualIconColor)
     }
 
     @Test
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/IconTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/IconTest.kt
index 9d7cdba..0f1d9c4 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/IconTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/IconTest.kt
@@ -192,7 +192,7 @@
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @Test
-    fun iconUnspecifiedTintColorIgnored() {
+    fun iconUnspecifiedColorIgnored() {
         val width = 35.dp
         val height = 83.dp
         val testTag = "testTag"
@@ -215,7 +215,7 @@
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @Test
-    fun iconSpecifiedTintColorApplied() {
+    fun iconSpecifiedColorApplied() {
         val width = 35.dp
         val height = 83.dp
         val testTag = "testTag"
@@ -232,7 +232,7 @@
             Icon(image, null, modifier = Modifier.testTag(testTag), tint = Color.Blue)
         }
 
-        // With a tint color provided, all pixels should be blue
+        // With a icon color provided, all pixels should be blue
         rule.onNodeWithTag(testTag).captureToImage().assertPixels { Color.Blue }
     }
 
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
index dd3eb02..4ea531b 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PositionIndicatorTest.kt
@@ -118,7 +118,7 @@
                 modifier = Modifier
                     .onSizeChanged { viewPortHeight = it.height }
                     .requiredSize(itemSizeDp * 3.5f + itemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(3) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -189,7 +189,7 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSize() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = true,
+            enableAutoCentering = true,
             contentPadding = PaddingValues(0.dp)
         )
     }
@@ -197,7 +197,7 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSizeWithContentPadding() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = true,
+            enableAutoCentering = true,
             contentPadding = PaddingValues(50.dp)
         )
     }
@@ -205,13 +205,13 @@
     @Test
     fun scrollableScalingLazyColumnGivesCorrectPositionAndSizeWithContentPaddingNoAutoCenter() {
         scrollableScalingLazyColumnPositionAndSize(
-            autoCentering = false,
+            enableAutoCentering = false,
             contentPadding = PaddingValues(50.dp)
         )
     }
 
     private fun scrollableScalingLazyColumnPositionAndSize(
-        autoCentering: Boolean,
+        enableAutoCentering: Boolean,
         contentPadding: PaddingValues
     ) {
         lateinit var state: ScalingLazyListState
@@ -230,7 +230,8 @@
                         itemSizeDp * 3f + itemSpacingDp * 2f
                     ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f),
-                autoCentering = autoCentering,
+                autoCentering = if (enableAutoCentering)
+                    AutoCenteringParams(itemIndex = 0) else null,
                 contentPadding = contentPadding
             ) {
                 items(5) {
@@ -325,7 +326,7 @@
                     .fillMaxWidth()
                     .requiredSize(itemSizeDp * 3.5f + itemSpacingDp * 2.5f)
                     .background(Color.DarkGray),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(3) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -371,7 +372,7 @@
                     )
                     .background(Color.DarkGray),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
index 8d050db..1a3cbe7 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnIndexedTest.kt
@@ -98,7 +98,7 @@
                 state = rememberScalingLazyListState(initialCenterItemIndex = 0)
                     .also { state = it },
                 modifier = Modifier.height(200.dp),
-                autoCentering = false,
+                autoCentering = null,
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f)
             ) {
                 itemsIndexed(items) { index, item ->
@@ -130,7 +130,7 @@
                 state = rememberScalingLazyListState(initialCenterItemIndex = 0)
                     .also { state = it },
                 modifier = Modifier.height(viewPortHeight),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(itemIndex = 0),
                 verticalArrangement = Arrangement.spacedBy(gapBetweenItems),
                 // No scaling as we are doing maths with expected item sizes
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(edgeScale = 1.0f)
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
index 3d17741..850300e 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyColumnTest.kt
@@ -87,7 +87,7 @@
                     state = rememberScalingLazyListState().also { state = it },
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(listSize),
                     anchorType = ScalingLazyListAnchorType.ItemCenter,
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(),
                     verticalArrangement = Arrangement.spacedBy(0.dp),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(
                         edgeScale = 0f,
@@ -139,7 +139,7 @@
                     state = rememberScalingLazyListState().also { state = it },
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(listSize),
                     anchorType = ScalingLazyListAnchorType.ItemStart,
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(),
                     verticalArrangement = Arrangement.spacedBy(0.dp),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(
                         edgeScale = 0f,
@@ -192,7 +192,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -224,7 +224,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = false,
+                    autoCentering = null,
                     userScrollEnabled = false
                 ) {
                     items(5) {
@@ -259,7 +259,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true
+                    autoCentering = AutoCenteringParams(itemIndex = 0)
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -292,7 +292,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(itemIndex = 0),
                     flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state)
                 ) {
                     items(5) {
@@ -337,7 +337,7 @@
                     modifier = Modifier.testTag(TEST_TAG).requiredSize(
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
-                    autoCentering = true,
+                    autoCentering = AutoCenteringParams(itemIndex = 0),
                     flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(
                         state = state,
                         snapOffset = snapOffset
@@ -381,7 +381,7 @@
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
                     reverseLayout = true,
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp))
@@ -414,6 +414,7 @@
                         itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                     ),
                     scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                    autoCentering = AutoCenteringParams(itemIndex = 0)
                 ) {
                     items(5) {
                         Box(Modifier.requiredSize(itemSizeDp).testTag("Item:" + it))
@@ -492,7 +493,7 @@
                     modifier = Modifier
                         .testTag(TEST_TAG)
                         .requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                    autoCentering = false
+                    autoCentering = null
                 ) {
                     items(6) {
                         Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
index a1ae7e9..c39f251 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
@@ -77,7 +77,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true
+                autoCentering = AutoCenteringParams()
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -103,7 +103,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp)
             ) {
                 items(5) {
@@ -129,7 +129,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp)
             ) {
                 items(5) {
@@ -155,7 +155,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true,
+                autoCentering = AutoCenteringParams(),
                 contentPadding = PaddingValues(all = 0.dp),
                 reverseLayout = true
             ) {
@@ -183,7 +183,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = true
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -209,7 +209,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -234,7 +234,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -261,7 +261,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = true
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -287,7 +287,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -314,7 +314,7 @@
                 modifier = Modifier.requiredSize(
                     itemSizeDp
                 ),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp * 5))
@@ -404,7 +404,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -569,6 +569,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(
@@ -661,6 +662,7 @@
                     itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
+                autoCentering = AutoCenteringParams(itemIndex = 0)
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -700,7 +702,7 @@
                 ),
                 scalingParams = ScalingLazyColumnDefaults.scalingParams(1.0f, 1.0f),
                 reverseLayout = true,
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -736,7 +738,7 @@
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + spacing * 2.5f),
                 verticalArrangement = Arrangement.spacedBy(spacing),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(5) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -773,7 +775,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -806,7 +808,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -892,7 +894,7 @@
             ScalingLazyColumn(
                 state = rememberScalingLazyListState().also { state = it },
                 modifier = Modifier.requiredSize(itemSizeDp * 3.5f + defaultItemSpacingDp * 2.5f),
-                autoCentering = false
+                autoCentering = null
             ) {
                 items(6) {
                     Box(Modifier.requiredSize(itemSizeDp))
@@ -1026,7 +1028,7 @@
                 state = rememberScalingLazyListState(
                     initialCenterItemIndex = 0
                 ).also { state = it },
-                autoCentering = true
+                autoCentering = AutoCenteringParams()
             ) {
                 items(7) {
                     Box(Modifier.requiredSize(itemSizeDp))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/StepperScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/StepperScreenshotTest.kt
index 6ceb1b2..837e4d1 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/StepperScreenshotTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/StepperScreenshotTest.kt
@@ -144,7 +144,7 @@
                 decreaseIcon = { Icon(StepperDefaults.Decrease, "Decrease") },
                 backgroundColor = Color.Green,
                 contentColor = Color.Yellow,
-                iconTintColor = Color.Magenta,
+                iconColor = Color.Magenta,
             ) {
                 Text("Demo")
             }
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
index f76360f..cd1ddc6 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
@@ -696,7 +696,7 @@
 
         rule.setContentWithTheme {
             Alert(
-                iconTintColor = overrideColor,
+                iconColor = overrideColor,
                 icon = { actualColor = LocalContentColor.current },
                 title = {},
                 negativeButton = {},
@@ -715,7 +715,7 @@
 
         rule.setContentWithTheme {
             Alert(
-                iconTintColor = overrideColor,
+                iconColor = overrideColor,
                 icon = { actualColor = LocalContentColor.current },
                 title = {},
                 message = {},
@@ -734,7 +734,7 @@
         rule.setContentWithTheme {
             Confirmation(
                 onTimeout = {},
-                iconTintColor = overrideColor,
+                iconColor = overrideColor,
                 icon = { actualColor = LocalContentColor.current },
                 content = {},
             )
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt
index 8117791..ba24155 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Chip.kt
@@ -215,9 +215,9 @@
         ) {
             if (icon != null) {
                 CompositionLocalProvider(
-                    LocalContentColor provides colors.iconTintColor(enabled).value,
+                    LocalContentColor provides colors.iconColor(enabled).value,
                     LocalContentAlpha provides
-                        colors.iconTintColor(enabled = enabled).value.alpha,
+                        colors.iconColor(enabled = enabled).value.alpha,
                 ) {
                     Box(
                         modifier = Modifier.wrapContentSize(align = Alignment.Center),
@@ -403,12 +403,12 @@
     public fun secondaryContentColor(enabled: Boolean): State<Color>
 
     /**
-     * Represents the icon tint color for this chip, depending on [enabled].
+     * Represents the icon color for this chip, depending on [enabled].
      *
      * @param enabled Whether the chip is enabled
      */
     @Composable
-    public fun iconTintColor(enabled: Boolean): State<Color>
+    public fun iconColor(enabled: Boolean): State<Color>
 }
 
 /**
@@ -425,20 +425,20 @@
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The secondary content color of this [Chip] when enabled, used
      * for secondaryLabel content
-     * @param iconTintColor The icon tint color of this [Chip] when enabled, used for icon content
+     * @param iconColor The icon color of this [Chip] when enabled, used for icon content
      */
     @Composable
     public fun primaryChipColors(
         backgroundColor: Color = MaterialTheme.colors.primary,
         contentColor: Color = contentColorFor(backgroundColor),
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor
+        iconColor: Color = contentColor
     ): ChipColors {
         return chipColors(
             backgroundColor = backgroundColor,
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            iconTintColor = iconTintColor
+            iconColor = iconColor
         )
     }
 
@@ -459,7 +459,7 @@
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The secondary content color of this [Chip] when enabled, used
      * for secondaryLabel content
-     * @param iconTintColor The icon tint color of this [Chip] when enabled, used for icon content
+     * @param iconColor The icon color of this [Chip] when enabled, used for icon content
      * @param gradientDirection Whether the chips gradient should be start to end (indicated by
      * [LayoutDirection.Ltr]) or end to start (indicated by [LayoutDirection.Rtl]).
      */
@@ -471,7 +471,7 @@
             .compositeOver(MaterialTheme.colors.surface.copy(alpha = 0.75f)),
         contentColor: Color = contentColorFor(endBackgroundColor),
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor,
+        iconColor: Color = contentColor,
         gradientDirection: LayoutDirection = LocalLayoutDirection.current
     ): ChipColors {
         val backgroundColors: List<Color>
@@ -499,7 +499,7 @@
             backgroundPainter = BrushPainter(Brush.linearGradient(backgroundColors)),
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            iconTintColor = iconTintColor,
+            iconColor = iconColor,
             disabledBackgroundPainter = BrushPainter(
                 Brush.linearGradient(disabledBackgroundColors)
             ),
@@ -507,7 +507,7 @@
             disabledSecondaryContentColor = secondaryContentColor.copy(
                 alpha = ContentAlpha.disabled
             ),
-            disabledIconTintColor = iconTintColor.copy(alpha = ContentAlpha.disabled),
+            disabledIconColor = iconColor.copy(alpha = ContentAlpha.disabled),
         )
     }
 
@@ -521,20 +521,20 @@
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The secondary content color of this [Chip] when enabled, used
      * for secondaryLabel content
-     * @param iconTintColor The icon tint color of this [Chip] when enabled, used for icon content
+     * @param iconColor The icon color of this [Chip] when enabled, used for icon content
      */
     @Composable
     public fun secondaryChipColors(
         backgroundColor: Color = MaterialTheme.colors.surface,
         contentColor: Color = contentColorFor(backgroundColor),
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor
+        iconColor: Color = contentColor
     ): ChipColors {
         return chipColors(
             backgroundColor = backgroundColor,
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            iconTintColor = iconTintColor
+            iconColor = iconColor
         )
     }
 
@@ -549,19 +549,19 @@
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The secondary content color of this [Chip] when enabled, used
      * for secondaryLabel content
-     * @param iconTintColor The icon tint color of this [Chip] when enabled, used for icon content
+     * @param iconColor The icon color of this [Chip] when enabled, used for icon content
      */
     @Composable
     public fun childChipColors(
         contentColor: Color = MaterialTheme.colors.onSurface,
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor
+        iconColor: Color = contentColor
     ): ChipColors {
         return chipColors(
             backgroundColor = Color.Transparent,
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            iconTintColor = iconTintColor
+            iconColor = iconColor
         )
     }
 
@@ -576,7 +576,7 @@
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The secondary content color of this [Chip] when enabled, used
      * for secondaryLabel content
-     * @param iconTintColor The icon tint color of this [Chip] when enabled, used for icon content
+     * @param iconColor The icon color of this [Chip] when enabled, used for icon content
      */
     @Composable
     public fun imageBackgroundChipColors(
@@ -589,7 +589,7 @@
         ),
         contentColor: Color = MaterialTheme.colors.onBackground,
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor,
+        iconColor: Color = contentColor,
     ): ChipColors {
         val backgroundPainter =
             remember(backgroundImagePainter, backgroundImageScrimBrush) {
@@ -612,13 +612,13 @@
             backgroundPainter = backgroundPainter,
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            iconTintColor = iconTintColor,
+            iconColor = iconColor,
             disabledBackgroundPainter = disabledBackgroundPainter,
             disabledContentColor = contentColor.copy(alpha = ContentAlpha.disabled),
             disabledSecondaryContentColor = secondaryContentColor.copy(
                 alpha = ContentAlpha.disabled
             ),
-            disabledIconTintColor = iconTintColor.copy(alpha = ContentAlpha.disabled),
+            disabledIconColor = iconColor.copy(alpha = ContentAlpha.disabled),
         )
     }
 
@@ -694,32 +694,32 @@
      * @param backgroundColor The background color of this [Chip] when enabled
      * @param contentColor The content color of this [Chip] when enabled
      * @param secondaryContentColor The content color of this [Chip] when enabled
-     * @param iconTintColor The content color of this [Chip] when enabled
+     * @param iconColor The content color of this [Chip] when enabled
      * @param disabledBackgroundColor The background color of this [Chip] when not enabled
      * @param disabledContentColor The content color of this [Chip] when not enabled
      * @param disabledSecondaryContentColor The content color of this [Chip] when not enabled
-     * @param disabledIconTintColor The content color of this [Chip] when not enabled
+     * @param disabledIconColor The content color of this [Chip] when not enabled
      */
     @Composable
     public fun chipColors(
         backgroundColor: Color = MaterialTheme.colors.primary,
         contentColor: Color = contentColorFor(backgroundColor),
         secondaryContentColor: Color = contentColor,
-        iconTintColor: Color = contentColor,
+        iconColor: Color = contentColor,
         disabledBackgroundColor: Color = backgroundColor.copy(alpha = ContentAlpha.disabled),
         disabledContentColor: Color = contentColor.copy(alpha = ContentAlpha.disabled),
         disabledSecondaryContentColor: Color =
             secondaryContentColor.copy(alpha = ContentAlpha.disabled),
-        disabledIconTintColor: Color = iconTintColor.copy(alpha = ContentAlpha.disabled),
+        disabledIconColor: Color = iconColor.copy(alpha = ContentAlpha.disabled),
     ): ChipColors = DefaultChipColors(
         backgroundColor = backgroundColor,
         contentColor = contentColor,
         secondaryContentColor = secondaryContentColor,
-        iconTintColor = iconTintColor,
+        iconColor = iconColor,
         disabledBackgroundColor = disabledBackgroundColor,
         disabledContentColor = disabledContentColor,
         disabledSecondaryContentColor = disabledSecondaryContentColor,
-        disabledIconTintColor = disabledIconTintColor,
+        disabledIconColor = disabledIconColor,
     )
 }
 
@@ -731,31 +731,31 @@
     private val backgroundPainter: Painter,
     private val contentColor: Color,
     private val secondaryContentColor: Color,
-    private val iconTintColor: Color,
+    private val iconColor: Color,
     private val disabledBackgroundPainter: Painter,
     private val disabledContentColor: Color,
     private val disabledSecondaryContentColor: Color,
-    private val disabledIconTintColor: Color,
+    private val disabledIconColor: Color,
 ) : ChipColors {
 
     constructor(
         backgroundColor: Color,
         contentColor: Color,
         secondaryContentColor: Color,
-        iconTintColor: Color,
+        iconColor: Color,
         disabledBackgroundColor: Color,
         disabledContentColor: Color,
         disabledSecondaryContentColor: Color,
-        disabledIconTintColor: Color
+        disabledIconColor: Color
     ) : this(
         ColorPainter(backgroundColor),
         contentColor,
         secondaryContentColor,
-        iconTintColor,
+        iconColor,
         ColorPainter(disabledBackgroundColor),
         disabledContentColor,
         disabledSecondaryContentColor,
-        disabledIconTintColor
+        disabledIconColor
     )
 
     @Composable
@@ -780,8 +780,8 @@
     }
 
     @Composable
-    override fun iconTintColor(enabled: Boolean): State<Color> {
-        return rememberUpdatedState(if (enabled) iconTintColor else disabledIconTintColor)
+    override fun iconColor(enabled: Boolean): State<Color> {
+        return rememberUpdatedState(if (enabled) iconColor else disabledIconColor)
     }
 
     override fun equals(other: Any?): Boolean {
@@ -794,11 +794,11 @@
         if (backgroundPainter != other.backgroundPainter) return false
         if (contentColor != other.contentColor) return false
         if (secondaryContentColor != other.secondaryContentColor) return false
-        if (iconTintColor != other.iconTintColor) return false
+        if (iconColor != other.iconColor) return false
         if (disabledBackgroundPainter != other.disabledBackgroundPainter) return false
         if (disabledContentColor != other.disabledContentColor) return false
         if (disabledSecondaryContentColor != other.disabledSecondaryContentColor) return false
-        if (disabledIconTintColor != other.disabledIconTintColor) return false
+        if (disabledIconColor != other.disabledIconColor) return false
 
         return true
     }
@@ -807,11 +807,11 @@
         var result = backgroundPainter.hashCode()
         result = 31 * result + contentColor.hashCode()
         result = 31 * result + secondaryContentColor.hashCode()
-        result = 31 * result + iconTintColor.hashCode()
+        result = 31 * result + iconColor.hashCode()
         result = 31 * result + disabledBackgroundPainter.hashCode()
         result = 31 * result + disabledContentColor.hashCode()
         result = 31 * result + disabledSecondaryContentColor.hashCode()
-        result = 31 * result + disabledIconTintColor.hashCode()
+        result = 31 * result + disabledIconColor.hashCode()
         return result
     }
 }
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
index 9b737ad..e9c7451 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
@@ -200,6 +200,43 @@
     }
 }
 
+/**
+ * Parameters to determine which list item and offset to calculate auto-centering spacing for.
+ *
+ * @param itemIndex Which list item index to enable auto-centering from. Space (padding) will be
+ * added such that items with index [itemIndex] or greater will be able to be scrolled to the center
+ * of the viewport. If the developer wants to add additional space to allow other list items to also
+ * be scrollable to the center they can use contentPadding on the ScalingLazyColumn. If the
+ * developer wants custom control over position and spacing they can switch off autoCentering
+ * and provide contentPadding.
+ *
+ * @param itemOffset What offset, if any, to apply when calculating space for auto-centering
+ * the [itemIndex] item. E.g. itemOffset can be used if the developer wants to align the viewport
+ * center in the gap between two list items.
+ *
+ * For an example of a [ScalingLazyColumn] with an explicit itemOffset see:
+ * @sample androidx.wear.compose.material.samples.ScalingLazyColumnEdgeAnchoredAndAnimatedScrollTo
+ */
+@Immutable
+public class AutoCenteringParams(
+    // @IntRange(from = 0)
+    internal val itemIndex: Int = 1,
+    internal val itemOffset: Int = 0,
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        return (other is AutoCenteringParams) &&
+            itemIndex == other.itemIndex &&
+            itemOffset == other.itemOffset
+    }
+
+    override fun hashCode(): Int {
+        var result = itemIndex
+        result = 31 * result + itemOffset
+        return result
+    }
+}
+
 internal fun convertToCenterOffset(
     anchorType: ScalingLazyListAnchorType,
     itemScrollOffset: Int,
@@ -262,14 +299,14 @@
  * @param scalingParams The parameters to configure the scaling and transparency effects for the
  * component
  * @param anchorType How to anchor list items to the center-line of the viewport
- * @param autoCentering Flag to indicate whether space/padding should be automatically added to make
- * sure that list items can be scrolled into the center of the viewport (based on their
- * [anchorType]). If true then space will be added before the first list item, if needed, to ensure
- * that items with indexes greater than or equal to the initialCenterItemIndex passed to
- * [ScalingLazyListState] will be able to be scrolled to the center. Similarly space will be added
- * at the end of the list to ensure that items can be scrolled up to the center. If false no
- * automatic space will be added and instead the developer can use [contentPadding] to manually
- * arrange the items.
+ * @param autoCentering AutoCenteringParams parameter to control whether space/padding should be
+ * automatically added to make sure that list items can be scrolled into the center of the viewport
+ * (based on their [anchorType]). If non-null then space will be added before the first list item,
+ * if needed, to ensure that items with indexes greater than or equal to the itemIndex (offset by
+ * itemOffset pixels) will be able to be scrolled to the center of the viewport. Similarly space
+ * will be added at the end of the list to ensure that items can be scrolled up to the center. If
+ * null no automatic space will be added and instead the developer can use [contentPadding] to
+ * manually arrange the items.
  */
 @Composable
 public fun ScalingLazyColumn(
@@ -287,7 +324,7 @@
     userScrollEnabled: Boolean = true,
     scalingParams: ScalingParams = ScalingLazyColumnDefaults.scalingParams(),
     anchorType: ScalingLazyListAnchorType = ScalingLazyListAnchorType.ItemCenter,
-    autoCentering: Boolean = true,
+    autoCentering: AutoCenteringParams? = AutoCenteringParams(),
     content: ScalingLazyListScope.() -> Unit
 ) {
     var initialized by remember { mutableStateOf(false) }
@@ -360,7 +397,7 @@
                 )
                 // Only add spacers if autoCentering == true as we have to consider the impact of
                 // vertical spacing between items.
-                if (autoCentering) {
+                if (autoCentering != null) {
                     item {
                         Spacer(
                             modifier = Modifier.height(state.topAutoCenteringItemSizePx.toDp())
@@ -368,7 +405,7 @@
                     }
                 }
                 scope.content()
-                if (autoCentering) {
+                if (autoCentering != null) {
                     item {
                         Spacer(
                             modifier = Modifier.height(state.bottomAutoCenteringItemSizePx.toDp())
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index f5a3607..88e9896 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -346,7 +346,7 @@
     scalingParams: ScalingParams,
     beforeContentPaddingPx: Int,
     anchorType: ScalingLazyListAnchorType,
-    autoCentering: Boolean,
+    autoCentering: AutoCenteringParams?,
     initialized: Boolean
 ): ScalingLazyListItemInfo {
     val adjustedItemStart = itemStart - verticalAdjustment
@@ -381,7 +381,7 @@
     )
     return DefaultScalingLazyListItemInfo(
         // Adjust index to take into account the Spacer before the first list item
-        index = if (autoCentering) item.index - 1 else item.index,
+        index = if (autoCentering != null) item.index - 1 else item.index,
         key = item.key,
         unadjustedOffset = unadjustedOffset,
         offset = offset,
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
index 04e33f8..6ba18f5 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListState.kt
@@ -39,12 +39,7 @@
  *
  * @param initialCenterItemIndex the initial value for [ScalingLazyListState.centerItemIndex],
  * defaults to 1. This will place the 2nd list item (index == 1) in the center of the viewport and
- * the first item (index == 0) before it. Note that if [ScalingLazyColumn] autoCentering property is
- * set to true then space (padding) will be added such that items with index
- * [initialCenterItemIndex] or greater will be able to be scrolled to the center of the viewport. If
- * the developer wants to add additional space to allow other list items to also be scrollable to
- * the center they can use contentPadding on the ScalingLazyColumn. If the developer wants custom
- * control over position and spacing they can switch off autoCentering and provide contentPadding.
+ * the first item (index == 0) before it.
  *
  * @param initialCenterItemScrollOffset the initial value for
  * [ScalingLazyListState.centerItemScrollOffset] in pixels
@@ -69,11 +64,7 @@
  *
  * @param initialCenterItemIndex the initial value for [ScalingLazyListState.centerItemIndex],
  * defaults to 1. This will place the 2nd list item (index == 1) in the center of the viewport and
- * the first item (index == 0) before it. Note that if [ScalingLazyColumn] autoCentering property is
- * set to true then space (padding) will be added such that items with index
- * [initialCenterItemIndex] or greater will be able to be scrolled to the center of the viewport. If
- * the developer wants to add additional space to allow other list items to also be scrollable to
- * the center they can use contentPadding on the ScalingLazyColumn.
+ * the first item (index == 0) before it.
  *
  * If the developer wants custom control over position and spacing they can switch off autoCentering
  * and provide contentPadding.
@@ -96,7 +87,7 @@
     internal val viewportHeightPx = mutableStateOf<Int?>(null)
     internal val reverseLayout = mutableStateOf<Boolean?>(null)
     internal val anchorType = mutableStateOf<ScalingLazyListAnchorType?>(null)
-    internal val autoCentering = mutableStateOf<Boolean?>(null)
+    internal val autoCentering = mutableStateOf<AutoCenteringParams?>(null)
     internal val initialized = mutableStateOf<Boolean>(false)
 
     /**
@@ -112,7 +103,7 @@
             gapBetweenItemsPx.value == null || viewportHeightPx.value == null ||
             anchorType.value == null || reverseLayout.value == null ||
             beforeContentPaddingPx.value == null || autoCentering.value == null ||
-            !autoCentering.value!! || layoutInfo.visibleItemsInfo.isEmpty()
+            autoCentering.value == null || layoutInfo.visibleItemsInfo.isEmpty()
         ) {
             0
         } else {
@@ -150,7 +141,7 @@
         if (extraPaddingPx.value == null || scalingParams.value == null ||
             gapBetweenItemsPx.value == null || viewportHeightPx.value == null ||
             anchorType.value == null || reverseLayout.value == null ||
-            beforeContentPaddingPx.value == null || autoCentering.value == null
+            beforeContentPaddingPx.value == null
         ) {
             EmptyScalingLazyListLayoutInfo
         } else {
@@ -184,7 +175,7 @@
                     scalingParams.value!!,
                     beforeContentPaddingPx.value!!,
                     anchorType.value!!,
-                    autoCentering.value!!,
+                    autoCentering.value,
                     initialized.value
                 )
                 visibleItemsInfo.add(
@@ -227,7 +218,7 @@
                                 scalingParams.value!!,
                                 beforeContentPaddingPx.value!!,
                                 anchorType.value!!,
-                                autoCentering.value!!,
+                                autoCentering.value,
                                 initialized.value
                             )
                             visibleItemsInfo.add(0, itemInfo)
@@ -261,7 +252,7 @@
                                 scalingParams.value!!,
                                 beforeContentPaddingPx.value!!,
                                 anchorType.value!!,
-                                autoCentering.value!!,
+                                autoCentering.value,
                                 initialized.value
                             )
 
@@ -274,7 +265,7 @@
                 }
             }
             val totalItemsCount =
-                if (autoCentering.value!!) {
+                if (autoCentering.value != null) {
                     (lazyListState.layoutInfo.totalItemsCount - 2).coerceAtLeast(0)
                 } else {
                     lazyListState.layoutInfo.totalItemsCount
@@ -290,7 +281,7 @@
                 // Not already initialized
                 !initialized.value && (
                     // Not autoCentering
-                    !autoCentering.value!! || (
+                    autoCentering.value == null || (
                         lazyListState.layoutInfo.visibleItemsInfo.size >= 2 && (
                             // or Empty list (other than the 2 spacers)
                             lazyListState.layoutInfo.visibleItemsInfo.size == 2 ||
@@ -411,7 +402,7 @@
             initialCenterItemScrollOffset = scrollOffset
             return
         }
-        val lazyListStateIndex = if (autoCentering.value!!) index + 1 else index
+        val lazyListStateIndex = if (autoCentering.value != null) index + 1 else index
         val offsetToCenterOfViewport =
             beforeContentPaddingPx.value!! - (viewportHeightPx.value!! / 2)
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
@@ -462,7 +453,7 @@
     ) {
         // Convert the index to take into account the Spacer added to the underlying LazyList before
         // the first ScalingLazyColumn list item
-        val lazyListStateIndex = if (autoCentering.value!!) index + 1 else index
+        val lazyListStateIndex = if (autoCentering.value != null) index + 1 else index
         val offsetToCenterOfViewport =
             beforeContentPaddingPx.value!! - (viewportHeightPx.value!! / 2)
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
@@ -492,24 +483,24 @@
     }
 
     private fun discardAutoCenteringListItem(item: LazyListItemInfo): Boolean =
-        autoCentering.value!! &&
+        autoCentering.value != null &&
             (item.index == 0 || item.index == lazyListState.layoutInfo.totalItemsCount - 1)
 
     /**
      * Calculate the amount of top padding needed (if any) to make sure that the
-     * [initialCenterItemIndex] item can be placed in the center of the viewport at
-     * [initialCenterItemScrollOffset]
+     * [AutoCenteringParams.itemIndex] item can be placed in the center of the viewport at
+     * [AutoCenteringParams.itemOffset]
      */
     private fun calculateTopAutoCenteringPaddingPx(
         visibleItems: List<ScalingLazyListItemInfo>,
         totalItemCount: Int
     ): Int {
-        if (! autoCentering.value!! || visibleItems.isEmpty() ||
+        if (autoCentering.value == null || visibleItems.isEmpty() ||
             visibleItems.first().index != 0) return 0
 
         // Work out the index we want to find - if there are less items in the list than would be
         // needed to make initialItemIndex be visible then use the last visible item
-        val itemIndexToFind = initialCenterItemIndex.coerceAtMost(totalItemCount - 1)
+        val itemIndexToFind = autoCentering.value!!.itemIndex.coerceAtMost(totalItemCount - 1)
 
         // Find the initialCenterItem, if it is null that means it is not in view - therefore
         // we have more than enough content before it to make sure it can be scrolled to the center
@@ -534,22 +525,22 @@
 
     /**
      * Calculate the amount of top padding needed (if any) to make sure that the
-     * [initialCenterItemIndex] item can be placed in the center of the viewport at
-     * [initialCenterItemScrollOffset]
+     * [AutoCenteringParams.itemIndex] item can be placed in the center of the viewport at
+     * [AutoCenteringParams.itemOffset]
      */
     private fun calculateTopAutoCenteringPaddingFromLazyListItemInfo(
         visibleItems: List<LazyListItemInfo>,
         totalItemCount: Int
     ): Int {
         // Check is list is empty or we are not at the start of the visible items
-        if (visibleItems.isEmpty() || visibleItems.isEmpty() ||
+        if (autoCentering.value == null || visibleItems.isEmpty() ||
             visibleItems[0].index != 0) return 0
 
         // Work out the index we want to find - if there are less items in the list than would be
         // needed to make initialItemIndex be visible then use the last visible item. The -3 is to
         // allow for the spacers, i.e. an underlying list of size 3 has 2 spacers in index 0 and 2
         // and one real item in index 1.
-        val itemIndexToFind = (initialCenterItemIndex + 1).coerceAtMost(totalItemCount - 3)
+        val itemIndexToFind = (autoCentering.value!!.itemIndex + 1).coerceAtMost(totalItemCount - 3)
 
         // Find the initialCenterItem, if it is null that means it is not in view - therefore
         // we have more than enough content before it to make sure it can be scrolled to the center
@@ -578,12 +569,12 @@
         } else {
             viewportHeightPx.value!! / 2f -
                 unadjustedSize / 2f
-        } - gapBetweenItemsPx.value!! - initialCenterItemScrollOffset
+        } - gapBetweenItemsPx.value!! - autoCentering.value!!.itemOffset
 
     private fun calculateBottomAutoCenteringPaddingPx(
         visibleItemsInfo: List<ScalingLazyListItemInfo>,
         totalItemsCount: Int
-    ) = if (autoCentering.value!! && visibleItemsInfo.isNotEmpty() &&
+    ) = if (autoCentering.value != null && visibleItemsInfo.isNotEmpty() &&
         visibleItemsInfo.last().index == totalItemsCount - 1
     ) {
         if (anchorType.value == ScalingLazyListAnchorType.ItemStart) {
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Stepper.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Stepper.kt
index 0d7bb08..52c4b58 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Stepper.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Stepper.kt
@@ -70,7 +70,7 @@
  * this range
  * @param backgroundColor [Color] representing the background color for the stepper.
  * @param contentColor [Color] representing the color for [content] in the middle.
- * @param iconTintColor Icon tint [Color] which used by [increaseIcon] and [decreaseIcon]
+ * @param iconColor Icon tint [Color] which used by [increaseIcon] and [decreaseIcon]
  * that defaults to [contentColor], unless specifically overridden.
  */
 @Composable
@@ -84,7 +84,7 @@
     valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat(),
     backgroundColor: Color = MaterialTheme.colors.background,
     contentColor: Color = contentColorFor(backgroundColor),
-    iconTintColor: Color = contentColor,
+    iconColor: Color = contentColor,
     content: @Composable BoxScope.() -> Unit
 ) {
     require(steps >= 0) { "steps should be >= 0" }
@@ -113,7 +113,7 @@
             onClick = { updateValue(1) },
             contentAlignment = Alignment.TopCenter,
             paddingValues = PaddingValues(top = StepperDefaults.BorderPadding),
-            iconTintColor = iconTintColor,
+            iconColor = iconColor,
             content = increaseIcon
         )
         Box(
@@ -132,7 +132,7 @@
             contentAlignment = Alignment.BottomCenter,
             paddingValues = PaddingValues(bottom = StepperDefaults.BorderPadding),
             content = decreaseIcon,
-            iconTintColor = iconTintColor
+            iconColor = iconColor
         )
     }
 }
@@ -167,7 +167,7 @@
  * @param modifier Modifiers for the Stepper layout
  * @param backgroundColor [Color] representing the background color for the stepper.
  * @param contentColor [Color] representing the color for [content] in the middle.
- * @param iconTintColor Icon tint [Color] which used by [increaseIcon] and [decreaseIcon]
+ * @param iconColor Icon tint [Color] which used by [increaseIcon] and [decreaseIcon]
  * that defaults to [contentColor], unless specifically overridden.
  */
 @Composable
@@ -180,7 +180,7 @@
     modifier: Modifier = Modifier,
     backgroundColor: Color = MaterialTheme.colors.background,
     contentColor: Color = contentColorFor(backgroundColor),
-    iconTintColor: Color = contentColor,
+    iconColor: Color = contentColor,
     content: @Composable BoxScope.() -> Unit
 ) {
     Stepper(
@@ -193,7 +193,7 @@
         increaseIcon = increaseIcon,
         backgroundColor = backgroundColor,
         contentColor = contentColor,
-        iconTintColor = iconTintColor,
+        iconColor = iconColor,
         content = content
     )
 }
@@ -222,7 +222,7 @@
     onClick: () -> Unit,
     contentAlignment: Alignment,
     paddingValues: PaddingValues,
-    iconTintColor: Color,
+    iconColor: Color,
     content: @Composable () -> Unit
 ) {
     val interactionSource = remember { MutableInteractionSource() }
@@ -236,6 +236,6 @@
             .padding(paddingValues),
         contentAlignment = contentAlignment,
     ) {
-        CompositionLocalProvider(LocalContentColor provides iconTintColor, content = content)
+        CompositionLocalProvider(LocalContentColor provides iconColor, content = content)
     }
 }
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
index 22075d5..824eee3 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/SwipeToDismissBox.kt
@@ -324,7 +324,7 @@
      */
     public suspend fun snapTo(targetValue: SwipeToDismissValue) = swipeableState.snapTo(targetValue)
 
-    companion object {
+    private companion object {
         private fun <T> SwipeableState<T>.edgeNestedScrollConnection(
             edgeTouched: State<Boolean>
         ): NestedScrollConnection =
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ToggleChip.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ToggleChip.kt
index 83af166..8ed97d3 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ToggleChip.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ToggleChip.kt
@@ -198,12 +198,12 @@
                 )
                 CompositionLocalProvider(
                     LocalContentColor provides
-                        colors.toggleControlTintColor(
+                        colors.toggleControlColor(
                             enabled = enabled,
                             checked = checked
                         ).value,
                     LocalContentAlpha provides
-                        colors.toggleControlTintColor(
+                        colors.toggleControlColor(
                             enabled = enabled,
                             checked = checked
                         ).value.alpha,
@@ -376,12 +376,12 @@
             ) {
                 CompositionLocalProvider(
                     LocalContentColor provides
-                        colors.toggleControlTintColor(
+                        colors.toggleControlColor(
                             enabled = enabled,
                             checked = checked
                         ).value,
                     LocalContentAlpha provides
-                        colors.toggleControlTintColor(
+                        colors.toggleControlColor(
                             enabled = enabled,
                             checked = checked
                         ).value.alpha,
@@ -461,14 +461,14 @@
     public fun secondaryContentColor(enabled: Boolean, checked: Boolean): State<Color>
 
     /**
-     * Represents the icon tint color for the toggle control for this chip, depending on the
-     * [enabled] and [checked]properties.
+     * Represents the color for the toggle control content for this chip, depending on the
+     * [enabled] and [checked] properties.
      *
      * @param enabled Whether the chip is enabled
      * @param checked Whether the chip is currently checked/selected or unchecked/not selected
      */
     @Composable
-    public fun toggleControlTintColor(enabled: Boolean, checked: Boolean): State<Color>
+    public fun toggleControlColor(enabled: Boolean, checked: Boolean): State<Color>
 }
 
 /**
@@ -501,14 +501,14 @@
     public fun secondaryContentColor(enabled: Boolean): State<Color>
 
     /**
-     * Represents the icon tint color for the toggle control for this chip, depending on the
-     * [enabled] and [checked]properties.
+     * Represents the color for the toggle control content for this chip, depending on the
+     * [enabled] and [checked] properties.
      *
      * @param enabled Whether the chip is enabled
      * @param checked Whether the chip is currently checked/selected or unchecked/not selected
      */
     @Composable
-    public fun toggleControlTintColor(enabled: Boolean, checked: Boolean): State<Color>
+    public fun toggleControlColor(enabled: Boolean, checked: Boolean): State<Color>
 
     /**
      * Represents the overlay to apply to a split background SplitToggleChip to distinguish
@@ -542,8 +542,8 @@
      * checked/selected.
      * @param checkedSecondaryContentColor The secondary content color of this [ToggleChip] when
      * enabled and checked/selected, used for secondaryLabel content
-     * @param checkedToggleControlTintColor The icon tint color of this [ToggleChip] when enabled
-     * and checked/selected, used for ToggleControl content
+     * @param checkedToggleControlColor The toggle control color of this [ToggleChip] when enabled
+     * and checked/selected, used for toggleControl content
      * @param uncheckedStartBackgroundColor The background color used at the start of the gradient
      * of a [ToggleChip] when enabled and unchecked/not selected.
      * @param uncheckedEndBackgroundColor The background color used at the end of the gradient of a
@@ -552,8 +552,8 @@
      * checked/selected.
      * @param uncheckedSecondaryContentColor The secondary content color of this [ToggleChip] when
      * enabled and unchecked/not selected, used for secondaryLabel content
-     * @param uncheckedToggleControlTintColor The icon tint color of this [ToggleChip] when enabled
-     * and unchecked/not selected, used for ToggleControl content
+     * @param uncheckedToggleControlColor The toggle control color of this [ToggleChip] when enabled
+     * and unchecked/not selected.
      * @param gradientDirection Whether the chips gradient should be start to end (indicated by
      * [LayoutDirection.Ltr]) or end to start (indicated by [LayoutDirection.Rtl]).
      */
@@ -563,12 +563,12 @@
         checkedEndBackgroundColor: Color = MaterialTheme.colors.primary.copy(alpha = 0.325f),
         checkedContentColor: Color = MaterialTheme.colors.onSurface,
         checkedSecondaryContentColor: Color = MaterialTheme.colors.onSurfaceVariant,
-        checkedToggleControlTintColor: Color = MaterialTheme.colors.secondary,
+        checkedToggleControlColor: Color = MaterialTheme.colors.secondary,
         uncheckedStartBackgroundColor: Color = MaterialTheme.colors.surface,
         uncheckedEndBackgroundColor: Color = uncheckedStartBackgroundColor,
         uncheckedContentColor: Color = contentColorFor(checkedEndBackgroundColor),
         uncheckedSecondaryContentColor: Color = uncheckedContentColor,
-        uncheckedToggleControlTintColor: Color = uncheckedContentColor,
+        uncheckedToggleControlColor: Color = uncheckedContentColor,
         gradientDirection: LayoutDirection = LocalLayoutDirection.current
     ): ToggleChipColors {
         val checkedBackgroundColors: List<Color>
@@ -618,13 +618,13 @@
             checkedBackgroundPainter = BrushPainter(Brush.linearGradient(checkedBackgroundColors)),
             checkedContentColor = checkedContentColor,
             checkedSecondaryContentColor = checkedSecondaryContentColor,
-            checkedIconTintColor = checkedToggleControlTintColor,
+            checkedIconColor = checkedToggleControlColor,
             uncheckedBackgroundPainter = BrushPainter(
                 Brush.linearGradient(uncheckedBackgroundColors)
             ),
             uncheckedContentColor = uncheckedContentColor,
             uncheckedSecondaryContentColor = uncheckedSecondaryContentColor,
-            uncheckedIconTintColor = uncheckedToggleControlTintColor,
+            uncheckedIconColor = uncheckedToggleControlColor,
             disabledCheckedBackgroundPainter = BrushPainter(
                 Brush.linearGradient(disabledCheckedBackgroundColors)
             ),
@@ -632,7 +632,7 @@
             disabledCheckedSecondaryContentColor = checkedSecondaryContentColor.copy(
                 alpha = ContentAlpha.disabled
             ),
-            disabledCheckedIconTintColor = checkedToggleControlTintColor.copy(
+            disabledCheckedIconColor = checkedToggleControlColor.copy(
                 alpha = ContentAlpha.disabled
             ),
             disabledUncheckedBackgroundPainter = BrushPainter(
@@ -644,7 +644,7 @@
             disabledUncheckedSecondaryContentColor = uncheckedSecondaryContentColor.copy(
                 alpha = ContentAlpha.disabled
             ),
-            disabledUncheckedIconTintColor = uncheckedToggleControlTintColor.copy(
+            disabledUncheckedIconColor = uncheckedToggleControlColor.copy(
                 alpha = ContentAlpha.disabled
             ),
         )
@@ -657,10 +657,10 @@
      * @param contentColor The content color of this [SplitToggleChip] when enabled.
      * @param secondaryContentColor The secondary content color of this[SplitToggleChip] when
      * enabled
-     * @param checkedToggleControlTintColor The icon tint color of this [SplitToggleChip] when
-     * enabled, used for ToggleControl content
-     * @param uncheckedToggleControlTintColor The icon tint color of this [SplitToggleChip] when
-     * enabled, used for ToggleControl content
+     * @param checkedToggleControlColor The toggle control content color of this [SplitToggleChip]
+     * when enabled.
+     * @param uncheckedToggleControlColor The toggle control content color of this [SplitToggleChip]
+     * when enabled.
      * @param splitBackgroundOverlayColor The color to use to lighten/distinguish the background
      * behind the ToggleControl for a split background chip. A split background chip has two
      * tappable areas, one for the main body of the chip and one for area around the toggle
@@ -671,28 +671,28 @@
         backgroundColor: Color = MaterialTheme.colors.surface,
         contentColor: Color = MaterialTheme.colors.onSurface,
         secondaryContentColor: Color = MaterialTheme.colors.onSurfaceVariant,
-        checkedToggleControlTintColor: Color = MaterialTheme.colors.secondary,
-        uncheckedToggleControlTintColor: Color = contentColor,
+        checkedToggleControlColor: Color = MaterialTheme.colors.secondary,
+        uncheckedToggleControlColor: Color = contentColor,
         splitBackgroundOverlayColor: Color = Color.White.copy(alpha = 0.05f),
     ): SplitToggleChipColors {
         return DefaultSplitToggleChipColors(
             backgroundColor = backgroundColor,
             contentColor = contentColor,
             secondaryContentColor = secondaryContentColor,
-            checkedIconTintColor = checkedToggleControlTintColor,
+            checkedIconColor = checkedToggleControlColor,
             checkedSplitBackgroundOverlay = splitBackgroundOverlayColor,
-            uncheckedIconTintColor = uncheckedToggleControlTintColor,
+            uncheckedIconColor = uncheckedToggleControlColor,
             uncheckedSplitBackgroundOverlay = splitBackgroundOverlayColor,
             disabledBackgroundColor = backgroundColor.copy(alpha = ContentAlpha.disabled),
             disabledContentColor = contentColor.copy(alpha = ContentAlpha.disabled),
             disabledSecondaryContentColor = secondaryContentColor.copy(
                 alpha = ContentAlpha.disabled
             ),
-            disabledCheckedIconTintColor = checkedToggleControlTintColor.copy(
+            disabledCheckedIconColor = checkedToggleControlColor.copy(
                 alpha = ContentAlpha.disabled
             ),
             disabledCheckedSplitBackgroundOverlay = splitBackgroundOverlayColor,
-            disabledUncheckedIconTintColor = uncheckedToggleControlTintColor.copy(
+            disabledUncheckedIconColor = uncheckedToggleControlColor.copy(
                 alpha = ContentAlpha.disabled
             ),
             disabledUncheckedSplitBackgroundOverlay = splitBackgroundOverlayColor,
@@ -700,7 +700,7 @@
     }
 
     /**
-     * The Wear Material UX recommended tint color to use for an unselected switch icon.
+     * The Wear Material UX recommended color to use for an unselected switch icon.
      */
     public val SwitchUncheckedIconColor: Color
         @Composable get() = MaterialTheme.colors.onSurface.copy(0.6f)
@@ -981,19 +981,19 @@
     private val checkedBackgroundPainter: Painter,
     private val checkedContentColor: Color,
     private val checkedSecondaryContentColor: Color,
-    private val checkedIconTintColor: Color,
+    private val checkedIconColor: Color,
     private val disabledCheckedBackgroundPainter: Painter,
     private val disabledCheckedContentColor: Color,
     private val disabledCheckedSecondaryContentColor: Color,
-    private val disabledCheckedIconTintColor: Color,
+    private val disabledCheckedIconColor: Color,
     private val uncheckedBackgroundPainter: Painter,
     private val uncheckedContentColor: Color,
     private val uncheckedSecondaryContentColor: Color,
-    private val uncheckedIconTintColor: Color,
+    private val uncheckedIconColor: Color,
     private val disabledUncheckedBackgroundPainter: Painter,
     private val disabledUncheckedContentColor: Color,
     private val disabledUncheckedSecondaryContentColor: Color,
-    private val disabledUncheckedIconTintColor: Color,
+    private val disabledUncheckedIconColor: Color,
 ) : ToggleChipColors {
 
     @Composable
@@ -1032,12 +1032,12 @@
     }
 
     @Composable
-    override fun toggleControlTintColor(enabled: Boolean, checked: Boolean): State<Color> {
+    override fun toggleControlColor(enabled: Boolean, checked: Boolean): State<Color> {
         return rememberUpdatedState(
             if (enabled) {
-                if (checked) checkedIconTintColor else uncheckedIconTintColor
+                if (checked) checkedIconColor else uncheckedIconColor
             } else {
-                if (checked) disabledCheckedIconTintColor else disabledUncheckedIconTintColor
+                if (checked) disabledCheckedIconColor else disabledUncheckedIconColor
             }
         )
     }
@@ -1051,15 +1051,15 @@
 
         if (checkedBackgroundPainter != other.checkedBackgroundPainter) return false
         if (checkedContentColor != other.checkedContentColor) return false
-        if (checkedIconTintColor != other.checkedIconTintColor) return false
+        if (checkedIconColor != other.checkedIconColor) return false
         if (checkedSecondaryContentColor != other.checkedSecondaryContentColor) return false
         if (uncheckedBackgroundPainter != other.uncheckedBackgroundPainter) return false
         if (uncheckedContentColor != other.uncheckedContentColor) return false
-        if (uncheckedIconTintColor != other.uncheckedIconTintColor) return false
+        if (uncheckedIconColor != other.uncheckedIconColor) return false
         if (uncheckedSecondaryContentColor != other.uncheckedSecondaryContentColor) return false
         if (disabledCheckedBackgroundPainter != other.disabledCheckedBackgroundPainter) return false
         if (disabledCheckedContentColor != other.disabledCheckedContentColor) return false
-        if (disabledCheckedIconTintColor != other.disabledCheckedIconTintColor) return false
+        if (disabledCheckedIconColor != other.disabledCheckedIconColor) return false
         if (disabledCheckedSecondaryContentColor !=
             other.disabledCheckedSecondaryContentColor
         ) return false
@@ -1067,7 +1067,7 @@
             other.disabledUncheckedBackgroundPainter
         ) return false
         if (disabledUncheckedContentColor != other.disabledUncheckedContentColor) return false
-        if (disabledUncheckedIconTintColor != other.disabledUncheckedIconTintColor) return false
+        if (disabledUncheckedIconColor != other.disabledUncheckedIconColor) return false
         if (disabledUncheckedSecondaryContentColor !=
             other.disabledUncheckedSecondaryContentColor
         ) return false
@@ -1079,19 +1079,19 @@
         var result = checkedBackgroundPainter.hashCode()
         result = 31 * result + checkedContentColor.hashCode()
         result = 31 * result + checkedSecondaryContentColor.hashCode()
-        result = 31 * result + checkedIconTintColor.hashCode()
+        result = 31 * result + checkedIconColor.hashCode()
         result = 31 * result + uncheckedBackgroundPainter.hashCode()
         result = 31 * result + uncheckedContentColor.hashCode()
         result = 31 * result + uncheckedSecondaryContentColor.hashCode()
-        result = 31 * result + uncheckedIconTintColor.hashCode()
+        result = 31 * result + uncheckedIconColor.hashCode()
         result = 31 * result + disabledCheckedBackgroundPainter.hashCode()
         result = 31 * result + disabledCheckedContentColor.hashCode()
         result = 31 * result + disabledCheckedSecondaryContentColor.hashCode()
-        result = 31 * result + disabledCheckedIconTintColor.hashCode()
+        result = 31 * result + disabledCheckedIconColor.hashCode()
         result = 31 * result + disabledUncheckedBackgroundPainter.hashCode()
         result = 31 * result + disabledUncheckedContentColor.hashCode()
         result = 31 * result + disabledUncheckedSecondaryContentColor.hashCode()
-        result = 31 * result + disabledUncheckedIconTintColor.hashCode()
+        result = 31 * result + disabledUncheckedIconColor.hashCode()
         return result
     }
 }
@@ -1104,16 +1104,16 @@
     private val backgroundColor: Color,
     private val contentColor: Color,
     private val secondaryContentColor: Color,
-    private val checkedIconTintColor: Color,
+    private val checkedIconColor: Color,
     private val checkedSplitBackgroundOverlay: Color,
     private val disabledBackgroundColor: Color,
     private val disabledContentColor: Color,
     private val disabledSecondaryContentColor: Color,
-    private val disabledCheckedIconTintColor: Color,
+    private val disabledCheckedIconColor: Color,
     private val disabledCheckedSplitBackgroundOverlay: Color,
-    private val uncheckedIconTintColor: Color,
+    private val uncheckedIconColor: Color,
     private val uncheckedSplitBackgroundOverlay: Color,
-    private val disabledUncheckedIconTintColor: Color,
+    private val disabledUncheckedIconColor: Color,
     private val disabledUncheckedSplitBackgroundOverlay: Color,
 ) : SplitToggleChipColors {
 
@@ -1139,12 +1139,12 @@
     }
 
     @Composable
-    override fun toggleControlTintColor(enabled: Boolean, checked: Boolean): State<Color> {
+    override fun toggleControlColor(enabled: Boolean, checked: Boolean): State<Color> {
         return rememberUpdatedState(
             if (enabled) {
-                if (checked) checkedIconTintColor else uncheckedIconTintColor
+                if (checked) checkedIconColor else uncheckedIconColor
             } else {
-                if (checked) disabledCheckedIconTintColor else disabledUncheckedIconTintColor
+                if (checked) disabledCheckedIconColor else disabledUncheckedIconColor
             }
         )
     }
@@ -1170,18 +1170,18 @@
 
         if (backgroundColor != other.backgroundColor) return false
         if (contentColor != other.contentColor) return false
-        if (checkedIconTintColor != other.checkedIconTintColor) return false
+        if (checkedIconColor != other.checkedIconColor) return false
         if (checkedSplitBackgroundOverlay != other.checkedSplitBackgroundOverlay) return false
-        if (uncheckedIconTintColor != other.uncheckedIconTintColor) return false
+        if (uncheckedIconColor != other.uncheckedIconColor) return false
         if (uncheckedSplitBackgroundOverlay != other.uncheckedSplitBackgroundOverlay) return false
         if (disabledBackgroundColor != other.disabledBackgroundColor) return false
         if (disabledContentColor != other.disabledContentColor) return false
-        if (disabledCheckedIconTintColor != other.disabledCheckedIconTintColor) return false
+        if (disabledCheckedIconColor != other.disabledCheckedIconColor) return false
         if (disabledSecondaryContentColor != other.disabledSecondaryContentColor) return false
         if (disabledCheckedSplitBackgroundOverlay !=
             other.disabledCheckedSplitBackgroundOverlay
         ) return false
-        if (disabledUncheckedIconTintColor != other.disabledUncheckedIconTintColor) return false
+        if (disabledUncheckedIconColor != other.disabledUncheckedIconColor) return false
         if (disabledUncheckedSplitBackgroundOverlay !=
             other.disabledUncheckedSplitBackgroundOverlay
         ) return false
@@ -1193,16 +1193,16 @@
         var result = backgroundColor.hashCode()
         result = 31 * result + contentColor.hashCode()
         result = 31 * result + secondaryContentColor.hashCode()
-        result = 31 * result + checkedIconTintColor.hashCode()
+        result = 31 * result + checkedIconColor.hashCode()
         result = 31 * result + checkedSplitBackgroundOverlay.hashCode()
-        result = 31 * result + uncheckedIconTintColor.hashCode()
+        result = 31 * result + uncheckedIconColor.hashCode()
         result = 31 * result + uncheckedSplitBackgroundOverlay.hashCode()
         result = 31 * result + disabledBackgroundColor.hashCode()
         result = 31 * result + disabledContentColor.hashCode()
         result = 31 * result + disabledSecondaryContentColor.hashCode()
-        result = 31 * result + disabledCheckedIconTintColor.hashCode()
+        result = 31 * result + disabledCheckedIconColor.hashCode()
         result = 31 * result + disabledCheckedSplitBackgroundOverlay.hashCode()
-        result = 31 * result + disabledUncheckedIconTintColor.hashCode()
+        result = 31 * result + disabledUncheckedIconColor.hashCode()
         result = 31 * result + disabledUncheckedSplitBackgroundOverlay.hashCode()
         return result
     }
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
index ed1246d..fac57f8 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/dialog/Dialog.kt
@@ -80,7 +80,7 @@
  * @param backgroundColor [Color] representing the background color for the dialog.
  * @param contentColor [Color] representing the color for [content].
  * @param titleColor [Color] representing the color for [title].
- * @param iconTintColor Icon [Color] that defaults to [contentColor],
+ * @param iconColor Icon [Color] that defaults to [contentColor],
  * unless specifically overridden.
  * @param verticalArrangement The vertical arrangement of the dialog's children. This allows us
  * to add spacing between items and specify the arrangement of the items when we have not enough
@@ -99,7 +99,7 @@
     backgroundColor: Color = MaterialTheme.colors.background,
     contentColor: Color = contentColorFor(backgroundColor),
     titleColor: Color = contentColor,
-    iconTintColor: Color = contentColor,
+    iconColor: Color = contentColor,
     verticalArrangement: Arrangement.Vertical = DialogDefaults.AlertVerticalArrangement,
     contentPadding: PaddingValues = DialogDefaults.ContentPadding,
     content: @Composable (ColumnScope.() -> Unit)? = null
@@ -113,7 +113,7 @@
     ) {
         if (icon != null) {
             item {
-                DialogIconHeader(iconTintColor, content = icon)
+                DialogIconHeader(iconColor, content = icon)
             }
         }
 
@@ -163,7 +163,7 @@
  * @param backgroundColor [Color] representing the background color for the dialog.
  * @param titleColor [Color] representing the color for [title].
  * @param messageColor [Color] representing the color for [message].
- * @param iconTintColor [Color] representing the color for [icon].
+ * @param iconColor [Color] representing the color for [icon].
  * @param verticalArrangement The vertical arrangement of the dialog's children. This allows us
  * to add spacing between items and specify the arrangement of the items when we have not enough
  * of them to fill the whole minimum size.
@@ -180,7 +180,7 @@
     backgroundColor: Color = MaterialTheme.colors.background,
     titleColor: Color = contentColorFor(backgroundColor),
     messageColor: Color = contentColorFor(backgroundColor),
-    iconTintColor: Color = contentColorFor(backgroundColor),
+    iconColor: Color = contentColorFor(backgroundColor),
     verticalArrangement: Arrangement.Vertical = DialogDefaults.AlertVerticalArrangement,
     contentPadding: PaddingValues = DialogDefaults.ContentPadding,
     content: ScalingLazyListScope.() -> Unit
@@ -194,7 +194,7 @@
     ) {
         if (icon != null) {
             item {
-                DialogIconHeader(iconTintColor, content = icon)
+                DialogIconHeader(iconColor, content = icon)
             }
         }
 
@@ -234,7 +234,7 @@
  * [DialogDefaults.LongDurationMillis] or [DialogDefaults.IndefiniteDurationMillis].
  * @param backgroundColor [Color] representing the background color for this dialog.
  * @param contentColor [Color] representing the color for [content].
- * @param iconTintColor Icon [Color] that defaults to the [contentColor],
+ * @param iconColor Icon [Color] that defaults to the [contentColor],
  * unless specifically overridden.
  * @param verticalArrangement The vertical arrangement of the dialog's children. This allows us
  * to add spacing between items and specify the arrangement of the items when we have not enough
@@ -251,7 +251,7 @@
     durationMillis: Long = DialogDefaults.ShortDurationMillis,
     backgroundColor: Color = MaterialTheme.colors.background,
     contentColor: Color = contentColorFor(backgroundColor),
-    iconTintColor: Color = contentColor,
+    iconColor: Color = contentColor,
     verticalArrangement: Arrangement.Vertical = DialogDefaults.ConfirmationVerticalArrangement,
     contentPadding: PaddingValues = DialogDefaults.ContentPadding,
     content: @Composable ColumnScope.() -> Unit
@@ -274,7 +274,7 @@
     ) {
         if (icon != null) {
             item {
-                DialogIconHeader(iconTintColor, content = icon)
+                DialogIconHeader(iconColor, content = icon)
             }
         }
 
@@ -382,7 +382,7 @@
 ) {
     ScalingLazyColumn(
         state = scrollState,
-        autoCentering = false,
+        autoCentering = null,
         horizontalAlignment = Alignment.CenterHorizontally,
         verticalArrangement = verticalArrangement,
         contentPadding = contentPadding,
@@ -397,15 +397,15 @@
  * [DialogIconHeader] displays an icon at the top of the dialog
  * followed by the recommended spacing.
  *
- * @param iconTintColor [Color] in which to tint the icon.
+ * @param iconColor [Color] in which to tint the icon.
  * @param content Slot for an icon.
  */
 @Composable
 private fun DialogIconHeader(
-    iconTintColor: Color,
+    iconColor: Color,
     content: @Composable ColumnScope.() -> Unit
 ) {
-    CompositionLocalProvider(LocalContentColor provides iconTintColor) {
+    CompositionLocalProvider(LocalContentColor provides iconColor) {
         Column(
             modifier = Modifier.fillMaxWidth(),
             horizontalAlignment = Alignment.CenterHorizontally
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ChipDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ChipDemo.kt
index b885417..3d8cbf8 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ChipDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ChipDemo.kt
@@ -357,7 +357,7 @@
                 // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
                 // rather than the default.
                 colors = ToggleChipDefaults.toggleChipColors(
-                    uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+                    uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
                 ),
                 toggleControl = {
                     Icon(
@@ -542,7 +542,7 @@
                 // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
                 // rather than the default.
                 colors = ToggleChipDefaults.toggleChipColors(
-                    uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+                    uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
                 ),
                 toggleControl = {
                     Icon(
@@ -599,7 +599,7 @@
                 // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
                 // rather than the default.
                 colors = ToggleChipDefaults.toggleChipColors(
-                    uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+                    uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
                 ),
                 toggleControl = {
                     Icon(
@@ -657,7 +657,7 @@
             // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
             // rather than the default.
             colors = ToggleChipDefaults.toggleChipColors(
-                uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+                uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
             ),
             toggleControl = {
                 Icon(
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
index 9da029a..76fe1ef 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PositionIndicatorDemos.kt
@@ -93,7 +93,7 @@
     ) {
         ScalingLazyColumn(
             state = listState,
-            autoCentering = false
+            autoCentering = null
         ) {
             items(
                 count = if (smallList) 3 else 10
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SliderDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SliderDemo.kt
index 3bff7a8..47a1ae8 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SliderDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SliderDemo.kt
@@ -83,7 +83,7 @@
                 // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
                 // rather than the default.
                 colors = ToggleChipDefaults.toggleChipColors(
-                    uncheckedToggleControlTintColor = ToggleChipDefaults.SwitchUncheckedIconColor
+                    uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
                 ),
                 toggleControl = {
                     Icon(
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ToggleChipDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ToggleChipDemo.kt
index f2b0323..e86d6b7 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ToggleChipDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/ToggleChipDemo.kt
@@ -104,7 +104,7 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.toggleChipColors(
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     toggleControl = {
@@ -164,7 +164,7 @@
                     onCheckedChange = { radioIconWithSecondaryChecked = it },
                     enabled = enabled,
                     colors = ToggleChipDefaults.toggleChipColors(
-                        checkedToggleControlTintColor = AlternatePrimaryColor3,
+                        checkedToggleControlColor = AlternatePrimaryColor3,
                         checkedEndBackgroundColor = AlternatePrimaryColor3.copy(alpha = 0.325f)
                     )
                 )
@@ -184,7 +184,7 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.toggleChipColors(
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     toggleControl = {
@@ -213,7 +213,7 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.toggleChipColors(
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     toggleControl = {
@@ -277,7 +277,7 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.splitToggleChipColors(
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     toggleControl = {
@@ -359,8 +359,8 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.splitToggleChipColors(
-                        checkedToggleControlTintColor = AlternatePrimaryColor1,
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        checkedToggleControlColor = AlternatePrimaryColor1,
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     enabled = enabled,
@@ -379,7 +379,7 @@
                     // unselected toggle control color to
                     // ToggleChipDefaults.switchUncheckedIconColor() rather than the default.
                     colors = ToggleChipDefaults.toggleChipColors(
-                        uncheckedToggleControlTintColor = ToggleChipDefaults
+                        uncheckedToggleControlColor = ToggleChipDefaults
                             .SwitchUncheckedIconColor
                     ),
                     toggleControl = {
diff --git a/wear/watchface/watchface-client/api/1.1.0-beta01.txt b/wear/watchface/watchface-client/api/1.1.0-beta01.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/1.1.0-beta01.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/current.txt b/wear/watchface/watchface-client/api/current.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/current.txt
+++ b/wear/watchface/watchface-client/api/current.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt b/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
index 95ff68c..92202fd 100644
--- a/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/public_plus_experimental_1.1.0-beta01.txt
@@ -102,7 +102,7 @@
     method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.time.Instant getPreviewReferenceInstant();
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default byte[] getUserStyleSchemaDigestHash() throws android.os.RemoteException;
     method @AnyThread public boolean isConnectionAlive();
@@ -207,19 +207,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -230,9 +217,9 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/public_plus_experimental_current.txt b/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
index 95ff68c..92202fd 100644
--- a/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
+++ b/wear/watchface/watchface-client/api/public_plus_experimental_current.txt
@@ -102,7 +102,7 @@
     method public default static androidx.wear.watchface.client.HeadlessWatchFaceClient createFromBundle(android.os.Bundle bundle);
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotState> getComplicationSlotsState();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public java.time.Instant getPreviewReferenceInstant();
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public default androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method @kotlin.jvm.Throws(exceptionClasses=RemoteException::class) public default byte[] getUserStyleSchemaDigestHash() throws android.os.RemoteException;
     method @AnyThread public boolean isConnectionAlive();
@@ -207,19 +207,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -230,9 +217,9 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @androidx.wear.watchface.WatchFaceFlavorsExperimental @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method @androidx.wear.watchface.WatchFaceFlavorsExperimental public androidx.wear.watchface.UserStyleFlavors getUserStyleFlavors();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt b/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
+++ b/wear/watchface/watchface-client/api/restricted_1.1.0-beta01.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/api/restricted_current.txt b/wear/watchface/watchface-client/api/restricted_current.txt
index 6e77b4d..6937121 100644
--- a/wear/watchface/watchface-client/api/restricted_current.txt
+++ b/wear/watchface/watchface-client/api/restricted_current.txt
@@ -203,19 +203,6 @@
     ctor public WatchFaceControlClient.ServiceStartFailureException(optional String message);
   }
 
-  public final class WatchFaceException extends java.lang.Exception {
-    ctor public WatchFaceException(Exception e, int reason);
-    method public int getReason();
-    property public final int reason;
-    field public static final androidx.wear.watchface.client.WatchFaceException.Companion Companion;
-    field public static final int TRANSACTION_TOO_LARGE = 2; // 0x2
-    field public static final int UNKNOWN = 3; // 0x3
-    field public static final int WATCHFACE_DIED = 1; // 0x1
-  }
-
-  public static final class WatchFaceException.Companion {
-  }
-
   public final class WatchFaceExceptionKt {
   }
 
@@ -226,8 +213,8 @@
   }
 
   public interface WatchFaceMetadataClient extends java.lang.AutoCloseable {
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap() throws androidx.wear.watchface.client.WatchFaceException;
-    method @kotlin.jvm.Throws(exceptionClasses=WatchFaceException::class) public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema() throws androidx.wear.watchface.client.WatchFaceException;
+    method public java.util.Map<java.lang.Integer,androidx.wear.watchface.client.ComplicationSlotMetadata> getComplicationSlotMetadataMap();
+    method public androidx.wear.watchface.style.UserStyleSchema getUserStyleSchema();
     method public boolean isUserStyleSchemaStatic();
     property public abstract boolean isUserStyleSchemaStatic;
     field public static final androidx.wear.watchface.client.WatchFaceMetadataClient.Companion Companion;
diff --git a/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml b/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
index a2ae439..4e73052 100644
--- a/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
+++ b/wear/watchface/watchface-client/src/androidTest/AndroidManifest.xml
@@ -18,6 +18,13 @@
     <application android:requestLegacyExternalStorage="true">
         <service android:name="androidx.wear.watchface.client.test.WatchFaceControlTestService"/>
         <service android:name="androidx.wear.watchface.client.test.TestNopCanvasWatchFaceService"/>
+        <service
+            android:name="androidx.wear.watchface.client.test.OutdatedWatchFaceControlTestService">
+            <meta-data android:name="androidx.wear.watchface.xml_version" android:value="99999" />
+            <meta-data
+                android:name="androidx.wear.watchface.XmlSchemaAndComplicationSlotsDefinition"
+                android:resource="@xml/xml_watchface" />
+        </service>
     </application>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
diff --git a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt
new file mode 100644
index 0000000..aa19f94
--- /dev/null
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/OutdatedWatchFaceControlTestService.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.client.test
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+
+/**
+ * Test WatchFaceControlService which has obsolete XML version in manifest.
+ */
+public class OutdatedWatchFaceControlTestService : Service() {
+    override fun onBind(p0: Intent?): IBinder? {
+        // It is not assumed to be called
+        throw NotImplementedError()
+    }
+}
diff --git a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
index 94e1489..ad5fda7 100644
--- a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceMetadataServiceTest.kt
@@ -358,4 +358,22 @@
         Truth.assertThat(right.systemDataSourceFallbackDefaultType).isEqualTo(
             ComplicationType.SHORT_TEXT)
     }
+
+    @Test
+    public fun xmlVersionCompatibility() {
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(context, context.resources)).isTrue()
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(
+                context,
+                context.resources,
+                ComponentName(context, OutdatedWatchFaceControlTestService::class.java)
+            )).isFalse()
+        Truth.assertThat(
+            WatchFaceMetadataClient.isXmlVersionCompatible(
+                context,
+                context.resources,
+                ComponentName("non.existing.package", "non.existing.package.Service")
+            )).isFalse()
+    }
 }
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt
new file mode 100644
index 0000000..fac5538
--- /dev/null
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/Api30Helper.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.client
+
+import android.os.Build
+import android.os.RemoteException
+import androidx.annotation.RequiresApi
+
+internal class Api30Helper {
+    @RequiresApi(Build.VERSION_CODES.R)
+    internal companion object {
+        internal fun toRuntimeExpression(e: RemoteException) = e.rethrowAsRuntimeException()
+    }
+}
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
index 5b88032..f96a66a2 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/HeadlessWatchFaceClient.kt
@@ -79,9 +79,13 @@
     @Throws(RemoteException::class)
     public fun getUserStyleSchemaDigestHash(): ByteArray = ByteArray(0)
 
-    /** The watch face's [UserStyleFlavors] if any. */
+    /**
+     * Returns the watch face's [UserStyleFlavors] if any.
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
+     */
     @WatchFaceFlavorsExperimental
-    @Throws(WatchFaceException::class)
     public fun getUserStyleFlavors(): UserStyleFlavors = UserStyleFlavors()
 
     /**
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
index eb5f023..53d358a 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceException.kt
@@ -16,62 +16,15 @@
 
 package androidx.wear.watchface.client
 
-import android.os.DeadObjectException
+import android.os.Build
 import android.os.RemoteException
-import android.os.TransactionTooLargeException
-import androidx.annotation.IntDef
 
-/**
- * Why the remote watch face query failed.
- * @hide
- **/
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
-    WatchFaceException.WATCHFACE_DIED,
-    WatchFaceException.TRANSACTION_TOO_LARGE,
-    WatchFaceException.UNKNOWN
-)
-annotation class WatchFaceExceptionReason
-
-/**
- * The watch face threw an exception while trying to service the request.
- *
- * @property reason The [WatchFaceExceptionReason] for the exception.
- */
-public class WatchFaceException(
-    e: Exception,
-    @WatchFaceExceptionReason val reason: Int
-) : Exception(e) {
-
-    companion object {
-        /**
-         * The watchface process died. Connecting again might work, but this isn't guaranteed.
-         */
-        const val WATCHFACE_DIED = 1
-
-        /**
-         * The watchface tried to send us too much data. Currently the limit on binder
-         * transactions is 1mb. See [TransactionTooLargeException] for more details.
-         */
-        const val TRANSACTION_TOO_LARGE = 2
-
-        /**
-         * The watch face threw an exception, typically during initialization. Depending on the
-         * nature of the problem this might be a transient issue or it might occur every time
-         * for that particular watch face.
-         */
-        const val UNKNOWN = 3
-    }
-}
-
-@Throws(WatchFaceException::class)
 internal fun <R> callRemote(task: () -> R): R =
     try {
         task()
-    } catch (e: DeadObjectException) {
-        throw WatchFaceException(e, WatchFaceException.WATCHFACE_DIED)
-    } catch (e: TransactionTooLargeException) {
-        throw WatchFaceException(e, WatchFaceException.TRANSACTION_TOO_LARGE)
     } catch (e: RemoteException) {
-        throw WatchFaceException(e, WatchFaceException.UNKNOWN)
+        if (Build.VERSION.SDK_INT >= 30)
+            throw Api30Helper.toRuntimeExpression(e)
+        else
+            throw RuntimeException(e)
     }
diff --git a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
index c39005c..4c670a1 100644
--- a/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
+++ b/wear/watchface/watchface-client/src/main/java/androidx/wear/watchface/client/WatchFaceMetadataClient.kt
@@ -21,10 +21,12 @@
 import android.content.Intent
 import android.content.ServiceConnection
 import android.content.pm.PackageManager
+import android.content.res.Resources
 import android.content.res.XmlResourceParser
 import android.graphics.RectF
 import android.os.Bundle
 import android.os.IBinder
+import android.util.Log
 import androidx.annotation.RestrictTo
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
@@ -55,6 +57,9 @@
 public interface WatchFaceMetadataClient : AutoCloseable {
 
     public companion object {
+        /** @hide */
+        private const val TAG = "WatchFaceMetadataClient"
+
         /**
          * Constructs a [WatchFaceMetadataClient] for fetching metadata for the specified watch
          * face.
@@ -90,11 +95,50 @@
         }
 
         /** @hide */
+        private const val ANDROIDX_WATCHFACE_XML_VERSION = "androidx.wear.watchface.xml_version"
+        /** @hide */
+        private const val ANDROIDX_WATCHFACE_CONTROL_SERVICE =
+            "androidx.wear.watchface.control.WatchFaceControlService"
+
+        @Suppress("DEPRECATION") // getServiceInfo
+        internal fun isXmlVersionCompatible(
+            context: Context,
+            resources: Resources,
+            controlServiceComponentName: ComponentName = ComponentName(
+                context, ANDROIDX_WATCHFACE_CONTROL_SERVICE)
+        ): Boolean {
+            val version = try {
+                context.packageManager.getServiceInfo(
+                    controlServiceComponentName,
+                    PackageManager.GET_META_DATA or PackageManager.MATCH_DISABLED_COMPONENTS
+                ).metaData.getInt(ANDROIDX_WATCHFACE_XML_VERSION, 0)
+            } catch (exception: PackageManager.NameNotFoundException) {
+                // WatchFaceControlService may be missing in case WF is built with
+                // pre-androidx watchface library.
+                return false
+            }
+
+            val ourVersion = resources.getInteger(
+                androidx.wear.watchface.R.integer.watch_face_xml_version)
+
+            if (version > ourVersion) {
+                Log.w(TAG, "WatchFaceControlService version ($version) " +
+                    "of $controlServiceComponentName is higher than $ourVersion")
+                return false
+            }
+
+            return true
+        }
+
+        /** @hide */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         @Suppress("DEPRECATION")
         open class ParserProvider {
             // Open to allow testing without having to install the sample app.
             open fun getParser(context: Context, watchFaceName: ComponentName): XmlResourceParser? {
+                if (!isXmlVersionCompatible(context, context.resources))
+                    return null
+
                 return context.packageManager.getServiceInfo(
                     watchFaceName,
                     PackageManager.GET_META_DATA
@@ -165,8 +209,10 @@
 
     /**
      * Returns the watch face's [UserStyleSchema].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     public fun getUserStyleSchema(): UserStyleSchema
 
     /**
@@ -179,14 +225,18 @@
     /**
      * Returns a map of [androidx.wear.watchface.ComplicationSlot] ID to [ComplicationSlotMetadata]
      * for each slot in the watch face's [androidx.wear.watchface.ComplicationSlotsManager].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     public fun getComplicationSlotMetadataMap(): Map<Int, ComplicationSlotMetadata>
 
     /**
      * Returns the watch face's [UserStyleFlavors].
+     *
+     * @throws [RuntimeException] if the watch face threw an exception while trying to service the
+     * request or there was a communication problem with watch face process.
      */
-    @Throws(WatchFaceException::class)
     @WatchFaceFlavorsExperimental
     public fun getUserStyleFlavors(): UserStyleFlavors
 }
diff --git a/wear/watchface/watchface/src/main/AndroidManifest.xml b/wear/watchface/watchface/src/main/AndroidManifest.xml
index 52231e3..546fd68 100644
--- a/wear/watchface/watchface/src/main/AndroidManifest.xml
+++ b/wear/watchface/watchface/src/main/AndroidManifest.xml
@@ -35,6 +35,8 @@
         android:exported="true"
         android:permission="com.google.android.wearable.permission.BIND_WATCH_FACE_CONTROL">
       <meta-data android:name="androidx.wear.watchface.api_version" android:value="5" />
+      <meta-data android:name="androidx.wear.watchface.xml_version"
+          android:value="@integer/watch_face_xml_version" />
       <intent-filter>
         <action android:name="com.google.android.wearable.action.WATCH_FACE_CONTROL"/>
       </intent-filter>
diff --git a/wear/watchface/watchface/src/main/res/values/config.xml b/wear/watchface/watchface/src/main/res/values/config.xml
index 2325b7c2..a0e0eec 100644
--- a/wear/watchface/watchface/src/main/res/values/config.xml
+++ b/wear/watchface/watchface/src/main/res/values/config.xml
@@ -17,4 +17,5 @@
 
 <resources>
     <bool name="watch_face_instance_service_enabled">false</bool>
+    <integer name="watch_face_xml_version">0</integer>
 </resources>