Merge "Address Nullability issue in NullabilityAnnotationsJava" into androidx-main
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
index a10706d..03d234b 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
@@ -33,7 +33,6 @@
 import androidx.compose.material.DismissValue.DismissedToEnd
 import androidx.compose.material.DismissValue.DismissedToStart
 import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.FractionalThreshold
 import androidx.compose.material.Icon
 import androidx.compose.material.ListItem
 import androidx.compose.material.SwipeToDismiss
@@ -94,9 +93,6 @@
                 state = dismissState,
                 modifier = Modifier.padding(vertical = 4.dp),
                 directions = setOf(StartToEnd, EndToStart),
-                dismissThresholds = { direction ->
-                    FractionalThreshold(if (direction == StartToEnd) 0.25f else 0.5f)
-                },
                 background = {
                     val direction = dismissState.dismissDirection ?: return@SwipeToDismiss
                     val color by animateColorAsState(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
index 31c09ad..0aa1377 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
@@ -37,6 +37,7 @@
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
 import kotlinx.coroutines.CancellationException
 import kotlin.math.roundToInt
 
@@ -173,7 +174,9 @@
     state: DismissState,
     modifier: Modifier = Modifier,
     directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
-    dismissThresholds: (DismissDirection) -> ThresholdConfig = { FractionalThreshold(0.5f) },
+    dismissThresholds: (DismissDirection) -> ThresholdConfig = {
+        FixedThreshold(DISMISS_THRESHOLD)
+    },
     background: @Composable RowScope.() -> Unit,
     dismissContent: @Composable RowScope.() -> Unit
 ) = BoxWithConstraints(modifier) {
@@ -236,3 +239,5 @@
         else -> null
     }
 }
+
+private val DISMISS_THRESHOLD = 56.dp
\ No newline at end of file
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index b405fc2..5654983 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -750,6 +750,18 @@
 
 }
 
+package androidx.compose.runtime.reflect {
+
+  public final class ComposableMethodInvokerKt {
+    method @kotlin.jvm.Throws(exceptionClasses=NoSuchMethodException::class) public static java.lang.reflect.Method getDeclaredComposableMethod(Class<?>, String methodName, Class<?>... args) throws java.lang.NoSuchMethodException;
+    method public static java.lang.reflect.Parameter![] getRealParameters(java.lang.reflect.Method);
+    method public static int getRealParametersCount(java.lang.reflect.Method);
+    method public static Object? invokeComposable(java.lang.reflect.Method, androidx.compose.runtime.Composer composer, Object? instance, java.lang.Object?... args);
+    method public static boolean isComposable(java.lang.reflect.Method);
+  }
+
+}
+
 package androidx.compose.runtime.snapshots {
 
   public final class ListUtilsKt {
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index e121f57..75793d0 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -815,6 +815,18 @@
 
 }
 
+package androidx.compose.runtime.reflect {
+
+  public final class ComposableMethodInvokerKt {
+    method @kotlin.jvm.Throws(exceptionClasses=NoSuchMethodException::class) public static java.lang.reflect.Method getDeclaredComposableMethod(Class<?>, String methodName, Class<?>... args) throws java.lang.NoSuchMethodException;
+    method public static java.lang.reflect.Parameter![] getRealParameters(java.lang.reflect.Method);
+    method public static int getRealParametersCount(java.lang.reflect.Method);
+    method public static Object? invokeComposable(java.lang.reflect.Method, androidx.compose.runtime.Composer composer, Object? instance, java.lang.Object?... args);
+    method public static boolean isComposable(java.lang.reflect.Method);
+  }
+
+}
+
 package androidx.compose.runtime.snapshots {
 
   public final class ListUtilsKt {
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 786f2b7..2643f45 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -778,6 +778,18 @@
 
 }
 
+package androidx.compose.runtime.reflect {
+
+  public final class ComposableMethodInvokerKt {
+    method @kotlin.jvm.Throws(exceptionClasses=NoSuchMethodException::class) public static java.lang.reflect.Method getDeclaredComposableMethod(Class<?>, String methodName, Class<?>... args) throws java.lang.NoSuchMethodException;
+    method public static java.lang.reflect.Parameter![] getRealParameters(java.lang.reflect.Method);
+    method public static int getRealParametersCount(java.lang.reflect.Method);
+    method public static Object? invokeComposable(java.lang.reflect.Method, androidx.compose.runtime.Composer composer, Object? instance, java.lang.Object?... args);
+    method public static boolean isComposable(java.lang.reflect.Method);
+  }
+
+}
+
 package androidx.compose.runtime.snapshots {
 
   public final class ListUtilsKt {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
index e318d61b..1dc664c 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
@@ -919,7 +919,10 @@
     }
 
     internal fun removeDerivedStateObservation(state: DerivedState<*>) {
-        derivedStates.removeScope(state)
+        // remove derived state if it is not observed in other scopes
+        if (state !in observations) {
+            derivedStates.removeScope(state)
+        }
     }
 
     /**
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
index 368da08..3accee3 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
@@ -24,7 +24,7 @@
 import androidx.compose.runtime.RecomposeScopeImpl
 import androidx.compose.runtime.Stable
 
-private const val SLOTS_PER_INT = 10
+internal const val SLOTS_PER_INT = 10
 private const val BITS_PER_SLOT = 3
 
 internal fun bitsForSlot(bits: Int, slot: Int): Int {
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionAndDerivedStateTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionAndDerivedStateTests.kt
index c73242e..125ac7d 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionAndDerivedStateTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionAndDerivedStateTests.kt
@@ -387,6 +387,54 @@
     }
 
     @Test
+    fun observingDerivedStateInMultipleScopes() = compositionTest {
+        var observeInFirstScope by mutableStateOf(true)
+        var count by mutableStateOf(0)
+
+        compose {
+            val items by remember {
+                derivedStateOf {
+                    List(count) { it }
+                }
+            }
+
+            Linear {
+                if (observeInFirstScope) {
+                    Text("List of size ${items.size}")
+                }
+            }
+
+            Linear {
+                Text("List of size ${items.size}")
+            }
+        }
+
+        validate {
+            Linear {
+                Text("List of size 0")
+            }
+
+            Linear {
+                Text("List of size 0")
+            }
+        }
+
+        observeInFirstScope = false
+        advance()
+        count++
+        advance()
+
+        validate {
+            Linear {
+            }
+
+            Linear {
+                Text("List of size 1")
+            }
+        }
+    }
+
+    @Test
     fun changingTheDerivedStateInstanceShouldClearDependencies() = compositionTest {
         var reload by mutableStateOf(0)
 
diff --git a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
index 3193f395..121e1e1 100644
--- a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
+++ b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
@@ -24,8 +24,6 @@
 import androidx.compose.runtime.Stable
 import kotlin.jvm.functions.FunctionN
 
-private const val SLOTS_PER_INT = 10
-
 @Stable
 internal class ComposableLambdaNImpl(
     val key: Int,
diff --git a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvoker.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvoker.kt
new file mode 100644
index 0000000..3b7777a
--- /dev/null
+++ b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvoker.kt
@@ -0,0 +1,211 @@
+/*
+ * 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.runtime.reflect
+
+import androidx.compose.runtime.Composer
+import androidx.compose.runtime.internal.SLOTS_PER_INT
+import java.lang.reflect.Method
+import java.lang.reflect.Modifier
+import java.lang.reflect.Parameter
+import kotlin.math.ceil
+
+private inline fun <reified T> T.dup(count: Int): Array<T> {
+    return (0 until count).map { this }.toTypedArray()
+}
+
+/**
+ * Find the given @Composable method by name.
+ */
+@Throws(NoSuchMethodException::class)
+fun Class<*>.getDeclaredComposableMethod(methodName: String, vararg args: Class<*>): Method {
+    val changedParams = changedParamCount(args.size, 0)
+    val method = try {
+        // without defaults
+        getDeclaredMethod(
+            methodName,
+            *args,
+            Composer::class.java, // composer param
+            *Int::class.java.dup(changedParams) // changed params
+        )
+    } catch (e: ReflectiveOperationException) {
+        val defaultParams = defaultParamCount(args.size)
+        try {
+            getDeclaredMethod(
+                methodName,
+                *args,
+                Composer::class.java, // composer param
+                *Int::class.java.dup(changedParams), // changed param
+                *Int::class.java.dup(defaultParams) // default param
+            )
+        } catch (e2: ReflectiveOperationException) {
+            null
+        }
+    } ?: throw NoSuchMethodException("$name.$methodName")
+
+    return method
+}
+
+/**
+ * Returns the default value for the [Class] type. This will be 0 for numeric types, false for
+ * boolean and null for object references.
+ */
+private fun Class<*>.getDefaultValue(): Any? = when (name) {
+    "int" -> 0.toInt()
+    "short" -> 0.toShort()
+    "byte" -> 0.toByte()
+    "long" -> 0.toLong()
+    "double" -> 0.toDouble()
+    "float" -> 0.toFloat()
+    "boolean" -> false
+    "char" -> 0.toChar()
+    else -> null
+}
+
+/**
+ * Structure intended to be used exclusively by [getComposableInfo].
+ */
+private data class ComposableInfo(
+    val isComposable: Boolean,
+    val realParamsCount: Int,
+    val changedParams: Int,
+    val defaultParams: Int
+)
+
+/**
+ * Checks whether the method is Composable function and returns result along with the real
+ * parameters count and changed parameter count (if composable) and packed in a structure.
+ */
+private fun Method.getComposableInfo(): ComposableInfo {
+    val realParamsCount = parameterTypes.indexOfLast { it == Composer::class.java }
+    if (realParamsCount == -1) {
+        return ComposableInfo(false, parameterTypes.size, 0, 0)
+    }
+    val thisParams = if (Modifier.isStatic(this.modifiers)) 0 else 1
+    val changedParams = changedParamCount(realParamsCount, thisParams)
+    val totalParamsWithoutDefaults = realParamsCount +
+        1 + // composer
+        changedParams
+    val totalParams = parameterTypes.size
+    val isDefault = totalParams != totalParamsWithoutDefaults
+    val defaultParams = if (isDefault)
+        defaultParamCount(realParamsCount)
+    else
+        0
+    return ComposableInfo(
+        totalParamsWithoutDefaults + defaultParams == totalParams,
+        realParamsCount,
+        changedParams,
+        defaultParams
+    )
+}
+
+/**
+ * Calls the Composable method on the given [instance]. If the method accepts default values, this
+ * function will call it with the correct options set.
+ */
+@Suppress("BanUncheckedReflection", "ListIterator")
+fun Method.invokeComposable(
+    composer: Composer,
+    instance: Any?,
+    vararg args: Any?
+): Any? {
+    val (isComposable, realParamsCount, changedParams, defaultParams) = getComposableInfo()
+
+    check(isComposable)
+
+    val totalParams = parameterTypes.size
+    val changedStartIndex = realParamsCount + 1
+    val defaultStartIndex = changedStartIndex + changedParams
+
+    val defaultsMasks = Array(defaultParams) { index ->
+        val start = index * BITS_PER_INT
+        val end = minOf(start + BITS_PER_INT, realParamsCount)
+        val useDefault =
+            (start until end).map { if (it >= args.size || args[it] == null) 1 else 0 }
+        val mask = useDefault.foldIndexed(0) { i, mask, default -> mask or (default shl i) }
+        mask
+    }
+
+    val arguments = Array(totalParams) { idx ->
+        when (idx) {
+            // pass in "empty" value for all real parameters since we will be using defaults.
+            in 0 until realParamsCount -> args.getOrElse(idx) {
+                parameterTypes[idx].getDefaultValue()
+            }
+            // the composer is the first synthetic parameter
+            realParamsCount -> composer
+            // since this is the root we don't need to be anything unique. 0 should suffice.
+            // changed parameters should be 0 to indicate "uncertain"
+            changedStartIndex -> 1
+            in changedStartIndex + 1 until defaultStartIndex -> 0
+            // Default values mask, all parameters set to use defaults
+            in defaultStartIndex until totalParams -> defaultsMasks[idx - defaultStartIndex]
+            else -> error("Unexpected index")
+        }
+    }
+    return invoke(instance, *arguments)
+}
+
+private const val BITS_PER_INT = 31
+
+private fun changedParamCount(realValueParams: Int, thisParams: Int): Int {
+    if (realValueParams == 0) return 1
+    val totalParams = realValueParams + thisParams
+    return ceil(
+        totalParams.toDouble() / SLOTS_PER_INT.toDouble()
+    ).toInt()
+}
+
+private fun defaultParamCount(realValueParams: Int): Int {
+    return ceil(
+        realValueParams.toDouble() / BITS_PER_INT.toDouble()
+    ).toInt()
+}
+
+/**
+ * Returns true if the method is a Composable function and false otherwise.
+ */
+val Method.isComposable: Boolean
+    get() = getComposableInfo().isComposable
+
+/**
+ * Returns real parameters count for the method, it returns the actual parameters count for the
+ * usual methods and for Composable functions it excludes the utility Compose-specific parameters
+ * from counting.
+ */
+val Method.realParametersCount: Int
+    get() {
+        val (isComposable, realParametersCount, _, _) = getComposableInfo()
+        if (isComposable) {
+            return realParametersCount
+        }
+        return parameterTypes.size
+    }
+
+/**
+ * Returns real parameters for the method, it returns the actual parameters for the usual methods
+ * and for Composable functions it excludes the utility Compose-specific parameters.
+ */
+val Method.realParameters: Array<out Parameter>
+    @Suppress("ClassVerificationFailure", "NewApi")
+    get() {
+        val (isComposable, realParametersCount, _, _) = getComposableInfo()
+        if (isComposable) {
+            return parameters.copyOfRange(0, realParametersCount)
+        }
+        return parameters
+    }
diff --git a/compose/runtime/runtime/src/jvmTest/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvokerTest.kt b/compose/runtime/runtime/src/jvmTest/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvokerTest.kt
new file mode 100644
index 0000000..a976fad
--- /dev/null
+++ b/compose/runtime/runtime/src/jvmTest/kotlin/androidx/compose/runtime/reflect/ComposableMethodInvokerTest.kt
@@ -0,0 +1,581 @@
+/*
+ * 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.runtime.reflect
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Composer
+import androidx.compose.runtime.Composition
+import androidx.compose.runtime.MonotonicFrameClock
+import androidx.compose.runtime.Recomposer
+import androidx.compose.runtime.currentComposer
+import androidx.compose.runtime.mock.EmptyApplier
+import androidx.compose.runtime.withRunningRecomposer
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+import kotlinx.coroutines.runBlocking
+
+@Composable
+private fun composableFunction() {
+}
+
+private fun nonComposableFunction() {
+}
+
+@Suppress("UNUSED_PARAMETER")
+private fun nonComposableFunctionWithComposerParam(unused: Composer) {
+}
+
+@Composable
+private fun composableFunctionWithDefaults(
+    s1: String,
+    s2: String,
+    s3: String = "a",
+    s4: String = "a",
+    s5: String = "a"
+): String { return s1 + s2 + s3 + s4 + s5 }
+
+@Composable
+private fun overloadedComposable() {
+}
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun overloadedComposable(s: String) {
+}
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun overloadedComposable(
+    v1: String,
+    v2: String,
+    v3: String,
+    v4: String,
+    v5: String,
+    v6: String,
+    v7: String,
+    v8: String,
+    v9: String,
+    v10: String
+) { }
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun overloadedComposable(
+    v1: String,
+    v2: String,
+    v3: String,
+    v4: String,
+    v5: String,
+    v6: String,
+    v7: String,
+    v8: String,
+    v9: String,
+    v10: String,
+    v11: String
+) { }
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun overloadedComposable(
+    v1: String,
+    v2: String,
+    v3: String,
+    v4: String,
+    v5: String,
+    v6: String,
+    v7: String,
+    v8: String,
+    v9: String,
+    v10: String,
+    v11: String,
+    v12: String
+) { }
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun differentParametersTypes(
+    v1: String,
+    v2: Any,
+    v3: Int,
+    v4: Float,
+    v5: Double,
+    v6: Long
+) { }
+
+private class ComposablesWrapper {
+    @Composable
+    fun composableMethod() {
+    }
+
+    fun nonComposableMethod() {
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    fun nonComposableMethodWithComposerParam(unused: Composer) {
+    }
+
+    @Composable
+    fun composableMethodWithDefaults(
+        s1: String,
+        s2: String,
+        s3: String = "a",
+        s4: String = "a",
+        s5: String = "a"
+    ): String { return s1 + s2 + s3 + s4 + s5 }
+
+    @Composable
+    fun overloadedComposableMethod() {
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    @Composable
+    fun overloadedComposableMethod(s: String) {
+    }
+
+    @Suppress("UNUSED_PARAMETER")
+    @Composable
+    fun overloadedComposableMethod(
+        v1: String,
+        v2: String,
+        v3: String,
+        v4: String,
+        v5: String,
+        v6: String,
+        v7: String,
+        v8: String,
+        v9: String,
+        v10: String
+    ) { }
+
+    @Suppress("UNUSED_PARAMETER")
+    @Composable
+    fun overloadedComposableMethod(
+        v1: String,
+        v2: String,
+        v3: String,
+        v4: String,
+        v5: String,
+        v6: String,
+        v7: String,
+        v8: String,
+        v9: String,
+        v10: String,
+        v11: String
+    ) { }
+
+    @Suppress("UNUSED_PARAMETER")
+    @Composable
+    fun overloadedComposableMethod(
+        v1: String,
+        v2: String,
+        v3: String,
+        v4: String,
+        v5: String,
+        v6: String,
+        v7: String,
+        v8: String,
+        v9: String,
+        v10: String,
+        v11: String,
+        v12: String
+    ) { }
+
+    @Suppress("UNUSED_PARAMETER")
+    @Composable
+    fun differentParametersTypesMethod(
+        v1: String,
+        v2: Any,
+        v3: Int,
+        v4: Float,
+        v5: Double,
+        v6: Long
+    ) { }
+}
+
+class ComposableMethodInvokerTest {
+    private val clazz =
+        Class.forName("androidx.compose.runtime.reflect.ComposableMethodInvokerTestKt")
+    private val wrapperClazz =
+        Class.forName("androidx.compose.runtime.reflect.ComposablesWrapper")
+
+    private val composable = clazz.declaredMethods.find { it.name == "composableFunction" }!!
+    private val nonComposable = clazz.declaredMethods.find { it.name == "nonComposableFunction" }!!
+    private val nonComposableWithComposer =
+        clazz.declaredMethods.find { it.name == "nonComposableFunctionWithComposerParam" }!!
+    private val composableMethod =
+        wrapperClazz.declaredMethods.find { it.name == "composableMethod" }!!
+    private val nonComposableMethod =
+        wrapperClazz.declaredMethods.find { it.name == "nonComposableMethod" }!!
+    private val nonComposableMethodWithComposer =
+        wrapperClazz.declaredMethods.find { it.name == "nonComposableMethodWithComposerParam" }!!
+
+    @Test
+    fun test_isComposable_correctly_checks_functions() {
+        assertTrue(composable.isComposable)
+        assertFalse(nonComposable.isComposable)
+        assertFalse(nonComposableWithComposer.isComposable)
+        assertTrue(composableMethod.isComposable)
+        assertFalse(nonComposableMethod.isComposable)
+        assertFalse(nonComposableMethodWithComposer.isComposable)
+    }
+
+    @Throws(NoSuchMethodException::class)
+    @Test
+    fun test_getDeclaredComposableMethod_differentiates_overloaded_functions() {
+        val method0 = clazz.getDeclaredComposableMethod("overloadedComposable")
+        val method1 = clazz.getDeclaredComposableMethod("overloadedComposable", String::class.java)
+        val method10 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(10) { String::class.java }
+            )
+        val method11 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(11) { String::class.java }
+            )
+        val method12 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(12) { String::class.java }
+            )
+
+        assertNotEquals(method0, method1)
+        assertNotEquals(method0, method10)
+        assertNotEquals(method0, method11)
+        assertNotEquals(method0, method12)
+        assertNotEquals(method1, method10)
+        assertNotEquals(method1, method11)
+        assertNotEquals(method1, method12)
+        assertNotEquals(method10, method11)
+        assertNotEquals(method10, method12)
+        assertNotEquals(method11, method12)
+    }
+
+    @Throws(NoSuchMethodException::class)
+    @Test
+    fun test_getDeclaredComposableMethod_differentiates_overloaded_methods() {
+        val method0 = wrapperClazz.getDeclaredComposableMethod("overloadedComposableMethod")
+        val method1 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                String::class.java
+            )
+        val method10 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(10) { String::class.java }
+            )
+        val method11 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(11) { String::class.java }
+            )
+        val method12 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(12) { String::class.java }
+            )
+
+        assertNotEquals(method0, method1)
+        assertNotEquals(method0, method10)
+        assertNotEquals(method0, method11)
+        assertNotEquals(method0, method12)
+        assertNotEquals(method1, method10)
+        assertNotEquals(method1, method11)
+        assertNotEquals(method1, method12)
+        assertNotEquals(method10, method11)
+        assertNotEquals(method10, method12)
+        assertNotEquals(method11, method12)
+    }
+
+    @Throws(NoSuchMethodException::class)
+    @Test
+    fun test_getDeclaredComposableMethod_works_with_default_params() {
+        clazz.getDeclaredComposableMethod(
+            "composableFunctionWithDefaults",
+            *Array(5) { String::class.java }
+        )
+
+        wrapperClazz.getDeclaredComposableMethod(
+            "composableMethodWithDefaults",
+            *Array(5) { String::class.java }
+        )
+    }
+
+    @Throws(NoSuchMethodException::class)
+    @Test
+    fun test_realParametersCount_returns_correct_number_of_parameters() {
+        val function0 = clazz.getDeclaredComposableMethod("overloadedComposable")
+        val function1 =
+            clazz.getDeclaredComposableMethod("overloadedComposable", String::class.java)
+        val function10 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(10) { String::class.java }
+            )
+        val function11 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(11) { String::class.java }
+            )
+        val function12 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(12) { String::class.java }
+            )
+
+        val method0 = wrapperClazz.getDeclaredComposableMethod("overloadedComposableMethod")
+        val method1 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod", String::class.java
+            )
+        val method10 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(10) { String::class.java }
+            )
+        val method11 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(11) { String::class.java }
+            )
+        val method12 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(12) { String::class.java }
+            )
+
+        assertEquals(0, function0.realParametersCount)
+        assertEquals(1, function1.realParametersCount)
+        assertEquals(10, function10.realParametersCount)
+        assertEquals(11, function11.realParametersCount)
+        assertEquals(12, function12.realParametersCount)
+
+        assertEquals(0, method0.realParametersCount)
+        assertEquals(1, method1.realParametersCount)
+        assertEquals(10, method10.realParametersCount)
+        assertEquals(11, method11.realParametersCount)
+        assertEquals(12, method12.realParametersCount)
+
+        assertEquals(0, nonComposable.realParametersCount)
+        assertEquals(1, nonComposableWithComposer.realParametersCount)
+        assertEquals(0, composableMethod.realParametersCount)
+        assertEquals(0, nonComposableMethod.realParametersCount)
+        assertEquals(1, nonComposableMethodWithComposer.realParametersCount)
+    }
+
+    @Suppress("ClassVerificationFailure", "NewApi")
+    @Throws(NoSuchMethodException::class)
+    @Test
+    fun test_realParameters_returns_correct_parameters() {
+        val function0 = clazz.getDeclaredComposableMethod("overloadedComposable")
+        val function1 =
+            clazz.getDeclaredComposableMethod("overloadedComposable", String::class.java)
+        val function10 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(10) { String::class.java }
+            )
+        val function11 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(11) { String::class.java }
+            )
+        val function12 =
+            clazz.getDeclaredComposableMethod(
+                "overloadedComposable",
+                *Array(12) { String::class.java }
+            )
+
+        val method0 = wrapperClazz.getDeclaredComposableMethod("overloadedComposableMethod")
+        val method1 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                String::class.java
+            )
+        val method10 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(10) { String::class.java }
+            )
+        val method11 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(11) { String::class.java }
+            )
+        val method12 =
+            wrapperClazz.getDeclaredComposableMethod(
+                "overloadedComposableMethod",
+                *Array(12) { String::class.java }
+            )
+
+        val diffParameters =
+            clazz.getDeclaredComposableMethod(
+                "differentParametersTypes",
+                String::class.java,
+                Any::class.java,
+                Int::class.java,
+                Float::class.java,
+                Double::class.java,
+                Long::class.java
+            )
+
+        val diffParametersMethod =
+            wrapperClazz.getDeclaredComposableMethod(
+                "differentParametersTypesMethod",
+                String::class.java,
+                Any::class.java,
+                Int::class.java,
+                Float::class.java,
+                Double::class.java,
+                Long::class.java
+            )
+
+        assertEquals(0, function0.realParameters.size)
+        assertEquals(1, function1.realParameters.size)
+        assertEquals(10, function10.realParameters.size)
+        assertEquals(11, function11.realParameters.size)
+        assertEquals(12, function12.realParameters.size)
+        assertEquals(12, function12.realParameters.size)
+
+        assertEquals(0, method0.realParameters.size)
+        assertEquals(1, method1.realParameters.size)
+        assertEquals(10, method10.realParameters.size)
+        assertEquals(11, method11.realParameters.size)
+        assertEquals(12, method12.realParameters.size)
+
+        assertEquals(0, nonComposable.realParameters.size)
+        assertEquals(1, nonComposableWithComposer.realParameters.size)
+        assertEquals(0, composableMethod.realParameters.size)
+        assertEquals(0, nonComposableMethod.realParameters.size)
+        assertEquals(1, nonComposableMethodWithComposer.realParameters.size)
+
+        assertEquals(6, diffParameters.realParameters.size)
+        assertEquals(
+            listOf(String::class.java, Any::class.java, Int::class.java, Float::class.java,
+                Double::class.java, Long::class.java),
+            diffParameters.realParameters.map { it.type })
+
+        assertEquals(6, diffParametersMethod.realParameters.size)
+        assertEquals(
+            listOf(String::class.java, Any::class.java, Int::class.java, Float::class.java,
+                Double::class.java, Long::class.java),
+            diffParametersMethod.realParameters.map { it.type })
+    }
+
+    private class TestFrameClock : MonotonicFrameClock {
+        override suspend fun <R> withFrameNanos(onFrame: (Long) -> R): R = onFrame(0L)
+    }
+
+    private fun <T> executeWithComposer(block: (composer: Composer) -> T): T =
+        runBlocking(TestFrameClock()) {
+            fun compose(
+                recomposer: Recomposer,
+                block: @Composable () -> Unit
+            ): Composition {
+                return Composition(
+                    EmptyApplier(),
+                    recomposer
+                ).apply {
+                    setContent(block)
+                }
+            }
+
+            var res: T? = null
+            withRunningRecomposer { r ->
+                compose(r) {
+                    res = block(currentComposer)
+                }
+            }
+            res!!
+        }
+
+    @Test
+    fun testInvokeComposableFunctions() {
+
+        val composableWithDefaults =
+            clazz.declaredMethods.find { it.name == "composableFunctionWithDefaults" }!!
+        composableWithDefaults.isAccessible = true
+
+        val resABAAA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, null, "a", "b") as String
+        }
+
+        val resABCAA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, null, "a", "b", "c") as String
+        }
+
+        val resABCDA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, null, "a", "b", "c", "d") as String
+        }
+
+        val resABCDE = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, null, "a", "b", "c", "d", "e") as String
+        }
+
+        val resABADA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, null, "a", "b", null, "d") as String
+        }
+
+        assertEquals("abaaa", resABAAA)
+        assertEquals("abcaa", resABCAA)
+        assertEquals("abcda", resABCDA)
+        assertEquals("abcde", resABCDE)
+        assertEquals("abada", resABADA)
+    }
+
+    @Test
+    fun testInvokeComposableMethods() {
+
+        val composableWithDefaults =
+            wrapperClazz.declaredMethods.find { it.name == "composableMethodWithDefaults" }!!
+        composableWithDefaults.isAccessible = true
+
+        val instance = ComposablesWrapper()
+
+        val resABAAA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, instance, "a", "b") as String
+        }
+
+        val resABCAA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, instance, "a", "b", "c") as String
+        }
+
+        val resABCDA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, instance, "a", "b", "c", "d") as String
+        }
+
+        val resABCDE = executeWithComposer {
+            composableWithDefaults
+                .invokeComposable(it, instance, "a", "b", "c", "d", "e") as String
+        }
+
+        val resABADA = executeWithComposer {
+            composableWithDefaults.invokeComposable(it, instance, "a", "b", null, "d") as String
+        }
+
+        assertEquals("abaaa", resABAAA)
+        assertEquals("abcaa", resABCAA)
+        assertEquals("abcda", resABCDA)
+        assertEquals("abcde", resABCDE)
+        assertEquals("abada", resABADA)
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
index cfbe91f..6428016 100644
--- a/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-tooling/api/public_plus_experimental_current.txt
@@ -1,9 +1,9 @@
 // Signature format: 4.0
 package androidx.compose.ui.tooling {
 
-  @androidx.compose.ui.ExperimentalComposeUiApi public final class ComposableInvoker {
-    method @androidx.compose.ui.ExperimentalComposeUiApi public void invokeComposable(String className, String methodName, androidx.compose.runtime.Composer composer, java.lang.Object?... args);
-    field public static final androidx.compose.ui.tooling.ComposableInvoker INSTANCE;
+  @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public final class ComposableInvoker {
+    method @Deprecated @androidx.compose.ui.ExperimentalComposeUiApi public void invokeComposable(String className, String methodName, androidx.compose.runtime.Composer composer, java.lang.Object?... args);
+    field @Deprecated public static final androidx.compose.ui.tooling.ComposableInvoker INSTANCE;
   }
 
   public final class ComposeViewAdapterKt {
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
index 7c484d32..5d07d1a 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
@@ -49,7 +49,6 @@
 import androidx.compose.ui.platform.LocalFontLoader
 import androidx.compose.ui.platform.ViewRootForTest
 import androidx.compose.ui.text.font.createFontFamilyResolver
-import androidx.compose.ui.tooling.ComposableInvoker.invokeComposable
 import androidx.compose.ui.tooling.animation.PreviewAnimationClock
 import androidx.compose.ui.tooling.data.Group
 import androidx.compose.ui.tooling.data.SourceLocation
@@ -553,6 +552,7 @@
      * @param onCommit callback invoked after every commit of the preview composable.
      * @param onDraw callback invoked after every draw of the adapter. Only for test use.
      */
+    @Suppress("DEPRECATION")
     @OptIn(ExperimentalComposeUiApi::class)
     @VisibleForTesting
     internal fun init(
@@ -587,7 +587,7 @@
                 // class loads correctly.
                 val composable = {
                     try {
-                        invokeComposable(
+                        ComposableInvoker.invokeComposable(
                             className,
                             methodName,
                             composer,
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/PreviewActivity.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/PreviewActivity.kt
index 6e5cad2..ec5b8d9 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/PreviewActivity.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/PreviewActivity.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.tooling.ComposableInvoker.invokeComposable
 
 /**
  * Activity used to run `@Composable` previews from Android Studio.
@@ -59,6 +58,7 @@
         intent?.getStringExtra("composable")?.let { setComposableContent(it) }
     }
 
+    @Suppress("DEPRECATION")
     @OptIn(ExperimentalComposeUiApi::class)
     private fun setComposableContent(composableFqn: String) {
         Log.d(TAG, "PreviewActivity has composable $composableFqn")
@@ -71,7 +71,7 @@
         }
         Log.d(TAG, "Previewing '$methodName' without a parameter provider.")
         setContent {
-            invokeComposable(
+            ComposableInvoker.invokeComposable(
                 className,
                 methodName,
                 currentComposer
@@ -86,6 +86,7 @@
      * Otherwise, the content will display a FAB that changes the argument value on click, cycling
      * through all the values in the provider's sequence.
      */
+    @Suppress("DEPRECATION")
     @OptIn(ExperimentalComposeUiApi::class)
     private fun setParameterizedContent(
         className: String,
@@ -107,7 +108,7 @@
 
                 Scaffold(
                     content = {
-                        invokeComposable(
+                        ComposableInvoker.invokeComposable(
                             className,
                             methodName,
                             currentComposer,
@@ -124,7 +125,7 @@
             }
         } else {
             setContent {
-                invokeComposable(
+                ComposableInvoker.invokeComposable(
                     className,
                     methodName,
                     currentComposer,
diff --git a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/NonInteractivePreviewFacade.kt b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/NonInteractivePreviewFacade.kt
index e569bf9..5cec2cc 100644
--- a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/NonInteractivePreviewFacade.kt
+++ b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/NonInteractivePreviewFacade.kt
@@ -20,7 +20,6 @@
 import androidx.compose.runtime.currentComposer
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.platform.TestComposeWindow
-import androidx.compose.ui.tooling.ComposableInvoker
 import androidx.compose.ui.unit.Density
 
 /**
@@ -43,7 +42,7 @@
  *    preview classpath (a requested preview function or a requested frame size may differ).
  * 7. A rendered frame is sent back to the IDE plugin and is shown in the IDE as an image.
  */
-@Suppress("unused")
+@Suppress("DEPRECATION", "unused")
 internal class NonInteractivePreviewFacade {
     companion object {
         @JvmStatic
@@ -57,7 +56,7 @@
                 // We need to delay the reflection instantiation of the class until we are in the
                 // composable to ensure all the right initialization has happened and the Composable
                 // class loads correctly.
-                ComposableInvoker.invokeComposable(
+                androidx.compose.ui.tooling.ComposableInvoker.invokeComposable(
                     className,
                     methodName,
                     currentComposer
diff --git a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
index 89a9b0c..a64124c 100644
--- a/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
+++ b/compose/ui/ui-tooling/src/desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/runtime/PreviewRunner.kt
@@ -19,7 +19,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.currentComposer
 import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.tooling.ComposableInvoker.invokeComposable
 import androidx.compose.ui.window.Window
 import androidx.compose.ui.window.launchApplication
 import kotlinx.coroutines.DelicateCoroutinesApi
@@ -29,6 +28,7 @@
     companion object {
         private var previewComposition: @Composable () -> Unit = {}
 
+        @Suppress("DEPRECATION")
         @JvmStatic
         @OptIn(ExperimentalComposeUiApi::class)
         fun main(args: Array<String>) {
@@ -40,7 +40,7 @@
                 // We need to delay the reflection instantiation of the class until we are in the
                 // composable to ensure all the right initialization has happened and the Composable
                 // class loads correctly.
-                invokeComposable(
+                androidx.compose.ui.tooling.ComposableInvoker.invokeComposable(
                     className,
                     methodName,
                     currentComposer
diff --git a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
index 20309f7..28d41ec 100644
--- a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
+++ b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
@@ -25,6 +25,7 @@
 /**
  * A utility object to invoke composable function by its name and containing class.
  */
+@Deprecated("Use androidx.compose.runtime.reflect.ComposableMethodInvoker instead")
 @ExperimentalComposeUiApi
 object ComposableInvoker {
 
@@ -56,7 +57,7 @@
     }
 
     private inline fun <reified T> T.dup(count: Int): Array<T> {
-        return (0..count).map { this }.toTypedArray()
+        return (0 until count).map { this }.toTypedArray()
     }
 
     /**
@@ -71,7 +72,6 @@
                 methodName,
                 *args.mapNotNull { it?.javaClass }.toTypedArray(),
                 Composer::class.java, // composer param
-                kotlin.Int::class.java, // key param
                 *kotlin.Int::class.java.dup(changedParams) // changed params
             )
         } catch (e: ReflectiveOperationException) {
@@ -97,7 +97,7 @@
         "double" -> 0.toDouble()
         "float" -> 0.toFloat()
         "boolean" -> false
-        "char" -> '0'
+        "char" -> 0.toChar()
         else -> null
     }
 
@@ -155,7 +155,7 @@
         return invoke(instance, *arguments)
     }
 
-    private const val SLOTS_PER_INT = 15
+    private const val SLOTS_PER_INT = 10
     private const val BITS_PER_INT = 31
 
     private fun changedParamCount(realValueParams: Int, thisParams: Int): Int {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 2e7abc3..a2f5105 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -60,7 +60,7 @@
 
         implementation("androidx.core:core:1.5.0")
         implementation('androidx.collection:collection:1.0.0')
-        implementation(project(":customview:customview-poolingcontainer"))
+        implementation("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
         implementation("androidx.savedstate:savedstate-ktx:1.2.0-rc01")
         implementation("androidx.lifecycle:lifecycle-common-java8:2.3.0")
         implementation("androidx.lifecycle:lifecycle-runtime:2.3.0")
@@ -151,7 +151,7 @@
                 implementation("androidx.autofill:autofill:1.0.0")
                 implementation(libs.kotlinCoroutinesAndroid)
 
-                implementation(project(":customview:customview-poolingcontainer"))
+                implementation("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
                 implementation("androidx.savedstate:savedstate-ktx:1.2.0-rc01")
                 implementation("androidx.lifecycle:lifecycle-common-java8:2.3.0")
                 implementation("androidx.lifecycle:lifecycle-runtime:2.3.0")
diff --git a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
index e7862f4..a886719 100644
--- a/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
+++ b/emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java
@@ -24,10 +24,12 @@
 import static org.mockito.Mockito.mock;
 
 import android.annotation.SuppressLint;
+import android.os.Build;
 import android.text.Editable;
 import android.text.SpannableString;
 import android.text.Spanned;
 
+import androidx.annotation.RequiresApi;
 import androidx.emoji2.text.EmojiMetadata;
 import androidx.emoji2.text.EmojiSpan;
 import androidx.emoji2.text.SpannableBuilder;
@@ -58,6 +60,7 @@
         assertThat(editable, instanceOf(Editable.class));
     }
 
+    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
     @Test
     public void testNewEditable_preservesCharSequenceData() {
         final String string = "abc";
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
index 3e7d8ca..d0ba42d 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.withSettings;
 
+import android.os.Build;
 import android.text.DynamicLayout;
 import android.text.Editable;
 import android.text.Layout;
@@ -45,6 +46,7 @@
 import android.text.style.QuoteSpan;
 import android.text.style.TypefaceSpan;
 
+import androidx.annotation.RequiresApi;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SdkSuppress;
@@ -125,6 +127,7 @@
         assertEquals(1, start);
     }
 
+    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
     @Test
     public void testBlocksSpanCallbacks_forEmojiSpans() {
         final EmojiSpan span = mock(EmojiSpan.class);
@@ -186,6 +189,7 @@
         verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
     }
 
+    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
     @Test
     public void testDoesNotBlockSpanCallbacksForOtherWatchers() {
         final TextWatcher textWatcher = mock(TextWatcher.class);
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e5bafaa..3f27db1 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -121,7 +121,7 @@
 kotlinCoroutinesRx3 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx3", version.ref = "kotlinCoroutines" }
 kotlinDaemonEmbeddable = { module = "org.jetbrains.kotlin:kotlin-daemon-embeddable", version.ref = "kotlin" }
 kotlinKlibCommonizer = { module = "org.jetbrains.kotlin:kotlin-klib-commonizer", version.ref = "kotlin" }
-kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.4.2" }
+kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.5.0" }
 kotlinStdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
 kotlinStdlibCommon = { module = "org.jetbrains.kotlin:kotlin-stdlib-common", version.ref = "kotlin" }
 kotlinStdlibJdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
diff --git a/slidingpanelayout/slidingpanelayout/api/current.txt b/slidingpanelayout/slidingpanelayout/api/current.txt
index 076425d..9340904 100644
--- a/slidingpanelayout/slidingpanelayout/api/current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/current.txt
@@ -6,7 +6,7 @@
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?);
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?, int);
     method public void addPanelSlideListener(androidx.slidingpanelayout.widget.SlidingPaneLayout.PanelSlideListener);
-    method protected boolean canScroll(android.view.View!, boolean, int, int, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
     method @Deprecated public boolean canSlide();
     method public void close();
     method public boolean closePane();
diff --git a/slidingpanelayout/slidingpanelayout/api/public_plus_experimental_current.txt b/slidingpanelayout/slidingpanelayout/api/public_plus_experimental_current.txt
index 076425d..9340904 100644
--- a/slidingpanelayout/slidingpanelayout/api/public_plus_experimental_current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/public_plus_experimental_current.txt
@@ -6,7 +6,7 @@
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?);
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?, int);
     method public void addPanelSlideListener(androidx.slidingpanelayout.widget.SlidingPaneLayout.PanelSlideListener);
-    method protected boolean canScroll(android.view.View!, boolean, int, int, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
     method @Deprecated public boolean canSlide();
     method public void close();
     method public boolean closePane();
diff --git a/slidingpanelayout/slidingpanelayout/api/restricted_current.txt b/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
index 076425d..9340904 100644
--- a/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
@@ -6,7 +6,7 @@
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?);
     ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet?, int);
     method public void addPanelSlideListener(androidx.slidingpanelayout.widget.SlidingPaneLayout.PanelSlideListener);
-    method protected boolean canScroll(android.view.View!, boolean, int, int, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
     method @Deprecated public boolean canSlide();
     method public void close();
     method public boolean closePane();
diff --git a/slidingpanelayout/slidingpanelayout/lint-baseline.xml b/slidingpanelayout/slidingpanelayout/lint-baseline.xml
deleted file mode 100644
index dc294c0..0000000
--- a/slidingpanelayout/slidingpanelayout/lint-baseline.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {"
-        errorLine2="                                ~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected Parcelable onSaveInstanceState() {"
-        errorLine2="              ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-</issues>
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
index 9ba74f4..9de4b03 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
@@ -1426,7 +1426,7 @@
      * @param y      Y coordinate of the active touch point
      * @return true if child views of v can be scrolled by delta of dx.
      */
-    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+    protected boolean canScroll(@NonNull View v, boolean checkV, int dx, int x, int y) {
         if (v instanceof ViewGroup) {
             final ViewGroup group = (ViewGroup) v;
             final int scrollX = v.getScrollX();
@@ -1479,6 +1479,7 @@
         return new LayoutParams(getContext(), attrs);
     }
 
+    @NonNull
     @Override
     protected Parcelable onSaveInstanceState() {
         Parcelable superState = super.onSaveInstanceState();