Fix capitalization and decapitalization deprecations

Fixes: 187985877
Change-Id: Ifb8fc8443cacc944e44b482eba3ae42f30866284
diff --git a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
index 4f1e2fb..dc4996c 100644
--- a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
+++ b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
@@ -41,6 +41,7 @@
 import org.jetbrains.uast.UExpression
 import org.jetbrains.uast.UReferenceExpression
 import org.jetbrains.uast.getParentOfType
+import java.util.Locale
 
 class ExperimentalDetector : Detector(), SourceCodeScanner {
 
@@ -234,9 +235,13 @@
         const val JAVA_OPT_IN_ANNOTATION =
             "androidx.annotation.OptIn"
 
-        @Suppress("DefaultLocale", "DEPRECATION") // b/187985877
+        @Suppress("DefaultLocale")
         private fun issueForLevel(level: String, severity: Severity): Issue = Issue.create(
-            id = "UnsafeOptInUsage${level.capitalize()}",
+            id = "UnsafeOptInUsage${level.replaceFirstChar {
+                if (it.isLowerCase()) it.titlecase(
+                    Locale.getDefault()
+                ) else it.toString()
+            }}",
             briefDescription = "Unsafe opt-in usage intended to be $level-level severity",
             explanation = """
                 This API has been flagged as opt-in with $level-level severity.
diff --git a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableNamingDetector.kt b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableNamingDetector.kt
index 74296ff..f5aa41d 100644
--- a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableNamingDetector.kt
+++ b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableNamingDetector.kt
@@ -54,8 +54,11 @@
 
             if (node.returnsUnit) {
                 if (!capitalizedFunctionName) {
-                    @Suppress("DEPRECATION") // b/187985877
-                    val capitalizedName = name.capitalize(Locale.getDefault())
+                    val capitalizedName = name.replaceFirstChar {
+                        if (it.isLowerCase()) it.titlecase(
+                            Locale.getDefault()
+                        ) else it.toString()
+                    }
                     context.report(
                         ComposableNaming,
                         node,
@@ -73,8 +76,7 @@
                 }
             } else {
                 if (capitalizedFunctionName) {
-                    @Suppress("DEPRECATION") // b/187985877
-                    val lowercaseName = name.decapitalize(Locale.getDefault())
+                    val lowercaseName = name.replaceFirstChar { it.lowercase(Locale.getDefault()) }
                     context.report(
                         ComposableNaming,
                         node,
diff --git a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/ModifierParameterDetector.kt b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/ModifierParameterDetector.kt
index 962beb0..d786c2f 100644
--- a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/ModifierParameterDetector.kt
+++ b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/ModifierParameterDetector.kt
@@ -165,5 +165,8 @@
     }
 }
 
-@Suppress("DEPRECATION") // b/187985877
-private val ModifierParameterName = Names.Ui.Modifier.shortName.decapitalize(Locale.ROOT)
+private val ModifierParameterName = Names.Ui.Modifier.shortName.replaceFirstChar {
+    it.lowercase(
+        Locale.ROOT
+    )
+}
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidStringDelegate.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidStringDelegate.android.kt
index c1a2b7b..33e1e35 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidStringDelegate.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidStringDelegate.android.kt
@@ -31,12 +31,14 @@
         string.lowercase((locale as AndroidLocale).javaLocale)
 
     override fun capitalize(string: String, locale: PlatformLocale): String =
-        @Suppress("DEPRECATION") // b/187985877
-        string.capitalize((locale as AndroidLocale).javaLocale)
+        string.replaceFirstChar {
+            if (it.isLowerCase())
+                it.titlecase((locale as AndroidLocale).javaLocale)
+            else it.toString()
+        }
 
     override fun decapitalize(string: String, locale: PlatformLocale): String =
-        @Suppress("DEPRECATION") // b/187985877
-        string.decapitalize((locale as AndroidLocale).javaLocale)
+        string.replaceFirstChar { it.lowercase((locale as AndroidLocale).javaLocale) }
 }
 
 internal actual fun ActualStringDelegate(): PlatformStringDelegate =
diff --git a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopStringDelegate.desktop.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopStringDelegate.desktop.kt
index 650db82..87dbb789 100644
--- a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopStringDelegate.desktop.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopStringDelegate.desktop.kt
@@ -31,12 +31,15 @@
         string.lowercase((locale as DesktopLocale).locale)
 
     override fun capitalize(string: String, locale: PlatformLocale): String =
-        @Suppress("DEPRECATION") // b/187985877
-        string.capitalize((locale as DesktopLocale).locale)
+        string.replaceFirstChar {
+            if (it.isLowerCase())
+                it.titlecase((locale as DesktopLocale).locale)
+            else
+                it.toString()
+        }
 
     override fun decapitalize(string: String, locale: PlatformLocale): String =
-        @Suppress("DEPRECATION") // b/187985877
-        string.decapitalize((locale as DesktopLocale).locale)
+        string.replaceFirstChar { it.lowercase((locale as DesktopLocale).locale) }
 }
 
 internal actual fun ActualStringDelegate(): PlatformStringDelegate =
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/AnnotatedStringTransformTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/AnnotatedStringTransformTest.kt
index c55e48a..a510bfb 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/AnnotatedStringTransformTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/AnnotatedStringTransformTest.kt
@@ -142,11 +142,15 @@
             )
         )
 
-        @Suppress("DEPRECATION") // b/187985877
         val capitalized = input.capitalize()
 
-        @Suppress("DEPRECATION") // b/187985877
-        assertThat(capitalized.text).isEqualTo(input.text.capitalize())
+        assertThat(capitalized.text).isEqualTo(
+            input.text.replaceFirstChar {
+                if (it.isLowerCase()) it.titlecase(
+                    Locale.getDefault()
+                ) else it.toString()
+            }
+        )
         assertThat(capitalized.spanStyles).isEqualTo(input.spanStyles)
         assertThat(capitalized.paragraphStyles).isEqualTo(input.paragraphStyles)
     }
@@ -166,11 +170,11 @@
             )
         )
 
-        @Suppress("DEPRECATION") // b/187985877
         val decapitalized = input.decapitalize()
 
-        @Suppress("DEPRECATION") // b/187985877
-        assertThat(decapitalized.text).isEqualTo(input.text.decapitalize())
+        assertThat(decapitalized.text).isEqualTo(
+            input.text.replaceFirstChar { it.lowercase(Locale.getDefault()) }
+        )
         assertThat(decapitalized.spanStyles).isEqualTo(input.spanStyles)
         assertThat(decapitalized.paragraphStyles).isEqualTo(input.paragraphStyles)
     }
@@ -189,11 +193,15 @@
                 makeRange(paraStyle2, "iii hhh (jjj)")
             )
         )
-        @Suppress("DEPRECATION") // b/187985877
         val capitalized = input.capitalize(LocaleList("tr"))
 
-        @Suppress("DEPRECATION") // b/187985877
-        assertThat(capitalized.text).isEqualTo(input.text.capitalize(Locale.forLanguageTag("tr")))
+        assertThat(capitalized.text).isEqualTo(
+            input.text.replaceFirstChar {
+                if (it.isLowerCase()) it.titlecase(
+                    Locale.forLanguageTag("tr")
+                ) else it.toString()
+            }
+        )
         assertThat(capitalized.spanStyles).isEqualTo(input.spanStyles)
         assertThat(capitalized.paragraphStyles).isEqualTo(input.paragraphStyles)
     }
@@ -213,12 +221,10 @@
             )
         )
 
-        @Suppress("DEPRECATION") // b/187985877
         val decapitalized = input.decapitalize(LocaleList("tr"))
 
-        @Suppress("DEPRECATION") // b/187985877
         assertThat(decapitalized.text).isEqualTo(
-            input.text.decapitalize(Locale.forLanguageTag("tr"))
+            input.text.replaceFirstChar { it.lowercase(Locale.forLanguageTag("tr")) }
         )
         assertThat(decapitalized.spanStyles).isEqualTo(input.spanStyles)
         assertThat(decapitalized.paragraphStyles).isEqualTo(input.paragraphStyles)
diff --git a/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/ext/String_ext.kt b/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/ext/String_ext.kt
index 1b5539c..cd05fb9 100644
--- a/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/ext/String_ext.kt
+++ b/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/ext/String_ext.kt
@@ -16,11 +16,16 @@
 
 package androidx.navigation.safe.args.generator.ext
 
+import java.util.Locale
+
 fun String.toCamelCase(): String {
     val split = this.split("_")
     if (split.size == 0) return ""
-    @Suppress("DEPRECATION") // b/187985877
-    if (split.size == 1) return split[0].capitalize()
+    if (split.size == 1) return split[0].replaceFirstChar {
+        if (it.isLowerCase()) it.titlecase(
+            Locale.getDefault()
+        ) else it.toString()
+    }
     return split.joinToCamelCase()
 }
 
diff --git a/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt b/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
index f121c0b..36dc115 100644
--- a/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
+++ b/navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
@@ -45,6 +45,7 @@
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import java.util.Locale
 import javax.lang.model.element.Modifier
 
 const val L = "\$L"
@@ -362,8 +363,12 @@
     ).initializer("new $T()", HASHMAP_CLASSNAME).build()
 
     fun setters(thisClassName: ClassName) = args.map { arg ->
-        @Suppress("DEPRECATION") // b/187985877
-        MethodSpec.methodBuilder("set${arg.sanitizedName.capitalize()}").apply {
+        val capitalizedName = arg.sanitizedName.replaceFirstChar {
+            if (it.isLowerCase()) it.titlecase(
+                Locale.getDefault()
+            ) else it.toString()
+        }
+        MethodSpec.methodBuilder("set$capitalizedName").apply {
             addAnnotation(androidAnnotations.NONNULL_CLASSNAME)
             addAnnotation(suppressAnnotationSpec)
             addModifiers(Modifier.PUBLIC)
@@ -516,9 +521,14 @@
         returns(TypeName.BOOLEAN)
     }.build()
 
-    private fun getterFromArgName(sanitizedName: String, suffix: String = "") =
-        @Suppress("DEPRECATION") // b/187985877
-        "get${sanitizedName.capitalize()}$suffix"
+    private fun getterFromArgName(sanitizedName: String, suffix: String = ""): String {
+        val capitalizedName = sanitizedName.replaceFirstChar {
+            if (it.isLowerCase()) it.titlecase(
+                Locale.getDefault()
+            ) else it.toString()
+        }
+        return "get${capitalizedName}$suffix"
+    }
 
     fun hashCodeMethod(
         additionalCode: CodeBlock? = null
diff --git a/navigation/navigation-safe-args-generator/src/test/kotlin/androidx/navigation/safe/args/generator/NavArgumentResolverTest.kt b/navigation/navigation-safe-args-generator/src/test/kotlin/androidx/navigation/safe/args/generator/NavArgumentResolverTest.kt
index 7a1f67d..0d1d1bf 100644
--- a/navigation/navigation-safe-args-generator/src/test/kotlin/androidx/navigation/safe/args/generator/NavArgumentResolverTest.kt
+++ b/navigation/navigation-safe-args-generator/src/test/kotlin/androidx/navigation/safe/args/generator/NavArgumentResolverTest.kt
@@ -27,22 +27,29 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import java.util.Locale
 
 @RunWith(JUnit4::class)
 class NavArgumentResolverTest {
 
     private fun id(id: String) = ResReference("a.b", "id", id)
 
-    private fun createTemplateDestination(name: String) =
-        @Suppress("DEPRECATION") // b/187985877
-        Destination(
-            id(name), ClassName.get("foo", "Fragment${name.capitalize()}"), "test",
+    private fun createTemplateDestination(name: String): Destination {
+        val capitalizedName = name.replaceFirstChar {
+            if (it.isLowerCase())
+                it.titlecase(Locale.getDefault())
+            else
+                it.toString()
+        }
+        return Destination(
+            id(name), ClassName.get("foo", "Fragment$capitalizedName"), "test",
             listOf(
                 Argument("arg1", StringType),
                 Argument("arg2", StringType, StringValue("foo"))
             ),
             emptyList()
         )
+    }
 
     @Test
     fun test() {
diff --git a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/InspectionCompanionGeneration.kt b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/InspectionCompanionGeneration.kt
index da5133e..7cfda87 100644
--- a/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/InspectionCompanionGeneration.kt
+++ b/resourceinspection/resourceinspection-processor/src/main/kotlin/androidx/resourceinspection/processor/InspectionCompanionGeneration.kt
@@ -106,10 +106,11 @@
         addMethod(
             MethodSpec.methodBuilder("readProperties").apply {
                 // Make sure the view parameter name doesn't conflict with anything
-                @Suppress("DEPRECATION") // b/187985877
+                val decapitalizedClassName = view.className.simpleName()
+                    .replaceFirstChar { it.lowercase(Locale.US) }
                 val viewParameter = attributeIdNames.clone()
                     .apply { newName("propertyReader") }
-                    .newName(view.className.simpleName().decapitalize(Locale.US))
+                    .newName(decapitalizedClassName)
 
                 addAnnotation(OVERRIDE)
                 addModifiers(Modifier.PUBLIC)
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
index 421f4f7..55bfae1 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticPropertyMethodElement.kt
@@ -151,8 +151,12 @@
                 return if (propName.startsWith("is")) {
                     propName
                 } else {
-                    @Suppress("DEPRECATION") // b/187985877
-                    "get${propName.capitalize(Locale.US)}"
+                    val capitalizedName = propName.replaceFirstChar {
+                        if (it.isLowerCase()) it.titlecase(
+                            Locale.US
+                        ) else it.toString()
+                    }
+                    "get$capitalizedName"
                 }
             }
         }
@@ -244,8 +248,12 @@
                 return if (propName.startsWith("is")) {
                     "set${propName.substring(2)}"
                 } else {
-                    @Suppress("DEPRECATION") // b/187985877
-                    "set${propName.capitalize(Locale.US)}"
+                    val capitalizedName = propName.replaceFirstChar {
+                        if (it.isLowerCase()) it.titlecase(
+                            Locale.US
+                        ) else it.toString()
+                    }
+                    "set$capitalizedName"
                 }
             }
         }