diff --git a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt index fe941a86e..104de91a6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt @@ -11,6 +11,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ActivityTestRule import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiSelector +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -76,6 +77,7 @@ class BaselinePingTest { companion object { @BeforeClass @JvmStatic + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage fun setupOnce() { val httpClient = ConceptFetchHttpUploader(lazy { GeckoViewFetchClient(ApplicationProvider.getApplicationContext()) diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/ext/String.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/ext/String.kt index b754a8634..71b701679 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/ext/String.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/ext/String.kt @@ -16,10 +16,10 @@ import java.net.URISyntaxException */ fun String.removePrefixesIgnoreCase(vararg prefixes: String): String { var value = this - var lower = this.toLowerCase() + var lower = this.lowercase() prefixes.forEach { - if (lower.startsWith(it.toLowerCase())) { + if (lower.startsWith(it.lowercase())) { value = value.substring(it.length) lower = lower.substring(it.length) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt index b40ad62b1..f88ea09d6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt @@ -134,7 +134,7 @@ private fun countRecyclerViewConstraintLayoutChildren(view: View, parent: View?) return if (view !is ViewGroup) { viewValue } else { - viewValue + view.children.sumBy { countRecyclerViewConstraintLayoutChildren(it, view) } + viewValue + view.children.sumOf { countRecyclerViewConstraintLayoutChildren(it, view) } } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index 3b06fadb0..a306c0914 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -222,10 +222,10 @@ private fun searchWrapper() = onView(withId(R.id.search_wrapper)) private fun assertSearchEngineURL(searchEngineName: String) { mDevice.waitNotNull( - Until.findObject(By.textContains("${searchEngineName.toLowerCase()}.com/?q=mozilla")), + Until.findObject(By.textContains("${searchEngineName.lowercase()}.com/?q=mozilla")), TestAssetHelper.waitingTime ) - onView(allOf(withText(startsWith("${searchEngineName.toLowerCase()}.com")))) + onView(allOf(withText(startsWith("${searchEngineName.lowercase()}.com")))) .check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 143e5c164..32bed7d53 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -17,6 +17,7 @@ import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration.Builder import androidx.work.Configuration.Provider import kotlinx.coroutines.Deferred +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async @@ -125,6 +126,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { PerfStartup.applicationOnCreate.stopAndAccumulate(completeMethodDurationTimerId) } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage protected open fun initializeGlean() { val telemetryEnabled = settings().isTelemetryEnabled @@ -208,6 +210,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun restoreBrowserState() = GlobalScope.launch(Dispatchers.Main) { val store = components.core.store val sessionStorage = components.core.sessionStorage @@ -233,6 +236,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { registerActivityLifecycleCallbacks(PerformanceActivityLifecycleCallbacks(queue)) } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage fun queueInitStorageAndServices() { components.performance.visualCompletenessQueue.queue.runIfReadyOrQueue { GlobalScope.launch(Dispatchers.IO) { @@ -266,12 +270,14 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage fun queueReviewPrompt() { GlobalScope.launch(Dispatchers.IO) { components.reviewPromptController.trackApplicationLaunch() } } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage fun queueRestoreLocale() { components.performance.visualCompletenessQueue.queue.runIfReadyOrQueue { GlobalScope.launch(Dispatchers.IO) { @@ -304,6 +310,8 @@ open class FenixApplication : LocaleAwareApplication(), Provider { // To re-enable this, we need to do so in a way that won't interfere with any startup operations // which acquire reserved+ sqlite lock. Currently, Fennec migrations need to write to storage // on startup, and since they run in a background service we can't simply order these operations. + + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun runStorageMaintenance() { GlobalScope.launch(Dispatchers.IO) { // Bookmarks and history storage sit on top of the same db file so we only need to @@ -358,6 +366,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { * - https://github.com/mozilla/application-services/blob/master/docs/design/megazords.md * - https://mozilla.github.io/application-services/docs/applications/consuming-megazord-libraries.html */ + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun setupMegazord(): Deferred { // Note: Megazord.init() must be called as soon as possible ... Megazord.init() @@ -439,6 +448,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun warmBrowsersCache() { // We avoid blocking the main thread for BrowsersCache on startup by loading it on // background thread. diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt index 14e6ed68c..f1c4c87ac 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt @@ -496,7 +496,7 @@ sealed class Event { } val countLabel: String - get() = "${engineSource.identifier.toLowerCase(Locale.getDefault())}.$label" + get() = "${engineSource.identifier.lowercase(Locale.getDefault())}.$label" val sourceLabel: String get() = "${engineSource.descriptor}.$label" @@ -577,7 +577,7 @@ sealed class Event { } override val extras: Map? - get() = mapOf(Events.browserMenuActionKeys.item to item.toString().toLowerCase(Locale.ROOT)) + get() = mapOf(Events.browserMenuActionKeys.item to item.toString().lowercase(Locale.ROOT)) } data class TabCounterMenuItemTapped(val item: Item) : Event() { @@ -586,7 +586,7 @@ sealed class Event { } override val extras: Map? - get() = mapOf(Events.tabCounterMenuActionKeys.item to item.toString().toLowerCase(Locale.ROOT)) + get() = mapOf(Events.tabCounterMenuActionKeys.item to item.toString().lowercase(Locale.ROOT)) } object AutoPlaySettingVisited : Event() @@ -597,7 +597,7 @@ sealed class Event { } override val extras: Map? - get() = mapOf(Autoplay.settingChangedKeys.autoplaySetting to setting.toString().toLowerCase(Locale.ROOT)) + get() = mapOf(Autoplay.settingChangedKeys.autoplaySetting to setting.toString().lowercase(Locale.ROOT)) } sealed class Search diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt index 31bd3e06e..fd73e6353 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/GleanMetricsService.kt @@ -83,7 +83,7 @@ private class EventWrapper>( if (index == 0) { builder.append(part) } else { - builder.append(part[0].toUpperCase()) + builder.append(part[0].uppercase()) builder.append(part.substring(1)) } } diff --git a/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt index 4183a4bfd..d4cf9b68a 100644 --- a/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt +++ b/app/src/main/java/org/mozilla/fenix/crashes/CrashReporterController.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.crashes import androidx.navigation.NavController +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job @@ -69,6 +70,7 @@ class CrashReporterController( * @param sendCrash If true, submit a crash report. * @return Job if report is submitted through an IO thread, null otherwise */ + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun submitReportIfNecessary(sendCrash: Boolean): Job? { var job: Job? = null val didSubmitReport = if (sendCrash && settings.isCrashReportingEnabled) { diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt index f82398c6a..222ff8684 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt @@ -170,7 +170,7 @@ class CustomTabToolbarMenu( private val poweredBy = BrowserMenuCategory( label = context.getStringWithArgSafe(R.string.browser_menu_powered_by, appName) - .toUpperCase(Locale.getDefault()), + .uppercase(Locale.getDefault()), textSize = CAPTION_TEXT_SIZE, textColorResource = primaryTextColor(), textStyle = Typeface.NORMAL diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index 19c84249e..cbbd5705d 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -75,7 +75,7 @@ fun String.toShortUrl(publicSuffixList: PublicSuffixList): String { return inputString .stripUserInfo() - .toLowerCase(Locale.getDefault()) + .lowercase(Locale.getDefault()) .stripPrefixes() .toUnicode() } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index 42f3943e8..1a5a4a7d1 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -295,7 +295,7 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan } private fun deleteMulti(selected: Set, eventType: Event = Event.RemoveBookmarks) { - selected.forEach { if (it.type == BookmarkNodeType.FOLDER) { + selected.iterator().forEach { if (it.type == BookmarkNodeType.FOLDER) { showRemoveFolderDialog(selected) return } } diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt index 7fb511347..7a9d03fa8 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupTimeline.kt @@ -9,6 +9,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import mozilla.components.service.glean.private.NoReasonCodes @@ -74,6 +75,7 @@ object StartupTimeline { /** * A [LifecycleObserver] for [HomeActivity] focused on startup performance measurement. */ +@OptIn(DelicateCoroutinesApi::class) // GlobalScope usage internal class StartupHomeActivityLifecycleObserver( private val frameworkStartMeasurement: StartupFrameworkStartMeasurement, private val startupTimeline: PingType = Pings.startupTimeline, diff --git a/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt b/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt index af1463612..930ec5952 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt @@ -13,6 +13,7 @@ import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting.PRIVATE import androidx.annotation.WorkerThread import androidx.core.content.getSystemService +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -28,6 +29,7 @@ import org.mozilla.fenix.GleanMetrics.StorageStats as Metrics @RequiresApi(Build.VERSION_CODES.O) // StorageStatsManager object StorageStatsMetrics { + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage fun report(context: Context) { GlobalScope.launch(Dispatchers.IO) { reportSync(context) diff --git a/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt index bf2e2b6a8..ca132a32e 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/about/AboutLibrariesFragment.kt @@ -85,7 +85,7 @@ class AboutLibrariesFragment : Fragment(R.layout.fragment_about_libraries) { val licenseData = licensesData.sliceArray(startOffset until startOffset + length) val licenseText = licenseData.toString(Charset.forName("UTF-8")) LibraryItem(name, licenseText) - }.sortedBy { item -> item.name.toLowerCase(Locale.ROOT) } + }.sortedBy { item -> item.name.lowercase(Locale.ROOT) } } private fun showLicenseDialog(libraryItem: LibraryItem) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt index 35cc659bf..831158be6 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleViewHolders.kt @@ -311,7 +311,7 @@ abstract class BaseLocaleViewHolder( * Similar to Kotlin's capitalize with locale parameter, but that method is currently experimental */ private fun String.capitalize(locale: Locale): String { - return substring(0, 1).toUpperCase(locale) + substring(1) + return substring(0, 1).uppercase(locale) + substring(1) } /** diff --git a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt index 4bb7dcd1c..7839ca965 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataFragment.kt @@ -55,14 +55,14 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da ) settings = requireContext().settings() - getCheckboxes().forEach { + getCheckboxes().iterator().forEach { it.onCheckListener = { _ -> updateDeleteButton() updatePreference(it) } } - getCheckboxes().forEach { + getCheckboxes().iterator().forEach { it.isChecked = when (it.id) { R.id.open_tabs_item -> settings.deleteOpenTabs R.id.browsing_data_item -> settings.deleteBrowsingHistory diff --git a/app/src/main/java/org/mozilla/fenix/share/ShareController.kt b/app/src/main/java/org/mozilla/fenix/share/ShareController.kt index bb7c72643..832baa214 100644 --- a/app/src/main/java/org/mozilla/fenix/share/ShareController.kt +++ b/app/src/main/java/org/mozilla/fenix/share/ShareController.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Deferred +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import mozilla.components.concept.engine.prompt.ShareData @@ -141,6 +142,7 @@ class DefaultShareController( dismiss(ShareController.Result.DISMISSED) } + @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage private fun shareToDevicesWithRetry(shareOperation: () -> Deferred) { // Use GlobalScope to allow the continuation of this method even if the share fragment is closed. GlobalScope.launch(Dispatchers.Main) { diff --git a/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DefaultDeleteBrowsingDataControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DefaultDeleteBrowsingDataControllerTest.kt index 328f5ffb3..a7354c475 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DefaultDeleteBrowsingDataControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/deletebrowsingdata/DefaultDeleteBrowsingDataControllerTest.kt @@ -8,6 +8,7 @@ import io.mockk.coVerify import io.mockk.mockk import io.mockk.spyk import io.mockk.verify +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.GlobalScope.coroutineContext import kotlinx.coroutines.test.TestCoroutineDispatcher @@ -45,6 +46,7 @@ class DefaultDeleteBrowsingDataControllerTest { private lateinit var controller: DefaultDeleteBrowsingDataController @Before + @OptIn(DelicateCoroutinesApi::class) // coroutineContext usage fun setup() { controller = DefaultDeleteBrowsingDataController( removeAllTabs = removeAllTabs, diff --git a/build.gradle b/build.gradle index ef36e1705..f52edd3f8 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,8 @@ allprojects { kotlinOptions.jvmTarget = "1.8" kotlinOptions.allWarningsAsErrors = true kotlinOptions.freeCompilerArgs += [ - "-Xuse-experimental=kotlin.Experimental" + "-Xuse-experimental=kotlin.Experimental", + "-Xopt-in=kotlin.RequiresOptIn" ] } } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 19832e82c..5afab644c 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object Versions { - const val kotlin = "1.4.30" - const val coroutines = "1.4.2" + const val kotlin = "1.5.10" + const val coroutines = "1.5.0" // These versions are linked: lint should be X+23.Y.Z of gradle_plugin version, according to: // https://github.com/alexjlockwood/android-lint-checks-demo/blob/0245fc027463137b1b4afb97c5295d60dce998b6/dependencies.gradle#L3