Merge "Updated code style of UiAutomator integration test files. Added bug id for UiObject2 testScrollDown() integration test." into androidx-main
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
index 5ba8226..69da2cb 100644
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
+++ b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
@@ -6,6 +6,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "androidx.buildSrc.tests.lib"
+}
+
 androidx {
     name = "Sample Library"
     publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml
deleted file mode 100644
index 4a84e24..0000000
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<manifest package="androidx.buildSrc.tests.lib"/>
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
index 8e04f77..0a06d18 100644
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
+++ b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
@@ -9,6 +9,10 @@
     implementation("androidx.buildSrc-tests:buildSrc-tests-max-dep-versions-dep:1.0.0")
 }
 
+android {
+    namespace "androidx.testapp"
+}
+
 androidx {
     name = "Sample Dependent library"
     mavenGroup = LibraryGroups.BUILDSRC_TESTS
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml
deleted file mode 100644
index e52ac12..0000000
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<manifest package="androidx.testapp"/>
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
index aceb657..bf549ed 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
@@ -562,7 +562,6 @@
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
-        @Suppress("DEPRECATION")
         val symbolRemapper = DeepCopySymbolRemapper()
         val keyVisitor = DurableKeyVisitor(builtKeys)
         val transformer = object : LiveLiteralTransformer(
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
index 9a46677..e8b2913 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
@@ -564,7 +564,6 @@
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
-        @Suppress("DEPRECATION")
         val symbolRemapper = DeepCopySymbolRemapper()
         val keyVisitor = DurableKeyVisitor(builtKeys)
         val transformer = object : LiveLiteralTransformer(
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
index 4d40f46..16ef215 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
@@ -124,6 +124,7 @@
 import org.jetbrains.kotlin.ir.types.defaultType
 import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
 import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
+import org.jetbrains.kotlin.ir.types.isMarkedNullable
 import org.jetbrains.kotlin.ir.types.isNullable
 import org.jetbrains.kotlin.ir.types.isPrimitiveType
 import org.jetbrains.kotlin.ir.types.makeNullable
@@ -156,7 +157,6 @@
 import org.jetbrains.kotlin.util.OperatorNameConventions
 import org.jetbrains.kotlin.utils.DFS
 
-@Suppress("DEPRECATION")
 abstract class AbstractComposeLowering(
     val context: IrPluginContext,
     val symbolRemapper: DeepCopySymbolRemapper,
@@ -271,7 +271,7 @@
         when (this) {
             is IrSimpleType -> IrSimpleTypeImpl(
                 classifier,
-                hasQuestionMark,
+                isMarkedNullable(),
                 List(arguments.size) { IrStarProjectionImpl },
                 annotations,
                 abbreviation
@@ -451,7 +451,6 @@
         body: IrBlockBodyBuilder.(IrFunction) -> Unit
     ) = irLambdaExpression(this.startOffset, this.endOffset, descriptor, type, body)
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrBuilderWithScope.irLambdaExpression(
         startOffset: Int,
         endOffset: Int,
@@ -599,7 +598,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun irCall(
         symbol: IrFunctionSymbol,
         origin: IrStatementOrigin? = null,
@@ -624,11 +622,9 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrType.binaryOperator(name: Name, paramType: IrType): IrFunctionSymbol =
         context.symbols.getBinaryOperator(name, this, paramType)
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrType.unaryOperator(name: Name): IrFunctionSymbol =
         context.symbols.getUnaryOperator(name, this)
 
@@ -1033,7 +1029,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun irLambda(function: IrFunction, type: IrType): IrExpression {
         return irBlock(
             type,
@@ -1306,7 +1301,6 @@
 
 @OptIn(ObsoleteDescriptorBasedAPI::class)
 fun IrValueParameter.isComposerParam(): Boolean =
-    @Suppress("DEPRECATION")
     (descriptor as? ValueParameterDescriptor)?.isComposerParam() ?: false
 
 fun ValueParameterDescriptor.isComposerParam(): Boolean =
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index 5438837..14cb8e5 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -46,6 +46,7 @@
 import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
 import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
 import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
 import org.jetbrains.kotlin.descriptors.SourceElement
 import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -470,7 +471,6 @@
  * of every function is also marked to correspond to indicate that the group corresponds to a call
  * and the source location of the caller can be determined from the containing group.
  */
-@Suppress("DEPRECATION")
 class ComposableFunctionBodyTransformer(
     context: IrPluginContext,
     symbolRemapper: DeepCopySymbolRemapper,
@@ -671,7 +671,7 @@
     private fun printScopeStack(): String {
         return buildString {
             currentScope.forEach {
-                appendln(it.name)
+                appendLine(it.name)
             }
         }
     }
@@ -1597,11 +1597,13 @@
             initialize(
                 null,
                 null,
+                emptyList<ReceiverParameterDescriptor>(),
                 emptyList(),
                 listOf(passedInComposerParameter, ignoredChangedParameter),
                 updateScopeBlockType.toKotlinType(),
                 Modality.FINAL,
-                DescriptorVisibilities.LOCAL
+                DescriptorVisibilities.LOCAL,
+                null
             )
         }
 
@@ -1855,7 +1857,6 @@
         return hash
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun functionSourceKey(): Int {
         val fn = currentFunctionScope.function
         if (fn is IrSimpleFunction) {
@@ -1986,7 +1987,6 @@
         return irMethodCall(irCurrentComposer(), endRestartGroupFunction)
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCache(
         startOffset: Int,
         endOffset: Int,
@@ -2115,7 +2115,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCall(
         function: IrFunction,
         startOffset: Int = UNDEFINED_OFFSET,
@@ -3723,7 +3722,7 @@
 
             private fun packageHash(): Int =
                 packageName()?.fold(0) { hash, current ->
-                    hash * 31 + current.toInt()
+                    hash * 31 + current.code
                 }?.absoluteValue ?: 0
 
             internal fun sourceFileInformation(): String {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
index 89384c6..cb0bb80 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
@@ -180,7 +180,6 @@
     @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall): IrCall {
         val ownerFn = expression.symbol.owner as? IrSimpleFunction
-        @Suppress("DEPRECATION")
         val containingClass = expression.symbol.descriptor.containingDeclaration as? ClassDescriptor
 
         // Any virtual calls on composable functions we want to make sure we update the call to
@@ -353,7 +352,6 @@
     private fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this)
 }
 
-@Suppress("DEPRECATION")
 class ComposerTypeRemapper(
     private val context: IrPluginContext,
     private val symbolRemapper: SymbolRemapper,
@@ -377,7 +375,6 @@
         return annotations.hasAnnotation(ComposeFqNames.Composable)
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private val IrConstructorCall.annotationClass
         get() = this.symbol.owner.returnType.classifierOrNull
 
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
index 04818ff..16bb2f3 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
@@ -59,7 +59,6 @@
 
     @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall): IrExpression {
-        @Suppress("DEPRECATION")
         val calleeFqName = expression.symbol.descriptor.fqNameSafe
         if (calleeFqName == currentComposerIntrinsic) {
             // since this call was transformed by the ComposerParamTransformer, the first argument
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index d3215535..0d6e9d2 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -390,7 +390,6 @@
         return result
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCurrentComposer(): IrExpression {
         val currentComposerSymbol = getTopLevelPropertyGetter(
             ComposeFqNames.fqNameFor("currentComposer")
@@ -814,7 +813,6 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun rememberExpression(
         functionContext: FunctionContext,
         expression: IrExpression,
@@ -1020,7 +1018,6 @@
         return this
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun IrExpression?.isNullOrStable() = this == null || stabilityOf(this).knownStable()
 }
 
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
index a834316..e3a5ab0 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
@@ -93,7 +93,6 @@
 import org.jetbrains.kotlin.resolve.multiplatform.findCompatibleExpectsForActual
 import org.jetbrains.kotlin.util.OperatorNameConventions
 
-@Suppress("DEPRECATION")
 class ComposerParamTransformer(
     context: IrPluginContext,
     symbolRemapper: DeepCopySymbolRemapper,
@@ -278,7 +277,7 @@
         endOffset: Int = UNDEFINED_OFFSET
     ): IrExpression {
         val classSymbol = classOrNull
-        if (this !is IrSimpleType || hasQuestionMark || !isInlineClassType()) {
+        if (this !is IrSimpleType || isMarkedNullable() || !isInlineClassType()) {
             return if (isMarkedNullable()) {
                 IrConstImpl.constNull(startOffset, endOffset, context.irBuiltIns.nothingNType)
             } else {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 5acafa0..b535bdc 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -112,6 +112,7 @@
 import org.jetbrains.kotlin.utils.Printer
 import java.util.Locale
 import kotlin.math.abs
+import org.jetbrains.kotlin.ir.types.isMarkedNullable
 
 fun IrElement.dumpSrc(): String {
     val sb = StringBuilder()
@@ -131,7 +132,6 @@
         .replace(Regex("}\\n(\\s)*,", RegexOption.MULTILINE), "},")
 }
 
-@Suppress("DEPRECATION")
 class IrSourcePrinterVisitor(
     out: Appendable,
     indentUnit: String = "  ",
@@ -206,11 +206,11 @@
                 declaration.visibility != DescriptorVisibilities.PUBLIC &&
                 declaration.visibility != DescriptorVisibilities.LOCAL
             ) {
-                print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+                print(declaration.visibility.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
             if (declaration.modality != Modality.FINAL) {
-                print(declaration.modality.toString().toLowerCase(Locale.ROOT))
+                print(declaration.modality.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
         }
@@ -266,7 +266,6 @@
 
     private var isInNotCall = false
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall) {
         val function = expression.symbol.owner
         val name = function.name.asString()
@@ -772,7 +771,6 @@
         println("}")
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitReturn(expression: IrReturn) {
         val value = expression.value
         // only print the return statement directly if it is not a lambda
@@ -879,7 +877,7 @@
             declaration.visibility != DescriptorVisibilities.PUBLIC &&
             declaration.visibility != DescriptorVisibilities.LOCAL
         ) {
-            print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+            print(declaration.visibility.toString().lowercase(Locale.ROOT))
             print(" ")
         }
         if (declaration.isStatic) {
@@ -1055,7 +1053,7 @@
             declaration.visibility != DescriptorVisibilities.PUBLIC &&
             declaration.visibility != DescriptorVisibilities.LOCAL
         ) {
-            print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+            print(declaration.visibility.toString().lowercase(Locale.ROOT))
             print(" ")
         }
         if (declaration.isInner) {
@@ -1070,7 +1068,7 @@
             print("object ")
         } else {
             if (declaration.modality != Modality.FINAL) {
-                print(declaration.modality.toString().toLowerCase(Locale.ROOT))
+                print(declaration.modality.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
             if (declaration.isAnnotationClass) {
@@ -1321,7 +1319,7 @@
                         }
                     )
                 }
-                if (hasQuestionMark) {
+                if (isMarkedNullable()) {
                     append('?')
                 }
                 abbreviation?.let {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
index 60220e4..f540715 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
@@ -240,7 +240,6 @@
         putValueArgument(0, irConst(file))
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irLiveLiteralGetter(
         key: String,
         literalValue: IrExpression,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
index 620fcd5..3644fe5 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
@@ -165,7 +165,6 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun IrFunction.decoyImplementationName(): Name {
         return dexSafeName(
             Name.identifier(name.asString() + IMPLEMENTATION_FUNCTION_SUFFIX)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
index 628c012..6c40374 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
@@ -15,20 +15,24 @@
  */
 package androidx.compose.foundation
 
-import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import androidx.annotation.RequiresApi
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.Orientation.Horizontal
+import androidx.compose.foundation.gestures.Orientation.Vertical
 import androidx.compose.foundation.gestures.animateScrollBy
 import androidx.compose.foundation.gestures.scrollBy
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -56,8 +60,8 @@
 import androidx.compose.ui.semantics.SemanticsActions
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.semantics.getOrNull
-import androidx.compose.ui.test.TouchInjectionScope
 import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.TouchInjectionScope
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.captureToImage
@@ -65,9 +69,9 @@
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.performScrollTo
 import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeDown
 import androidx.compose.ui.test.swipeLeft
 import androidx.compose.ui.test.swipeRight
@@ -76,14 +80,17 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.LayoutDirection.Ltr
+import androidx.compose.ui.unit.LayoutDirection.Rtl
 import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import androidx.testutils.AnimationDurationScaleRule
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import org.junit.After
@@ -93,12 +100,27 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
+import org.junit.runners.Parameterized
 
 @MediumTest
-@RunWith(AndroidJUnit4::class)
-class ScrollTest {
+@RunWith(Parameterized::class)
+class ScrollTest(private val config: Config) {
+
+    data class Config(
+        val orientation: Orientation,
+        val layoutDirection: LayoutDirection,
+    )
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun data(): List<Config> = listOf(
+            // Don't need to check both directions for vertical scrolling.
+            Config(Vertical, Ltr),
+            Config(Horizontal, Ltr),
+            Config(Horizontal, Rtl),
+        )
+    }
 
     @get:Rule
     val rule = createComposeRule()
@@ -143,19 +165,19 @@
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_SmallContent() {
-        val height = 40
+    fun smallContent() {
+        val size = 40
 
-        composeVerticalScroller(height = height)
+        composeScroller(mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
     }
 
     @Test
-    fun verticalScroller_SmallContent_Unscrollable() {
+    fun smallContent_Unscrollable() {
         val scrollState = ScrollState(initial = 0)
 
-        composeVerticalScroller(scrollState)
+        composeScroller(scrollState)
 
         rule.runOnIdle {
             assertTrue(scrollState.maxValue == 0)
@@ -164,24 +186,24 @@
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_NoScroll() {
-        val height = 30
+    fun largeContent_NoScroll() {
+        val size = 30
 
-        composeVerticalScroller(height = height)
+        composeScroller(mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_ScrollToEnd() {
+    fun largeContent_ScrollToEnd() {
         val scrollState = ScrollState(initial = 0)
-        val height = 30
+        val size = 30
         val scrollDistance = 10
 
-        composeVerticalScroller(scrollState, height = height)
+        composeScroller(scrollState, mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
 
         rule.waitForIdle()
         assertEquals(scrollDistance, scrollState.maxValue)
@@ -189,187 +211,41 @@
             scrollState.scrollTo(scrollDistance)
         }
 
-        validateVerticalScroller(offset = scrollDistance, height = height)
+        validateScroller(offset = scrollDistance, mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_Reversed() {
+    fun reversed() {
         val scrollState = ScrollState(initial = 0)
-        val height = 30
-        val expectedOffset = defaultCellSize * colors.size - height
+        val size = 30
+        val expectedOffset = defaultCellSize * colors.size - size
 
-        composeVerticalScroller(scrollState, height = height, isReversed = true)
+        composeScroller(scrollState, mainAxisSize = size, isReversed = true)
 
-        validateVerticalScroller(offset = expectedOffset, height = height)
+        validateScroller(offset = expectedOffset, mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_Reversed_ScrollToEnd() {
+    fun largeContent_Reversed_ScrollToEnd() {
         val scrollState = ScrollState(initial = 0)
-        val height = 20
+        val size = 20
         val scrollDistance = 10
-        val expectedOffset = defaultCellSize * colors.size - height - scrollDistance
+        val expectedOffset = defaultCellSize * colors.size - size - scrollDistance
 
-        composeVerticalScroller(scrollState, height = height, isReversed = true)
+        composeScroller(scrollState, mainAxisSize = size, isReversed = true)
 
         scope.launch {
             scrollState.scrollTo(scrollDistance)
         }
 
-        validateVerticalScroller(offset = expectedOffset, height = height)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_SmallContent() {
-        val width = 40
-
-        composeHorizontalScroller(width = width)
-
-        validateHorizontalScroller(width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_SmallContent() {
-        val width = 40
-
-        composeHorizontalScroller(width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_NoScroll() {
-        val width = 30
-
-        composeHorizontalScroller(width = width)
-
-        validateHorizontalScroller(width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_NoScroll() {
-        val width = 30
-
-        composeHorizontalScroller(width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        composeHorizontalScroller(scrollState, width = width)
-
-        validateHorizontalScroller(width = width)
-
-        rule.waitForIdle()
-        assertEquals(scrollDistance, scrollState.maxValue)
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = scrollDistance, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        composeHorizontalScroller(scrollState, width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-
-        rule.waitForIdle()
-        assertEquals(scrollDistance, scrollState.maxValue)
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = scrollDistance, width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_reversed() {
-        val scrollState = ScrollState(initial = 0)
-        val width = 30
-        val expectedOffset = defaultCellSize * colors.size - width
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true)
-
-        validateHorizontalScroller(offset = expectedOffset, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_reversed() {
-        val scrollState = ScrollState(initial = 0)
-        val width = 30
-        val expectedOffset = defaultCellSize * colors.size - width
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true, isRtl = true)
-
-        validateHorizontalScroller(offset = expectedOffset, width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_Reversed_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        val expectedOffset = defaultCellSize * colors.size - width - scrollDistance
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true)
-
-        rule.waitForIdle()
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = expectedOffset, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_Reversed_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        val expectedOffset = defaultCellSize * colors.size - width - scrollDistance
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true, isRtl = true)
-
-        rule.waitForIdle()
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = expectedOffset, width = width, checkInRtl = true)
+        validateScroller(offset = expectedOffset, mainAxis = size)
     }
 
     @Test
-    fun verticalScroller_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = true)
+    fun scrollTo_scrollForward() {
+        createScrollableContent()
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -378,8 +254,8 @@
     }
 
     @Test
-    fun horizontalScroller_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = false)
+    fun reversed_scrollTo_scrollForward() {
+        createScrollableContent(isReversed = true)
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -388,61 +264,8 @@
     }
 
     @Test
-    fun horizontalScroller_rtl_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = false, isRtl = true)
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun verticalScroller_reversed_scrollTo_scrollForward() {
-        createScrollableContent(
-            isVertical = true,
-            scrollState = ScrollState(initial = 0),
-            isReversed = true
-        )
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun horizontalScroller_reversed_scrollTo_scrollForward() {
-        createScrollableContent(
-            isVertical = false,
-            scrollState = ScrollState(initial = 0),
-            isReversed = true
-        )
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun verticalScroller_scrollTo_scrollBack() {
-        createScrollableContent(isVertical = true)
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-
-        rule.onNodeWithText("20")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun horizontalScroller_scrollTo_scrollBack() {
-        createScrollableContent(isVertical = false)
+    fun scrollTo_scrollBack() {
+        createScrollableContent()
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -457,24 +280,12 @@
 
     @Test
     @LargeTest
-    fun verticalScroller_swipeUp_swipeDown() {
-        swipeScrollerAndBack(true, TouchInjectionScope::swipeUp, TouchInjectionScope::swipeDown)
-    }
-
-    @Test
-    @LargeTest
-    fun horizontalScroller_swipeLeft_swipeRight() {
-        swipeScrollerAndBack(false, TouchInjectionScope::swipeLeft, TouchInjectionScope::swipeRight)
-    }
-
-    @Test
-    @LargeTest
-    fun horizontalScroller_rtl_swipeLeft_swipeRight() {
+    fun swipeForward_swipeBackward() {
         swipeScrollerAndBack(
-            false,
-            TouchInjectionScope::swipeRight,
-            TouchInjectionScope::swipeLeft,
-            isRtl = true
+            isVertical = config.orientation == Vertical,
+            isRtl = config.layoutDirection == Rtl,
+            firstSwipe = { configAwareSwipe(forward = true) },
+            secondSwipe = { configAwareSwipe(forward = false) }
         )
     }
 
@@ -496,7 +307,10 @@
             rule.waitForIdle()
         }
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(
+            isVertical = config.orientation == Vertical,
+            scrollState = scrollState
+        )
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -519,24 +333,14 @@
     }
 
     @Test
-    fun verticalScroller_LargeContent_coerceWhenMaxChanges() {
+    fun largeContent_coerceWhenMaxChanges() {
         val scrollState = ScrollState(initial = 0)
         val itemCount = mutableStateOf(100)
-        rule.setContent {
-            ExtractCoroutineScope()
-            Box {
-                Column(
-                    Modifier
-                        .size(100.dp)
-                        .testTag(scrollerTag)
-                        .verticalScroll(scrollState)
-                ) {
-                    for (i in 0..itemCount.value) {
-                        BasicText(i.toString())
-                    }
-                }
-            }
-        }
+
+        createScrollableContent(
+            scrollState = scrollState,
+            itemCount = { itemCount.value }
+        )
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -573,7 +377,7 @@
             rule.waitForIdle()
         }
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -601,13 +405,15 @@
         rule.mainClock.autoAdvance = false
         val scrollState = ScrollState(initial = 0)
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         assertThat(scrollState.value).isEqualTo(0)
         assertThat(scrollState.isScrollInProgress).isEqualTo(false)
 
         rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { swipeUp() }
+            .performTouchInput {
+                configAwareSwipe()
+            }
 
         assertThat(scrollState.isScrollInProgress).isEqualTo(true)
         val scrollAtFlingStart = scrollState.value
@@ -635,9 +441,23 @@
             ExtractCoroutineScope()
             val actualState = rememberScrollState()
             SideEffect { scrollState = actualState }
-            Column(Modifier.verticalScroll(actualState)) {
+            val content = @Composable {
                 repeat(50) {
-                    Box(Modifier.height(100.dp))
+                    Box(Modifier.size(100.dp))
+                }
+            }
+            when (config.orientation) {
+                Vertical -> {
+                    Column(Modifier.verticalScroll(actualState)) {
+                        content()
+                    }
+                }
+                Horizontal -> {
+                    CompositionLocalProvider(LocalLayoutDirection provides config.layoutDirection) {
+                        Row(Modifier.horizontalScroll(actualState)) {
+                            content()
+                        }
+                    }
                 }
             }
         }
@@ -656,54 +476,22 @@
         }
     }
 
-    private fun swipeScrollerAndBack(
-        isVertical: Boolean,
-        firstSwipe: TouchInjectionScope.() -> Unit,
-        secondSwipe: TouchInjectionScope.() -> Unit,
-        isRtl: Boolean = false
-    ) {
-        rule.mainClock.autoAdvance = false
-        val scrollState = ScrollState(initial = 0)
-
-        createScrollableContent(isVertical, scrollState = scrollState, isRtl = isRtl)
-
-        assertThat(scrollState.value).isEqualTo(0)
-
-        rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { firstSwipe() }
-
-        rule.mainClock.advanceTimeBy(5000)
-
-        rule.onNodeWithTag(scrollerTag)
-            .awaitScrollAnimation(scrollState)
-
-        val scrolledValue = scrollState.value
-        assertThat(scrolledValue).isGreaterThan(0)
-
-        rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { secondSwipe() }
-
-        rule.mainClock.advanceTimeBy(5000)
-
-        rule.onNodeWithTag(scrollerTag)
-            .awaitScrollAnimation(scrollState)
-
-        assertThat(scrollState.value).isLessThan(scrolledValue)
-    }
-
     @Test
     fun scroller_semanticsScroll_isAnimated() {
         rule.mainClock.autoAdvance = false
         val scrollState = ScrollState(initial = 0)
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
         assertThat(scrollState.maxValue).isGreaterThan(100) // If this fails, just add more items
 
         rule.onNodeWithTag(scrollerTag).performSemanticsAction(SemanticsActions.ScrollBy) {
-            it(0f, 100f)
+            when (config.orientation) {
+                Vertical -> it(0f, 100f)
+                Horizontal -> it(100f, 0f)
+            }
         }
 
         // We haven't advanced time yet, make sure it's still zero
@@ -725,13 +513,20 @@
     fun scroller_touchInputEnabled_shouldHaveSemanticsInfo() {
         val scrollState = ScrollState(initial = 0)
         val scrollNode = rule.onNodeWithTag(scrollerTag)
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
         val yScrollState = scrollNode
             .fetchSemanticsNode()
             .config
-            .getOrNull(SemanticsProperties.VerticalScrollAxisRange)
+            .getOrNull(
+                when (config.orientation) {
+                    Vertical -> SemanticsProperties.VerticalScrollAxisRange
+                    Horizontal -> SemanticsProperties.HorizontalScrollAxisRange
+                }
+            )
 
-        scrollNode.performTouchInput { swipeUp() }
+        scrollNode.performTouchInput {
+            configAwareSwipe()
+        }
 
         assertThat(yScrollState?.value?.invoke()).isEqualTo(scrollState.value)
     }
@@ -741,18 +536,24 @@
         val scrollState = ScrollState(initial = 0)
         val scrollNode = rule.onNodeWithTag(scrollerTag)
         createScrollableContent(
-            isVertical = true,
             scrollState = scrollState,
             touchInputEnabled = false
         )
-        val yScrollState = scrollNode
+        val scrollSemantics = scrollNode
             .fetchSemanticsNode()
             .config
-            .getOrNull(SemanticsProperties.VerticalScrollAxisRange)
+            .getOrNull(
+                when (config.orientation) {
+                    Vertical -> SemanticsProperties.VerticalScrollAxisRange
+                    Horizontal -> SemanticsProperties.HorizontalScrollAxisRange
+                }
+            )
 
-        scrollNode.performTouchInput { swipeUp() }
+        scrollNode.performTouchInput {
+            configAwareSwipe()
+        }
 
-        assertThat(yScrollState?.value?.invoke()).isEqualTo(scrollState.value)
+        assertThat(scrollSemantics?.value?.invoke()).isEqualTo(scrollState.value)
     }
 
     @Test
@@ -765,25 +566,229 @@
         rule.setContent {
             Box {
                 Box(Modifier.size(containerSize, containerSize)) {
-                    Column(
-                        Modifier
-                            .testTag(scrollerTag)
-                            .verticalScroll(state = scrollState)
-                    ) {
-                        Box(Modifier.height(contentSize).fillMaxWidth())
+                    when (config.orientation) {
+                        Vertical -> {
+                            Column(
+                                Modifier
+                                    .testTag(scrollerTag)
+                                    .verticalScroll(state = scrollState)
+                            ) {
+                                Box(
+                                    Modifier
+                                        .height(contentSize)
+                                        .fillMaxWidth()
+                                )
+                            }
+                        }
+                        Horizontal -> {
+                            CompositionLocalProvider(
+                                LocalLayoutDirection provides config.layoutDirection
+                            ) {
+                                Row(
+                                    Modifier
+                                        .testTag(scrollerTag)
+                                        .horizontalScroll(state = scrollState)
+                                ) {
+                                    Box(
+                                        Modifier
+                                            .width(contentSize)
+                                            .fillMaxHeight()
+                                    )
+                                }
+                            }
+                        }
                     }
                 }
             }
         }
 
         rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { swipeUp() }
+            .performTouchInput {
+                configAwareSwipe()
+            }
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(10)
         }
     }
 
+    @Test
+    fun testInspectorValue() {
+        val state = ScrollState(initial = 0)
+        rule.setContent {
+            val modifier = when (config.orientation) {
+                Vertical -> Modifier.verticalScroll(state)
+                Horizontal -> Modifier.horizontalScroll(state)
+            } as InspectableValue
+            assertThat(modifier.nameFallback).isEqualTo("scroll")
+            assertThat(modifier.valueOverride).isNull()
+            assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
+                "state",
+                "reverseScrolling",
+                "flingBehavior",
+                "isScrollable",
+                "isVertical"
+            )
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test
+    fun doesNotClipOverdraw() {
+        rule.setContent {
+            val scrollState = rememberScrollState(20)
+            Box(
+                Modifier
+                    .size(60.dp)
+                    .testTag("container")
+                    .background(Color.Gray)
+            ) {
+                val content = @Composable {
+                    repeat(4) {
+                        Box(
+                            Modifier
+                                .size(20.dp)
+                                .drawOutsideOfBounds()
+                        )
+                    }
+                }
+                when (config.orientation) {
+                    Vertical -> {
+                        Column(
+                            Modifier
+                                .padding(20.dp)
+                                .fillMaxSize()
+                                .verticalScroll(scrollState)
+                        ) {
+                            content()
+                        }
+                    }
+                    Horizontal -> {
+                        CompositionLocalProvider(
+                            LocalLayoutDirection provides config.layoutDirection
+                        ) {
+                            Row(
+                                Modifier
+                                    .padding(20.dp)
+                                    .fillMaxSize()
+                                    .horizontalScroll(scrollState)
+                            ) {
+                                content()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        val (horizontalPadding, verticalPadding) = when (config.orientation) {
+            Vertical -> Pair(0.dp, 20.dp)
+            Horizontal -> Pair(20.dp, 0.dp)
+        }
+
+        rule.onNodeWithTag("container")
+            .captureToImage()
+            .assertShape(
+                density = rule.density,
+                shape = RectangleShape,
+                shapeColor = Color.Red,
+                backgroundColor = Color.Gray,
+                horizontalPadding = horizontalPadding,
+                verticalPadding = verticalPadding
+            )
+    }
+
+    @Test
+    fun intrinsicMeasurements() = with(rule.density) {
+        rule.setContent {
+            Layout(
+                content = {
+                    CompositionLocalProvider(LocalLayoutDirection provides config.layoutDirection) {
+                        Layout(
+                            content = {},
+                            modifier = when (config.orientation) {
+                                Vertical -> Modifier.verticalScroll(rememberScrollState())
+                                Horizontal -> Modifier.horizontalScroll(rememberScrollState())
+                            },
+                            object : MeasurePolicy {
+                                override fun MeasureScope.measure(
+                                    measurables: List<Measurable>,
+                                    constraints: Constraints,
+                                ) = layout(0, 0) {}
+
+                                override fun IntrinsicMeasureScope.minIntrinsicWidth(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    height: Int,
+                                ) = 10.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.minIntrinsicHeight(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    width: Int,
+                                ) = 20.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    height: Int,
+                                ) = 30.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    width: Int,
+                                ) = 40.dp.roundToPx()
+                            }
+                        )
+                    }
+                }
+            ) { measurables, _ ->
+                val measurable = measurables.first()
+                assertEquals(10.dp.roundToPx(), measurable.minIntrinsicWidth(Constraints.Infinity))
+                assertEquals(20.dp.roundToPx(), measurable.minIntrinsicHeight(Constraints.Infinity))
+                assertEquals(30.dp.roundToPx(), measurable.maxIntrinsicWidth(Constraints.Infinity))
+                assertEquals(40.dp.roundToPx(), measurable.maxIntrinsicHeight(Constraints.Infinity))
+                layout(0, 0) {}
+            }
+        }
+        rule.waitForIdle()
+    }
+
+    /**
+     * Swipes forward (up/left) or backward given the current orientation and layout direction
+     * of the test config.
+     */
+    private fun TouchInjectionScope.configAwareSwipe(forward: Boolean = true) =
+        when (config.orientation) {
+            Vertical -> if (forward) swipeUp() else swipeDown()
+            Horizontal -> when (config.layoutDirection) {
+                Ltr -> if (forward) swipeLeft() else swipeRight()
+                Rtl -> if (forward) swipeRight() else swipeLeft()
+            }
+        }
+
+    private fun composeScroller(
+        scrollState: ScrollState? = null,
+        isReversed: Boolean = false,
+        mainAxisSize: Int = defaultMainAxisSize,
+        crossAxisSize: Int = defaultCrossAxisSize,
+        cellSize: Int = defaultCellSize
+    ) {
+        when (config.orientation) {
+            Vertical -> composeVerticalScroller(
+                scrollState = scrollState,
+                isReversed = isReversed,
+                width = crossAxisSize,
+                height = mainAxisSize,
+                rowHeight = cellSize
+            )
+            Horizontal -> composeHorizontalScroller(
+                scrollState = scrollState,
+                isReversed = isReversed,
+                width = mainAxisSize,
+                height = crossAxisSize,
+                isRtl = config.layoutDirection == Rtl
+            )
+        }
+    }
+
     private fun composeVerticalScroller(
         scrollState: ScrollState? = null,
         isReversed: Boolean = false,
@@ -831,7 +836,7 @@
         with(rule.density) {
             rule.setContent {
                 ExtractCoroutineScope()
-                val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+                val direction = if (isRtl) Rtl else Ltr
                 CompositionLocalProvider(LocalLayoutDirection provides direction) {
                     Box {
                         Row(
@@ -858,6 +863,29 @@
     }
 
     @RequiresApi(api = 26)
+    private fun validateScroller(
+        offset: Int = 0,
+        mainAxis: Int = 40,
+        crossAxis: Int = 45,
+        cellSize: Int = 5
+    ) {
+        when (config.orientation) {
+            Vertical -> validateVerticalScroller(
+                offset = offset,
+                width = crossAxis,
+                height = mainAxis,
+                rowHeight = cellSize
+            )
+            Horizontal -> validateHorizontalScroller(
+                offset = offset,
+                width = mainAxis,
+                height = crossAxis,
+                checkInRtl = config.layoutDirection == Rtl
+            )
+        }
+    }
+
+    @RequiresApi(api = 26)
     private fun validateVerticalScroller(
         offset: Int = 0,
         width: Int = 45,
@@ -890,26 +918,28 @@
     }
 
     private fun createScrollableContent(
-        isVertical: Boolean,
-        itemCount: Int = 100,
+        isVertical: Boolean = config.orientation == Vertical,
+        itemCount: () -> Int = { 100 },
         width: Dp = 100.dp,
         height: Dp = 100.dp,
         isReversed: Boolean = false,
         scrollState: ScrollState? = null,
-        isRtl: Boolean = false,
+        isRtl: Boolean = config.layoutDirection == Rtl,
         touchInputEnabled: Boolean = true
     ) {
         val resolvedState = scrollState ?: ScrollState(initial = 0)
         rule.setContent {
             ExtractCoroutineScope()
             val content = @Composable {
-                repeat(itemCount) {
+                repeat(itemCount()) {
                     BasicText(text = "$it")
                 }
             }
             Box {
                 Box(
-                    Modifier.size(width, height).background(Color.White)
+                    Modifier
+                        .size(width, height)
+                        .background(Color.White)
                 ) {
                     if (isVertical) {
                         Column(
@@ -924,10 +954,11 @@
                             content()
                         }
                     } else {
-                        val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+                        val direction = if (isRtl) Rtl else Ltr
                         CompositionLocalProvider(LocalLayoutDirection provides direction) {
                             Row(
-                                Modifier.testTag(scrollerTag)
+                                Modifier
+                                    .testTag(scrollerTag)
                                     .horizontalScroll(
                                         resolvedState,
                                         enabled = touchInputEnabled,
@@ -963,130 +994,39 @@
         return this
     }
 
-    @Test
-    fun testInspectorValue() {
-        val state = ScrollState(initial = 0)
-        rule.setContent {
-            val modifier = Modifier.verticalScroll(state) as InspectableValue
-            assertThat(modifier.nameFallback).isEqualTo("scroll")
-            assertThat(modifier.valueOverride).isNull()
-            assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
-                "state",
-                "reverseScrolling",
-                "flingBehavior",
-                "isScrollable",
-                "isVertical"
-            )
-        }
-    }
+    private fun swipeScrollerAndBack(
+        isVertical: Boolean = config.orientation == Vertical,
+        firstSwipe: TouchInjectionScope.() -> Unit,
+        secondSwipe: TouchInjectionScope.() -> Unit,
+        isRtl: Boolean = config.layoutDirection == Rtl
+    ) {
+        rule.mainClock.autoAdvance = false
+        val scrollState = ScrollState(initial = 0)
 
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun horizontalScroller_doesNotClipVerticalOverdraw() {
-        rule.setContent {
-            Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
-                Row(
-                    Modifier
-                        .padding(20.dp)
-                        .fillMaxSize()
-                        .horizontalScroll(rememberScrollState(20))
-                ) {
-                    repeat(4) {
-                        Box(Modifier.size(20.dp).drawOutsideOfBounds())
-                    }
-                }
-            }
-        }
+        createScrollableContent(isVertical, scrollState = scrollState, isRtl = isRtl)
 
-        rule.onNodeWithTag("container")
-            .captureToImage()
-            .assertShape(
-                density = rule.density,
-                shape = RectangleShape,
-                shapeColor = Color.Red,
-                backgroundColor = Color.Gray,
-                horizontalPadding = 20.dp,
-                verticalPadding = 0.dp
-            )
-    }
+        assertThat(scrollState.value).isEqualTo(0)
 
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun verticalScroller_doesNotClipHorizontalOverdraw() {
-        rule.setContent {
-            Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
-                Column(
-                    Modifier
-                        .padding(20.dp)
-                        .fillMaxSize()
-                        .verticalScroll(rememberScrollState(20))
-                ) {
-                    repeat(4) {
-                        Box(Modifier.size(20.dp).drawOutsideOfBounds())
-                    }
-                }
-            }
-        }
+        rule.onNodeWithTag(scrollerTag)
+            .performTouchInput { firstSwipe() }
 
-        rule.onNodeWithTag("container")
-            .captureToImage()
-            .assertShape(
-                density = rule.density,
-                shape = RectangleShape,
-                shapeColor = Color.Red,
-                backgroundColor = Color.Gray,
-                horizontalPadding = 0.dp,
-                verticalPadding = 20.dp
-            )
-    }
+        rule.mainClock.advanceTimeBy(5000)
 
-    @Test
-    fun intrinsicMeasurements() = with(rule.density) {
-        rule.setContent {
-            Layout(
-                content = {
-                    Layout(
-                        {},
-                        Modifier.verticalScroll(rememberScrollState())
-                            .horizontalScroll(rememberScrollState()),
-                        object : MeasurePolicy {
-                            override fun MeasureScope.measure(
-                                measurables: List<Measurable>,
-                                constraints: Constraints,
-                            ) = layout(0, 0) {}
+        rule.onNodeWithTag(scrollerTag)
+            .awaitScrollAnimation(scrollState)
 
-                            override fun IntrinsicMeasureScope.minIntrinsicWidth(
-                                measurables: List<IntrinsicMeasurable>,
-                                height: Int,
-                            ) = 10.dp.roundToPx()
+        val scrolledValue = scrollState.value
+        assertThat(scrolledValue).isGreaterThan(0)
 
-                            override fun IntrinsicMeasureScope.minIntrinsicHeight(
-                                measurables: List<IntrinsicMeasurable>,
-                                width: Int,
-                            ) = 20.dp.roundToPx()
+        rule.onNodeWithTag(scrollerTag)
+            .performTouchInput { secondSwipe() }
 
-                            override fun IntrinsicMeasureScope.maxIntrinsicWidth(
-                                measurables: List<IntrinsicMeasurable>,
-                                height: Int,
-                            ) = 30.dp.roundToPx()
+        rule.mainClock.advanceTimeBy(5000)
 
-                            override fun IntrinsicMeasureScope.maxIntrinsicHeight(
-                                measurables: List<IntrinsicMeasurable>,
-                                width: Int,
-                            ) = 40.dp.roundToPx()
-                        }
-                    )
-                }
-            ) { measurables, _ ->
-                val measurable = measurables.first()
-                assertEquals(10.dp.roundToPx(), measurable.minIntrinsicWidth(Constraints.Infinity))
-                assertEquals(20.dp.roundToPx(), measurable.minIntrinsicHeight(Constraints.Infinity))
-                assertEquals(30.dp.roundToPx(), measurable.maxIntrinsicWidth(Constraints.Infinity))
-                assertEquals(40.dp.roundToPx(), measurable.maxIntrinsicHeight(Constraints.Infinity))
-                layout(0, 0) {}
-            }
-        }
-        rule.waitForIdle()
+        rule.onNodeWithTag(scrollerTag)
+            .awaitScrollAnimation(scrollState)
+
+        assertThat(scrollState.value).isLessThan(scrolledValue)
     }
 
     private fun Modifier.drawOutsideOfBounds() = drawBehind {
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 581e3db..cf95a0f 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -345,6 +345,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.runtime.Stable public interface ListItemColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> headlineColor(boolean enabled);
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index 77cfe24..1d21786 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -486,6 +486,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.material3.ExperimentalMaterial3Api public final class InputChipDefaults {
     method public float getAvatarSize();
     method public float getHeight();
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 581e3db..cf95a0f 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -345,6 +345,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.runtime.Stable public interface ListItemColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> headlineColor(boolean enabled);
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt
new file mode 100644
index 0000000..d29b497
--- /dev/null
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.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.compose.material3
+
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.PlatformTextStyle
+import androidx.compose.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+@OptIn(ExperimentalTextApi::class)
+@Suppress("DEPRECATION")
+internal actual fun copyAndSetFontPadding(
+    style: TextStyle,
+    includeFontPadding: Boolean
+): TextStyle =
+    style.copy(platformStyle = PlatformTextStyle(includeFontPadding = includeFontPadding))
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
index 3696f19..a19294f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
@@ -169,8 +169,10 @@
             CompositionLocalProvider(
                 LocalContentColor provides contentColor
             ) {
-                val style =
-                    MaterialTheme.typography.fromToken(BadgeTokens.LargeLabelTextFont)
+                val style = copyAndSetFontPadding(
+                    style = MaterialTheme.typography.fromToken(BadgeTokens.LargeLabelTextFont),
+                    includeFontPadding = false
+                )
                 ProvideTextStyle(
                     value = style,
                     content = { content() }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt
new file mode 100644
index 0000000..e6ace4e
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.compose.material3
+
+import androidx.compose.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+internal expect fun copyAndSetFontPadding(style: TextStyle, includeFontPadding: Boolean): TextStyle
diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt
new file mode 100644
index 0000000..31ecb1e
--- /dev/null
+++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.compose.material3
+
+import androidx.compose.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+/* NOOP includeFontPadding doesn't exist on desktop */
+internal actual fun copyAndSetFontPadding(
+    style: TextStyle,
+    includeFontPadding: Boolean
+): TextStyle = style
\ No newline at end of file
diff --git a/datastore/settings.gradle b/datastore/settings.gradle
index 4fcda2f..1b88d33 100644
--- a/datastore/settings.gradle
+++ b/datastore/settings.gradle
@@ -31,6 +31,7 @@
         if (name == ":datastore:datastore-compose-samples") return false
         if (name.startsWith(":datastore")) return true
         if (name == ":annotation:annotation-sampled") return true
+        if (name == ":internal-testutils-datastore") return true
         if (name == ":internal-testutils-kmp") return true
         if (name == ":internal-testutils-truth") return true
         return false
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index dd30501..070a903 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -375,6 +375,11 @@
 \^
 # Gradle will log if you are not authenticated to upload scans
 A build scan was not published as you have not authenticated with server 'ge\.androidx\.dev'\.
+# > Task :core:core:processDebugAndroidTestManifest
+package=".*" found in source AndroidManifest\.xml: .*/AndroidManifest\.xml\.
+Setting the namespace via a source AndroidManifest\.xml's package attribute is deprecated\.
+Please instead set the namespace \(or testNamespace\) in the module's build\.gradle file, as described here: https://developer\.android\.com/studio/build/configure\-app\-module\#set\-namespace
+This migration can be done automatically using the AGP Upgrade Assistant, please refer to https://developer\.android\.com/studio/build/agp\-upgrade\-assistant for more information\.
 # Room unresolved type error messages
 Found an unresolved type in androidx\.room\.RoomDatabase\.Builder\$createFromAsset\(kotlin\.String\) \(RoomDatabase\.kt:[0-9]+\)
 Found an unresolved type in androidx\.room\.RoomDatabase\.Builder\$createFromAsset\(kotlin\.String\,\ androidx\.room\.RoomDatabase\.PrepackagedDatabaseCallback\) \(RoomDatabase\.kt:[0-9]+\)
diff --git a/glance/glance-appwidget/build.gradle b/glance/glance-appwidget/build.gradle
index 92af5d1..6b1a161 100644
--- a/glance/glance-appwidget/build.gradle
+++ b/glance/glance-appwidget/build.gradle
@@ -52,6 +52,7 @@
     implementation("androidx.datastore:datastore-core:1.0.0")
     implementation("androidx.datastore:datastore-preferences-core:1.0.0")
     implementation("androidx.datastore:datastore-preferences:1.0.0")
+    implementation("com.google.android.material:material:1.6.0")
     implementation(project(':core:core-remoteviews'))
     implementation(libs.kotlinStdlib)
 
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
index 99844f7..6060207 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
@@ -17,7 +17,6 @@
 package androidx.glance.appwidget.template
 
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
@@ -27,7 +26,6 @@
 import androidx.glance.Image
 import androidx.glance.LocalSize
 import androidx.glance.action.clickable
-import androidx.glance.background
 import androidx.glance.layout.Alignment
 import androidx.glance.layout.Column
 import androidx.glance.layout.Row
@@ -35,6 +33,7 @@
 import androidx.glance.layout.fillMaxWidth
 import androidx.glance.layout.height
 import androidx.glance.layout.width
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.TemplateButton
 import androidx.glance.template.TemplateImageButton
 import androidx.glance.template.TemplateImageWithDescription
@@ -60,7 +59,7 @@
     if (headerIcon == null && header == null && actionButton == null) return
 
     Row(
-        modifier = GlanceModifier.fillMaxWidth().background(Color.Transparent),
+        modifier = GlanceModifier.fillMaxWidth(),
         verticalAlignment = Alignment.CenterVertically
     ) {
         headerIcon?.let {
@@ -79,7 +78,9 @@
             Text(
                 modifier = GlanceModifier.defaultWeight(),
                 text = header.text,
-                style = TextStyle(fontSize = size),
+                style = TextStyle(
+                    fontSize = size,
+                    color = LocalTemplateColors.current.onSurface),
                 maxLines = 1
             )
         }
@@ -102,14 +103,13 @@
 internal fun AppWidgetTextSection(textList: List<TemplateText>) {
     if (textList.isEmpty()) return
 
-    Column(modifier = GlanceModifier.background(Color.Transparent)) {
+    Column() {
         textList.forEachIndexed { index, item ->
             val size = textSize(item.type, DisplaySize.fromDpSize(LocalSize.current))
             Text(
                 item.text,
-                style = TextStyle(fontSize = size),
-                maxLines = maxLines(item.type),
-                modifier = GlanceModifier.background(Color.Transparent)
+                style = TextStyle(fontSize = size, color = LocalTemplateColors.current.onSurface),
+                maxLines = maxLines(item.type)
             )
             if (index < textList.size - 1) {
                 Spacer(modifier = GlanceModifier.height(8.dp))
@@ -129,6 +129,7 @@
     button: TemplateButton,
     glanceModifier: GlanceModifier = GlanceModifier
 ) {
+    val colors = LocalTemplateColors.current
     when (button) {
         is TemplateImageButton -> {
             // TODO: Specify sizing for image button
@@ -140,7 +141,12 @@
             )
         }
         is TemplateTextButton -> {
-            Button(text = button.text, onClick = button.action, modifier = glanceModifier)
+            Button(
+                text = button.text,
+                onClick = button.action,
+                style = TextStyle(color = colors.onPrimary),
+                modifier = glanceModifier
+            )
         }
     }
 }
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
index 26bd34c..fa89286 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
@@ -23,8 +23,10 @@
 import androidx.glance.LocalSize
 import androidx.glance.appwidget.GlanceAppWidget
 import androidx.glance.appwidget.SizeMode
+import androidx.glance.color.dynamicThemeColorProviders
 import androidx.glance.state.GlanceStateDefinition
 import androidx.glance.state.PreferencesGlanceStateDefinition
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.LocalTemplateMode
 import androidx.glance.template.TemplateMode
 
@@ -43,7 +45,13 @@
     final override fun Content() {
         // TODO: Add other local values
         val mode = mode()
-        CompositionLocalProvider(LocalTemplateMode provides mode) { TemplateContent() }
+        val colors = dynamicThemeColorProviders()
+        CompositionLocalProvider(
+            LocalTemplateMode provides mode,
+            LocalTemplateColors provides colors
+        ) {
+            TemplateContent()
+        }
     }
 
     @Composable
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
index ed17cce..de9c45f 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
@@ -17,7 +17,6 @@
 package androidx.glance.appwidget.template
 
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
 import androidx.glance.GlanceModifier
 import androidx.glance.Image
@@ -33,6 +32,7 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.padding
 import androidx.glance.layout.width
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.LocalTemplateMode
 import androidx.glance.template.SingleEntityTemplateData
 import androidx.glance.template.TemplateMode
@@ -56,7 +56,8 @@
 
 @Composable
 private fun WidgetLayoutCollapsed(data: SingleEntityTemplateData) {
-    var modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)
+    var modifier = GlanceModifier
+        .fillMaxSize().padding(16.dp).background(LocalTemplateColors.current.surface)
 
     data.image?.let { image ->
         modifier = modifier.background(image.image, ContentScale.Crop)
@@ -70,7 +71,11 @@
 
 @Composable
 private fun WidgetLayoutVertical(data: SingleEntityTemplateData) {
-    Column(modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)) {
+
+    Column(modifier = GlanceModifier
+        .fillMaxSize()
+        .padding(16.dp)
+        .background(LocalTemplateColors.current.surface)) {
         data.headerIcon?.let { AppWidgetTemplateHeader(it, data.header) }
         Spacer(modifier = GlanceModifier.height(16.dp))
         data.image?.let { image ->
@@ -92,10 +97,14 @@
 
 @Composable
 private fun WidgetLayoutHorizontal(data: SingleEntityTemplateData) {
-    Row(modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)) {
+    Row(modifier = GlanceModifier
+        .fillMaxSize()
+        .padding(16.dp)
+        .background(LocalTemplateColors.current.surface)) {
+
         Column(
             modifier =
-            GlanceModifier.fillMaxHeight().background(Color.Transparent).defaultWeight()
+            GlanceModifier.defaultWeight().fillMaxHeight()
         ) {
             data.headerIcon?.let { AppWidgetTemplateHeader(it, data.header) }
             Spacer(modifier = GlanceModifier.height(16.dp))
diff --git a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
index 823f7c9..f086c17 100644
--- a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
+++ b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
@@ -150,8 +150,8 @@
         val tile = tileFuture.await()
 
         val resourcesIds = arrayOf(
-            "android_" + ovalBitmapHashCode,
-            "android_" + R.drawable.ic_launcher_background
+            "android_" + R.drawable.ic_launcher_background,
+            "android_" + ovalBitmapHashCode
         )
 
         val resourcesVersion = Arrays.hashCode(resourcesIds).toString()
diff --git a/glance/glance/api/current.txt b/glance/glance/api/current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/current.txt
+++ b/glance/glance/api/current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/api/public_plus_experimental_current.txt b/glance/glance/api/public_plus_experimental_current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/public_plus_experimental_current.txt
+++ b/glance/glance/api/public_plus_experimental_current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/api/restricted_current.txt b/glance/glance/api/restricted_current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/restricted_current.txt
+++ b/glance/glance/api/restricted_current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/build.gradle b/glance/glance/build.gradle
index 804fbf6..6b5a6fd 100644
--- a/glance/glance/build.gradle
+++ b/glance/glance/build.gradle
@@ -38,6 +38,7 @@
     api("androidx.datastore:datastore-preferences:1.0.0")
 
     implementation("androidx.annotation:annotation:1.1.0")
+    implementation("com.google.android.material:material:1.6.0")
     implementation(libs.kotlinStdlib)
     implementation(project(":compose:runtime:runtime"))
 
@@ -60,6 +61,7 @@
 android {
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
+    resourcePrefix "glance_"
     namespace "androidx.glance"
 }
 
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt
new file mode 100644
index 0000000..46ba370
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt
@@ -0,0 +1,187 @@
+/*
+ * 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.glance.color
+
+import androidx.annotation.RestrictTo
+import androidx.glance.R
+import androidx.glance.unit.ColorProvider
+
+/**
+ * Holds a set of Glance specific [ColorProvider] that can be used to represent a Material 3 color
+ * scheme.
+ */
+class ColorProviders(
+    val primary: ColorProvider,
+    val onPrimary: ColorProvider,
+    val primaryContainer: ColorProvider,
+    val onPrimaryContainer: ColorProvider,
+    val secondary: ColorProvider,
+    val onSecondary: ColorProvider,
+    val secondaryContainer: ColorProvider,
+    val onSecondaryContainer: ColorProvider,
+    val tertiary: ColorProvider,
+    val onTertiary: ColorProvider,
+    val tertiaryContainer: ColorProvider,
+    val onTertiaryContainer: ColorProvider,
+    val error: ColorProvider,
+    val errorContainer: ColorProvider,
+    val onError: ColorProvider,
+    val onErrorContainer: ColorProvider,
+    val background: ColorProvider,
+    val onBackground: ColorProvider,
+    val surface: ColorProvider,
+    val onSurface: ColorProvider,
+    val surfaceVariant: ColorProvider,
+    val onSurfaceVariant: ColorProvider,
+    val outline: ColorProvider,
+    val inverseOnSurface: ColorProvider,
+    val inverseSurface: ColorProvider,
+    val inversePrimary: ColorProvider
+    ) {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as ColorProviders
+
+        if (primary != other.primary) return false
+        if (onPrimary != other.onPrimary) return false
+        if (primaryContainer != other.primaryContainer) return false
+        if (onPrimaryContainer != other.onPrimaryContainer) return false
+        if (secondary != other.secondary) return false
+        if (onSecondary != other.onSecondary) return false
+        if (secondaryContainer != other.secondaryContainer) return false
+        if (onSecondaryContainer != other.onSecondaryContainer) return false
+        if (tertiary != other.tertiary) return false
+        if (onTertiary != other.onTertiary) return false
+        if (tertiaryContainer != other.tertiaryContainer) return false
+        if (onTertiaryContainer != other.onTertiaryContainer) return false
+        if (error != other.error) return false
+        if (errorContainer != other.errorContainer) return false
+        if (onError != other.onError) return false
+        if (onErrorContainer != other.onErrorContainer) return false
+        if (background != other.background) return false
+        if (onBackground != other.onBackground) return false
+        if (surface != other.surface) return false
+        if (onSurface != other.onSurface) return false
+        if (surfaceVariant != other.surfaceVariant) return false
+        if (onSurfaceVariant != other.onSurfaceVariant) return false
+        if (outline != other.outline) return false
+        if (inverseOnSurface != other.inverseOnSurface) return false
+        if (inverseSurface != other.inverseSurface) return false
+        if (inversePrimary != other.inversePrimary) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = primary.hashCode()
+        result = 31 * result + onPrimary.hashCode()
+        result = 31 * result + primaryContainer.hashCode()
+        result = 31 * result + onPrimaryContainer.hashCode()
+        result = 31 * result + secondary.hashCode()
+        result = 31 * result + onSecondary.hashCode()
+        result = 31 * result + secondaryContainer.hashCode()
+        result = 31 * result + onSecondaryContainer.hashCode()
+        result = 31 * result + tertiary.hashCode()
+        result = 31 * result + onTertiary.hashCode()
+        result = 31 * result + tertiaryContainer.hashCode()
+        result = 31 * result + onTertiaryContainer.hashCode()
+        result = 31 * result + error.hashCode()
+        result = 31 * result + errorContainer.hashCode()
+        result = 31 * result + onError.hashCode()
+        result = 31 * result + onErrorContainer.hashCode()
+        result = 31 * result + background.hashCode()
+        result = 31 * result + onBackground.hashCode()
+        result = 31 * result + surface.hashCode()
+        result = 31 * result + onSurface.hashCode()
+        result = 31 * result + surfaceVariant.hashCode()
+        result = 31 * result + onSurfaceVariant.hashCode()
+        result = 31 * result + outline.hashCode()
+        result = 31 * result + inverseOnSurface.hashCode()
+        result = 31 * result + inverseSurface.hashCode()
+        result = 31 * result + inversePrimary.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "ColorProviders(primary=$primary," +
+            " onPrimary=$onPrimary, " +
+            "primaryContainer=$primaryContainer, " +
+            "onPrimaryContainer=$onPrimaryContainer, " +
+            "secondary=$secondary, " +
+            "onSecondary=$onSecondary, " +
+            "secondaryContainer=$secondaryContainer, " +
+            "onSecondaryContainer=$onSecondaryContainer, " +
+            "tertiary=$tertiary, " +
+            "onTertiary=$onTertiary, " +
+            "tertiaryContainer=$tertiaryContainer, " +
+            "onTertiaryContainer=$onTertiaryContainer, " +
+            "error=$error, " +
+            "errorContainer=$errorContainer, " +
+            "onError=$onError, " +
+            "onErrorContainer=$onErrorContainer, " +
+            "background=$background, " +
+            "onBackground=$onBackground, " +
+            "surface=$surface, " +
+            "onSurface=$onSurface, " +
+            "surfaceVariant=$surfaceVariant, " +
+            "onSurfaceVariant=$onSurfaceVariant, " +
+            "outline=$outline, " +
+            "inverseOnSurface=$inverseOnSurface, " +
+            "inverseSurface=$inverseSurface, " +
+            "inversePrimary=$inversePrimary)"
+    }
+}
+
+/**
+ * Creates a set of color providers that represents a Material 3 style dynamic color theme. On
+ * devices that support it, this theme is derived from the user specific platform colors, on other
+ * devices this falls back to the Material baseline theme.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun dynamicThemeColorProviders(): ColorProviders {
+    return ColorProviders(
+        primary = ColorProvider(R.color.glance_colorPrimary),
+        onPrimary = ColorProvider(R.color.glance_colorOnPrimary),
+        primaryContainer = ColorProvider(R.color.glance_colorPrimaryContainer),
+        onPrimaryContainer = ColorProvider(R.color.glance_colorOnPrimaryContainer),
+        secondary = ColorProvider(R.color.glance_colorSecondary),
+        onSecondary = ColorProvider(R.color.glance_colorOnSecondary),
+        secondaryContainer = ColorProvider(R.color.glance_colorSecondaryContainer),
+        onSecondaryContainer = ColorProvider(R.color.glance_colorOnSecondaryContainer),
+        tertiary = ColorProvider(R.color.glance_colorTertiary),
+        onTertiary = ColorProvider(R.color.glance_colorOnTertiary),
+        tertiaryContainer = ColorProvider(R.color.glance_colorTertiaryContainer),
+        onTertiaryContainer = ColorProvider(R.color.glance_colorOnTertiaryContainer),
+        error = ColorProvider(R.color.glance_colorError),
+        errorContainer = ColorProvider(R.color.glance_colorErrorContainer),
+        onError = ColorProvider(R.color.glance_colorOnError),
+        onErrorContainer = ColorProvider(R.color.glance_colorOnErrorContainer),
+        background = ColorProvider(R.color.glance_colorBackground),
+        onBackground = ColorProvider(R.color.glance_colorOnBackground),
+        surface = ColorProvider(R.color.glance_colorSurface),
+        onSurface = ColorProvider(R.color.glance_colorOnSurface),
+        surfaceVariant = ColorProvider(R.color.glance_colorSurfaceVariant),
+        onSurfaceVariant = ColorProvider(R.color.glance_colorOnSurfaceVariant),
+        outline = ColorProvider(R.color.glance_colorOutline),
+        inverseOnSurface = ColorProvider(R.color.glance_colorOnSurfaceInverse),
+        inverseSurface = ColorProvider(R.color.glance_colorSurfaceInverse),
+        inversePrimary = ColorProvider(R.color.glance_colorPrimaryInverse),
+    )
+}
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
index c6c6b70..4cf1991 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
@@ -17,5 +17,10 @@
 package androidx.glance.template
 
 import androidx.compose.runtime.compositionLocalOf
+import androidx.glance.color.ColorProviders
 
-val LocalTemplateMode = compositionLocalOf<TemplateMode> { error("Not provided") }
\ No newline at end of file
+val LocalTemplateMode = compositionLocalOf<TemplateMode> { error("No template mode provided") }
+
+val LocalTemplateColors = compositionLocalOf<ColorProviders> {
+    error("No template colors provided")
+}
diff --git a/glance/glance/src/androidMain/res/values-night-v31/colors.xml b/glance/glance/src/androidMain/res/values-night-v31/colors.xml
new file mode 100644
index 0000000..36c885b
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-night-v31/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dynamic_dark_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dynamic_dark_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dynamic_dark_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dynamic_dark_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dynamic_dark_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dynamic_dark_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dynamic_dark_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dynamic_dark_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dynamic_dark_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dynamic_dark_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dynamic_dark_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dynamic_dark_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dynamic_dark_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dynamic_dark_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dynamic_dark_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dynamic_dark_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dynamic_dark_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dynamic_dark_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dynamic_dark_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dynamic_dark_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dynamic_dark_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dynamic_dark_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_dark_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_dark_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_dark_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_dark_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dynamic_dark_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dynamic_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dynamic_dark_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dynamic_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values-night/colors.xml b/glance/glance/src/androidMain/res/values-night/colors.xml
new file mode 100644
index 0000000..5f432cb
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-night/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dark_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dark_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dark_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dark_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dark_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dark_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dark_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dark_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dark_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dark_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dark_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dark_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dark_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dark_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dark_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dark_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dark_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dark_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dark_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dark_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dark_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dark_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_dark_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_dark_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_dark_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_dark_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dark_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dark_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values-v31/colors.xml b/glance/glance/src/androidMain/res/values-v31/colors.xml
new file mode 100644
index 0000000..e6cac06
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-v31/colors.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dynamic_light_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dynamic_light_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dynamic_light_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dynamic_light_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dynamic_light_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dynamic_light_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dynamic_light_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dynamic_light_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dynamic_light_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dynamic_light_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dynamic_light_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dynamic_light_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dynamic_light_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dynamic_light_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dynamic_light_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dynamic_light_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dynamic_light_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dynamic_light_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dynamic_light_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dynamic_light_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dynamic_light_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dynamic_light_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_light_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_light_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_light_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_light_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dynamic_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dynamic_dark_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dynamic_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dynamic_dark_default_color_secondary_text
+    </color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values/colors.xml b/glance/glance/src/androidMain/res/values/colors.xml
new file mode 100644
index 0000000..8fd372f
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_light_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_light_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_light_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_light_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_light_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_light_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_light_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_light_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_light_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_light_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_light_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_light_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_light_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_light_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_light_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_light_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_light_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_light_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_light_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_light_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_light_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_light_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_light_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_light_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_light_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_light_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dark_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dark_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/leanback/leanback/api/current.txt b/leanback/leanback/api/current.txt
index 6c2710a..6cf18f9 100644
--- a/leanback/leanback/api/current.txt
+++ b/leanback/leanback/api/current.txt
@@ -509,10 +509,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
diff --git a/leanback/leanback/api/public_plus_experimental_current.txt b/leanback/leanback/api/public_plus_experimental_current.txt
index 6c2710a..6cf18f9 100644
--- a/leanback/leanback/api/public_plus_experimental_current.txt
+++ b/leanback/leanback/api/public_plus_experimental_current.txt
@@ -509,10 +509,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
diff --git a/leanback/leanback/api/restricted_current.txt b/leanback/leanback/api/restricted_current.txt
index af1803f..5011866 100644
--- a/leanback/leanback/api/restricted_current.txt
+++ b/leanback/leanback/api/restricted_current.txt
@@ -539,10 +539,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
diff --git a/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java b/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
index 927e8a3..e3ab902 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
@@ -337,7 +337,7 @@
      */
     public void onCreateActions(
             @NonNull List<GuidedAction> actions,
-            @NonNull Bundle savedInstanceState
+            @Nullable Bundle savedInstanceState
     ) {
     }
 
@@ -349,7 +349,7 @@
      */
     public void onCreateButtonActions(
             @NonNull List<GuidedAction> actions,
-            @NonNull Bundle savedInstanceState
+            @Nullable Bundle savedInstanceState
     ) {
     }
 
diff --git a/settings.gradle b/settings.gradle
index eb2e597..66e19e6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -944,6 +944,7 @@
 /////////////////////////////
 
 includeProject(":internal-testutils-common", "testutils/testutils-common", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":internal-testutils-datastore", "testutils/testutils-datastore", [BuildType.MAIN])
 includeProject(":internal-testutils-runtime", "testutils/testutils-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.MEDIA, BuildType.WEAR])
 includeProject(":internal-testutils-appcompat", "testutils/testutils-appcompat", [BuildType.MAIN])
 includeProject(":internal-testutils-espresso", "testutils/testutils-espresso", [BuildType.MAIN, BuildType.COMPOSE])
diff --git a/testutils/testutils-datastore/OWNERS b/testutils/testutils-datastore/OWNERS
new file mode 100644
index 0000000..e750dab
--- /dev/null
+++ b/testutils/testutils-datastore/OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
diff --git a/testutils/testutils-datastore/build.gradle b/testutils/testutils-datastore/build.gradle
new file mode 100644
index 0000000..6582467
--- /dev/null
+++ b/testutils/testutils-datastore/build.gradle
@@ -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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+dependencies {
+    implementation(libs.kotlinStdlib)
+}
+
+androidx {
+    type = LibraryType.INTERNAL_TEST_LIBRARY
+}