diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bce3efffa..28a05f8b23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'zulu' - uses: gradle/gradle-build-action@v2 - name: Build and run unit tests with Gradle diff --git a/.github/workflows/renovate-config-validation.yml b/.github/workflows/renovate-config-validation.yml new file mode 100644 index 0000000000..128c882567 --- /dev/null +++ b/.github/workflows/renovate-config-validation.yml @@ -0,0 +1,9 @@ +name: "Validate Renovate Config" +on: [push, pull_request] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: suzuki-shunsuke/github-action-renovate-config-validator@v0.1.2 diff --git a/annotation/compiler/build.gradle b/annotation/compiler/build.gradle index 5d09e8e1aa..7329c93608 100644 --- a/annotation/compiler/build.gradle +++ b/annotation/compiler/build.gradle @@ -11,11 +11,11 @@ configurations { dependencies { jarjar "com.googlecode.jarjar:jarjar:1.3" - compileOnly "com.squareup:javapoet:${JAVAPOET_VERSION}" - compileOnly "com.google.auto.service:auto-service:${AUTO_SERVICE_VERSION}" - compileOnly "com.google.code.findbugs:jsr305:${JSR_305_VERSION}" + compileOnly libs.javapoet + compileOnly libs.autoservice + compileOnly libs.findbugs.jsr305 implementation project(':annotation') - annotationProcessor "com.google.auto.service:auto-service:${AUTO_SERVICE_VERSION}" + annotationProcessor libs.autoservice } javadoc { diff --git a/annotation/compiler/test/build.gradle b/annotation/compiler/test/build.gradle index 1c8294c6e5..925402b22c 100644 --- a/annotation/compiler/test/build.gradle +++ b/annotation/compiler/test/build.gradle @@ -27,11 +27,11 @@ afterEvaluate { } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdk libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } @@ -56,9 +56,9 @@ android { dependencies { testImplementation project(':glide') testImplementation project(':annotation:compiler') - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "com.squareup:javapoet:${JAVAPOET_VERSION}" - testImplementation "com.google.code.findbugs:jsr305:${JSR_305_VERSION}" + testImplementation libs.junit + testImplementation libs.javapoet + testImplementation libs.findbugs.jsr305 // Using 0.10 of compile-testing is required for Android Studio to function, but not for the // gradle build. Not yet clear why, but it looks like some kind of version conflict between // javapoet, guava and/or truth. @@ -68,13 +68,13 @@ dependencies { // confusing. exclude group: "com.google.auto.value", module: "auto-value" } - testImplementation "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" - testImplementation "androidx.fragment:fragment:${ANDROID_X_FRAGMENT_VERSION}" + testImplementation libs.androidx.annotation + testImplementation libs.androidx.fragment // TODO: Find some way to include a similar dependency on java 9+ and re-enable these tests in gradle. // testImplementation files(Jvm.current().getJre().homeDir.getAbsolutePath()+'/lib/rt.jar') testAnnotationProcessor project(':annotation:compiler') - testAnnotationProcessor "com.google.auto.service:auto-service:${AUTO_SERVICE_VERSION}" + testAnnotationProcessor libs.autoservice } task regenerateTestResources { diff --git a/annotation/ksp/build.gradle b/annotation/ksp/build.gradle index b8a62747a8..febb5e62b4 100644 --- a/annotation/ksp/build.gradle +++ b/annotation/ksp/build.gradle @@ -4,11 +4,11 @@ plugins { } dependencies { - implementation("com.squareup:kotlinpoet:1.12.0") + implementation libs.kotlinpoet implementation project(":annotation") - implementation 'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6' - ksp("dev.zacsweers.autoservice:auto-service-ksp:1.0.0") - implementation("com.google.auto.service:auto-service-annotations:1.0.1") + implementation libs.ksp + implementation libs.autoservice.annotations + ksp libs.ksp.autoservice } apply from: "${rootProject.projectDir}/scripts/upload.gradle" diff --git a/annotation/ksp/integrationtest/build.gradle b/annotation/ksp/integrationtest/build.gradle index 610e2716ac..16ee4b0d07 100644 --- a/annotation/ksp/integrationtest/build.gradle +++ b/annotation/ksp/integrationtest/build.gradle @@ -15,24 +15,24 @@ plugins { } android { - compileSdkVersion COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdkVersion MIN_SDK_VERSION as int - targetSdkVersion TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } } dependencies { - implementation "junit:junit:$JUNIT_VERSION" + implementation libs.junit testImplementation project(":annotation:ksp:test") testImplementation project(":annotation:ksp") testImplementation project(":annotation") testImplementation project(":glide") testImplementation project(":integration:okhttp3") - testImplementation "com.github.tschuchortdev:kotlin-compile-testing-ksp:${KOTLIN_COMPILE_TESTING_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "org.jetbrains.kotlin:kotlin-test:${JETBRAINS_KOTLIN_TEST_VERSION}" + testImplementation libs.ksp.compiletesting + testImplementation libs.truth + testImplementation libs.kotlin.test testImplementation project(path: ':annotation:ksp:test') } \ No newline at end of file diff --git a/annotation/ksp/test/build.gradle b/annotation/ksp/test/build.gradle index 64f7287156..8de75bffa7 100644 --- a/annotation/ksp/test/build.gradle +++ b/annotation/ksp/test/build.gradle @@ -4,22 +4,22 @@ plugins { } android { - compileSdkVersion COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdkVersion MIN_SDK_VERSION as int - targetSdkVersion TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } } dependencies { - implementation "junit:junit:$JUNIT_VERSION" + implementation libs.junit implementation project(":annotation:ksp") - implementation "com.github.tschuchortdev:kotlin-compile-testing-ksp:${KOTLIN_COMPILE_TESTING_VERSION}" - implementation "com.google.truth:truth:${TRUTH_VERSION}" + implementation libs.ksp.compiletesting + implementation libs.truth testImplementation project(":annotation:ksp") testImplementation project(":annotation") testImplementation project(":glide") - testImplementation "org.jetbrains.kotlin:kotlin-test:${JETBRAINS_KOTLIN_TEST_VERSION}" + testImplementation libs.kotlin.test } \ No newline at end of file diff --git a/benchmark/build.gradle b/benchmark/build.gradle index 0eedc157d2..e5022d06ee 100644 --- a/benchmark/build.gradle +++ b/benchmark/build.gradle @@ -4,7 +4,8 @@ plugins { } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() + buildToolsVersion "30.0.3" compileOptions { @@ -14,7 +15,7 @@ android { defaultConfig { minSdk 19 - targetSdk TARGET_SDK_VERSION as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName "1.0" @@ -32,12 +33,12 @@ android { } dependencies { - androidTestImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" - androidTestImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - androidTestImplementation "junit:junit:{$JUNIT_VERSION}" + androidTestImplementation libs.androidx.test.runner + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.junit androidTestImplementation project(':library') androidTestImplementation project(':testutil') - androidTestImplementation "androidx.benchmark:benchmark-junit4:${ANDROID_X_BENCHMARK_VERSION}" - androidTestImplementation "com.google.guava:guava:${GUAVA_VERSION}" + androidTestImplementation libs.androidx.benchmark.junit + androidTestImplementation libs.guava } \ No newline at end of file diff --git a/build.gradle b/build.gradle index b80b4b3768..77064c167d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,17 +9,18 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:$ANDROID_GRADLE_VERSION" + classpath libs.android.gradle if (!hasProperty('DISABLE_ERROR_PRONE')) { - classpath "net.ltgt.gradle:gradle-errorprone-plugin:$ERROR_PRONE_PLUGIN_VERSION" + classpath libs.errorprone.gradle } - classpath 'com.guardsquare:proguard-gradle:7.1.0' - classpath "se.bjurr.violations:violations-gradle-plugin:$VIOLATIONS_PLUGIN_VERSION" - classpath "androidx.benchmark:benchmark-gradle-plugin:$ANDROID_X_BENCHMARK_VERSION" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$JETBRAINS_KOTLIN_VERSION" - classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$KSP_GRADLE_PLUGIN_VERSION" - classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$JETBRAINS_KOTLINX_BINARY_COMPATIBILITY_VALIDATOR_VERSION" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:$JETBRAINS_DOKKA_VERSION" + classpath libs.proguard.gradle + classpath libs.violations + classpath libs.androidx.benchmark.gradle + classpath libs.kotlin.gradle + classpath libs.ksp.gradle + classpath libs.coroutines.binarycompat.gradle + classpath libs.dokka.gradle + classpath 'com.guardsquare:proguard-gradle:' + (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11) ? '7.3.2' : '7.1.0') } } diff --git a/gradle.properties b/gradle.properties index 9bc226797d..f57f03b6c2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,83 +33,14 @@ POM_SCM_URL=https\://github.com/bumptech/glide POM_URL=https\://github.com/bumptech/glide ## Gradle config -android.enableJetifier=true android.useAndroidX=true org.gradle.configureondemand=false org.gradle.daemon=true org.gradle.jvmargs=-Xmx4096M TEST_JVM_MEMORY_SIZE=4096M -## Glide versioning +## Glide versioning - these may be overwritten in lower level gradle.properties files VERSION_MAJOR=4 VERSION_MINOR=16 VERSION_PATCH=0 -VERSION_NAME=4.16.0-SNAPSHOT - -## SDK versioning -COMPILE_SDK_VERSION=33 -MIN_SDK_VERSION=14 -OK_HTTP_4_MIN_SDK_VERSION=21 -TARGET_SDK_VERSION=32 - -## AndroidX versions -ANDROID_X_ANNOTATION_VERSION=1.3.0 -ANDROID_X_APPCOMPAT_VERSION=1.3.1 -ANDROID_X_BENCHMARK_VERSION=1.1.0 -ANDROID_X_CARDVIEW_VERSION=1.0.0 -ANDROID_X_COMPOSE_VERSION=1.3.2 -ANDROID_X_COMPOSE_FOUNDATION_VERSION=1.3.1 -ANDROID_X_COMPOSE_MATERIAL_VERSION=1.3.1 -ANDROID_X_CONCURRENT_FUTURES_VERSION=1.1.0 -ANDROID_X_CORE_VERSION=1.6.0 -ANDROID_X_EXIF_INTERFACE_VERSION=1.3.3 -# At least versions 1.5 and later require java 8 desugaring, which Glide can't -# currently use, so we're stuck on an older version. -ANDROID_X_FRAGMENT_VERSION=1.3.6 -ANDROID_X_RECYCLERVIEW_VERSION=1.2.1 -ANDROID_X_TEST_CORE_VERSION=1.4.0 -ANDROID_X_TEST_ESPRESSO_VERSION=3.4.0 -ANDROID_X_TEST_JUNIT_VERSION=1.1.3 -ANDROID_X_TEST_RULES_VERSION=1.4.0 -ANDROID_X_TEST_RUNNER_VERSION=1.4.0 -ANDROID_X_TEST_CORE_KTX_VERSION=1.4.0 -ANDROID_X_TEST_JUNIT_KTX_VERSION=1.1.3 -ANDROID_X_TRACING_VERSION=1.0.0 -ANDROID_X_VECTOR_DRAWABLE_ANIMATED_VERSION=1.1.0 -ANDROID_X_CORE_KTX_VERSION=1.8.0 -ANDROID_X_LIFECYCLE_KTX_VERSION=2.4.1 - -ANDROID_SUPPORT_MULTIDEX_VERSION=1.0.3 - -# org.jetbrains versions -JETBRAINS_KOTLINX_COROUTINES_VERSION=1.6.4 -JETBRAINS_KOTLINX_COROUTINES_TEST_VERSION=1.6.4 -JETBRAINS_KOTLIN_VERSION=1.7.0 -JETBRAINS_KOTLIN_TEST_VERSION=1.7.0 -JETBRAINS_KOTLINX_BINARY_COMPATIBILITY_VALIDATOR_VERSION=0.11.0 -JETBRAINS_DOKKA_VERSION=1.7.10 - -## Other dependency versions -ACCOMPANIEST_VERSION=0.25.1 -ANDROID_GRADLE_VERSION=7.3.0 -AUTO_SERVICE_VERSION=1.0-rc3 -KOTLIN_COMPILE_TESTING_VERSION=1.4.9 -DAGGER_VERSION=2.15 -ERROR_PRONE_PLUGIN_VERSION=2.0.2 -ERROR_PRONE_VERSION=2.18.0 -GUAVA_TESTLIB_VERSION=18.0 -GUAVA_VERSION=28.1-android -JAVAPOET_VERSION=1.9.0 -JSR_305_VERSION=3.0.2 -JUNIT_VERSION=4.13.2 -KSP_GRADLE_PLUGIN_VERSION=1.7.0-1.0.6 -MOCKITO_ANDROID_VERSION=2.24.0 -MOCKITO_VERSION=2.24.0 -MOCKWEBSERVER_VERSION=3.0.0-RC1 -OK_HTTP_VERSION=3.10.0 -OK_HTTP_4_VERSION=4.10.0 -PMD_VERSION=6.0.0 -ROBOLECTRIC_VERSION=4.8.1 -TRUTH_VERSION=1.1.3 -VIOLATIONS_PLUGIN_VERSION=1.8 -VOLLEY_VERSION=1.2.0 +VERSION_NAME=4.16.0-SNAPSHOT \ No newline at end of file diff --git a/instrumentation/build.gradle b/instrumentation/build.gradle index b3fdc67172..f884cd9c8c 100644 --- a/instrumentation/build.gradle +++ b/instrumentation/build.gradle @@ -8,34 +8,34 @@ apply plugin: 'com.android.application' dependencies { annotationProcessor project(":annotation:compiler") implementation project(":library") - implementation "com.android.support:multidex:$ANDROID_SUPPORT_MULTIDEX_VERSION" - implementation "androidx.appcompat:appcompat:$ANDROID_X_APPCOMPAT_VERSION" + implementation libs.androidx.multidex + implementation libs.androidx.appcompat androidTestImplementation project(':library') androidTestImplementation project(':mocks') androidTestImplementation project(':testutil') - androidTestImplementation "org.mockito:mockito-android:$MOCKITO_ANDROID_VERSION" - androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION" - androidTestImplementation "androidx.test:rules:$ANDROID_X_TEST_RULES_VERSION" - androidTestImplementation "androidx.test:core:$ANDROID_X_TEST_CORE_VERSION" - androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$ANDROID_X_TEST_ESPRESSO_VERSION" - androidTestImplementation "androidx.test.espresso:espresso-core:$ANDROID_X_TEST_ESPRESSO_VERSION" - androidTestImplementation "com.google.truth:truth:$TRUTH_VERSION" - androidTestImplementation "junit:junit:$JUNIT_VERSION" - androidTestImplementation "androidx.exifinterface:exifinterface:$ANDROID_X_EXIF_INTERFACE_VERSION" + androidTestImplementation libs.mockito.android + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.test.rules + androidTestImplementation libs.androidx.test.core + androidTestImplementation libs.androidx.espresso.idling + androidTestImplementation libs.androidx.espresso + androidTestImplementation libs.truth + androidTestImplementation libs.junit + androidTestImplementation libs.androidx.exifinterface // Not totally clear why this is required, but it seems to be missing when tests are run on // 4.1.2 and 4.2.0 emulators. - androidTestImplementation "com.google.code.findbugs:jsr305:$JSR_305_VERSION" + androidTestImplementation libs.findbugs.jsr305 } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId 'com.bumptech.glide.instrumentation' - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName '1.0' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/integration/avif/build.gradle b/integration/avif/build.gradle index 35c09a65bd..ff5209519b 100644 --- a/integration/avif/build.gradle +++ b/integration/avif/build.gradle @@ -3,17 +3,17 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') implementation 'org.aomedia.avif.android:avif:0.11.1.3c786d2' - implementation "com.google.guava:guava:${GUAVA_VERSION}" + implementation libs.guava annotationProcessor project(':annotation:compiler') } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/compose/build.gradle b/integration/compose/build.gradle index 89480bfd7f..6569fe7ed9 100644 --- a/integration/compose/build.gradle +++ b/integration/compose/build.gradle @@ -24,7 +24,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion '1.2.0' + kotlinCompilerExtensionVersion libs.versions.kotlin.compiler.extension.get() } compileOptions { @@ -50,19 +50,19 @@ dependencies { implementation(project(':integration:recyclerview')) { transitive = false } - implementation "androidx.compose.foundation:foundation:$ANDROID_X_COMPOSE_FOUNDATION_VERSION" - implementation "androidx.compose.ui:ui:$ANDROID_X_COMPOSE_VERSION" - implementation "com.google.accompanist:accompanist-drawablepainter:$ACCOMPANIEST_VERSION" - implementation "androidx.core:core-ktx:$ANDROID_X_CORE_KTX_VERSION" - debugImplementation "androidx.compose.ui:ui-test-manifest:$ANDROID_X_COMPOSE_VERSION" - androidTestImplementation "junit:junit:$JUNIT_VERSION" - androidTestImplementation "androidx.compose.ui:ui-test-junit4:$ANDROID_X_COMPOSE_VERSION" - androidTestImplementation "androidx.test.espresso:espresso-core:$ANDROID_X_TEST_ESPRESSO_VERSION" - androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$ANDROID_X_TEST_ESPRESSO_VERSION" - androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION" - androidTestImplementation "androidx.compose.material:material:$ANDROID_X_COMPOSE_MATERIAL_VERSION" + implementation libs.compose.foundation + implementation libs.compose.ui + implementation libs.drawablepainter + implementation libs.androidx.core.ktx + debugImplementation libs.compose.ui.testmanifest + androidTestImplementation libs.junit + androidTestImplementation libs.compose.ui.testjunit4 + androidTestImplementation libs.androidx.espresso + androidTestImplementation libs.androidx.espresso.idling + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.compose.material + androidTestImplementation libs.truth androidTestImplementation project(':testutil') - androidTestImplementation "com.google.truth:truth:${TRUTH_VERSION}" } apply from: "${rootProject.projectDir}/scripts/upload.gradle" diff --git a/integration/compose/rules.bzl b/integration/compose/rules.bzl deleted file mode 100644 index d36b18dc99..0000000000 --- a/integration/compose/rules.bzl +++ /dev/null @@ -1,51 +0,0 @@ -""" -Workaround for the lack of kt_android_library_test_rule (b/243549140). -""" - -load("//tools/build_defs/kotlin:rules.bzl", "kt_android_library") -load("//tools/build_defs/android:rules.bzl", "android_library_test") - -def kt_android_library_test(name, size, srcs, custom_package, manifest, manifest_values, deps, target_devices, test_class): - """A simple equivalent of android_library_test that works with Kotlin. - - This is not well generalized. A better solution is b/243549140, which would - mean adding a real kt_android_library_test to Android's test_macros: - http://google3/tools/build_defs/android/dev/test_macros.bzl;l=17;rcl=470614953 - - While this is only used in one place and we could theoretically move a bunch - of constants out of the test rule into this one, it seems better not to do - so. Leaving the constant values in the calling BUILD file should make a - migration to a real kt_android_library_test rule easier in the future. - - Args: - name: The test name - size: The test size, probably large - srcs: The test library source set - custom_package: The test library and android_library_test package - manifest: The android_library_test manifest - manifest_values: The android_library_test manifest values - deps: the test library and android_library_test dependencies - target_devices: the target devices passed to android_library_test - test_class: the test class for the android_library_test - """ - library_attrs = {} - library_attrs["srcs"] = srcs - library_attrs["deps"] = deps - library_attrs["testonly"] = 1 - library_attrs["custom_package"] = custom_package - - libname = name + "_lib" - - test_attrs = {} - test_attrs["deps"] = [":" + libname] - test_attrs["size"] = size - test_attrs["manifest"] = manifest - test_attrs["multidex"] = "legacy" - - test_attrs["target_devices"] = target_devices - test_attrs["manifest"] = manifest - test_attrs["manifest_values"] = manifest_values - test_attrs["test_class"] = test_class - - kt_android_library(libname, **library_attrs) - android_library_test(name, **test_attrs) diff --git a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt index 6778cf64d7..d6c9a6726c 100644 --- a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt +++ b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt @@ -13,7 +13,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.DefaultAlpha import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.semantics.SemanticsPropertyKey @@ -35,9 +34,8 @@ import com.google.accompanist.drawablepainter.rememberDrawablePainter public typealias RequestBuilderTransform = (RequestBuilder) -> RequestBuilder /** - * Start a request by passing [model] to [RequestBuilder.load] using the given [requestManager] and - * then applying the [requestBuilderTransform] function to add options or apply mutations if the - * caller desires. + * Start a request by passing [model] to [RequestBuilder.load] and then applying the + * [requestBuilderTransform] function to add options or apply mutations if the caller desires. * * [alignment], [contentScale], [alpha], [colorFilter] and [contentDescription] have the same * defaults (if any) and function identically to the parameters in [Image]. @@ -51,10 +49,6 @@ public typealias RequestBuilderTransform = (RequestBuilder) -> RequestBuil * explicitly if you can. You may end up loading a substantially larger image than you need, which * will increase memory usage and may also increase latency. * - * If you provide your own [requestManager] rather than using this method's default, consider using - * [remember] at a higher level to avoid some amount of overhead of retrieving it each - * re-composition. - * * This method will inspect [contentScale] and apply a matching transformation if one exists. Any * automatically applied transformation can be overridden using [requestBuilderTransform]. Either * apply a specific transformation instead, or use [RequestBuilder.dontTransform]] @@ -111,7 +105,7 @@ public fun GlideImage( .let { failure?.apply(it::error, it::error) ?: it } val overrideSize: Size? = requestBuilder.overrideSize() - val (size, finalModifier) = rememberSizeAndModifier(overrideSize, modifier) + val size = rememberResolvableSize(overrideSize) // TODO(judds): It seems like we should be able to use the production paths for // resource / drawables as well as Composables. It's not totally clear what part of the prod code @@ -124,7 +118,7 @@ public fun GlideImage( SizedGlideImage( requestBuilder = requestBuilder, size = size, - modifier = finalModifier, + modifier = modifier, contentDescription = contentDescription, alignment = alignment, contentScale = contentScale, @@ -233,25 +227,13 @@ public sealed class Placeholder { } } -@OptIn(InternalGlideApi::class) -private data class SizeAndModifier(val size: ResolvableGlideSize, val modifier: Modifier) - @OptIn(InternalGlideApi::class) @Composable -private fun rememberSizeAndModifier( +private fun rememberResolvableSize( overrideSize: Size?, - modifier: Modifier, ) = - remember(overrideSize, modifier) { - if (overrideSize != null) { - SizeAndModifier(ImmediateGlideSize(overrideSize), modifier) - } else { - val sizeObserver = SizeObserver() - SizeAndModifier( - AsyncGlideSize(sizeObserver::getSize), - modifier.sizeObservingModifier(sizeObserver) - ) - } + remember(overrideSize) { + overrideSize?.let { ImmediateGlideSize(it) } ?: AsyncGlideSize() } @Composable @@ -347,17 +329,6 @@ private fun rememberGlidePainter( return remember(requestBuilder, size) { GlidePainter(requestBuilder, size, scope) } } -@OptIn(InternalGlideApi::class) -private fun Modifier.sizeObservingModifier(sizeObserver: SizeObserver): Modifier = - this.layout { measurable, constraints -> - val inferredSize = constraints.inferredGlideSize() - if (inferredSize != null) { - sizeObserver.setSize(inferredSize) - } - val placeable = measurable.measure(constraints) - layout(placeable.width, placeable.height) { placeable.place(0, 0) } - } - internal val DisplayedDrawableKey = SemanticsPropertyKey>("DisplayedDrawable") internal var SemanticsPropertyReceiver.displayedDrawable by DisplayedDrawableKey diff --git a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt index 5c1cf28436..adb81d1568 100644 --- a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt +++ b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlidePainter.kt @@ -3,7 +3,6 @@ package com.bumptech.glide.integration.compose import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.RememberObserver import androidx.compose.runtime.Stable @@ -20,7 +19,9 @@ import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.graphics.painter.Painter import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.integration.ktx.AsyncGlideSize import com.bumptech.glide.integration.ktx.ExperimentGlideFlows +import com.bumptech.glide.integration.ktx.ImmediateGlideSize import com.bumptech.glide.integration.ktx.InternalGlideApi import com.bumptech.glide.integration.ktx.Placeholder import com.bumptech.glide.integration.ktx.ResolvableGlideSize @@ -44,7 +45,7 @@ internal class GlidePainter @OptIn(InternalGlideApi::class) constructor( private val requestBuilder: RequestBuilder, - private val size: ResolvableGlideSize, + private val resolvableSize: ResolvableGlideSize, scope: CoroutineScope, ) : Painter(), RememberObserver { @OptIn(ExperimentGlideFlows::class) internal var status: Status by mutableStateOf(Status.CLEARED) @@ -59,7 +60,15 @@ constructor( override val intrinsicSize: Size get() = delegate?.intrinsicSize ?: Size.Unspecified + @OptIn(InternalGlideApi::class) override fun DrawScope.onDraw() { + when (resolvableSize) { + is AsyncGlideSize -> { + size.toGlideSize()?.let { resolvableSize.setSize(it) } + } + // Do nothing. + is ImmediateGlideSize -> {} + } delegate?.apply { draw(size, alpha, colorFilter) } } @@ -82,7 +91,7 @@ constructor( @OptIn(ExperimentGlideFlows::class, InternalGlideApi::class) private fun launchRequest() = this.scope.launch { - requestBuilder.flowResolvable(size).collect { + requestBuilder.flowResolvable(resolvableSize).collect { updateDelegate( when (it) { is Resource -> it.resource diff --git a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/Sizes.kt b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/Sizes.kt index cc56d4eb59..c59550f865 100644 --- a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/Sizes.kt +++ b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/Sizes.kt @@ -2,13 +2,12 @@ package com.bumptech.glide.integration.compose -import androidx.compose.ui.unit.Constraints import com.bumptech.glide.RequestBuilder import com.bumptech.glide.integration.ktx.InternalGlideApi import com.bumptech.glide.integration.ktx.Size import com.bumptech.glide.integration.ktx.isValidGlideDimension -import com.bumptech.glide.request.target.Target import kotlinx.coroutines.CompletableDeferred +import kotlin.math.roundToInt internal class SizeObserver { private val size = CompletableDeferred() @@ -32,12 +31,11 @@ internal fun RequestBuilder.overrideSize(): Size? = internal fun RequestBuilder.isOverrideSizeSet(): Boolean = overrideWidth.isValidGlideDimension() && overrideHeight.isValidGlideDimension() -internal fun Constraints.inferredGlideSize(): Size? { - val width = if (hasBoundedWidth) maxWidth else Target.SIZE_ORIGINAL - val height = if (hasBoundedHeight) maxHeight else Target.SIZE_ORIGINAL +internal fun androidx.compose.ui.geometry.Size.toGlideSize(): Size? { + val width = width.roundToInt(); + val height = height.roundToInt(); if (!width.isValidGlideDimension() || !height.isValidGlideDimension()) { - return null + return null; } - return Size(width, height) + return Size(width, height); } - diff --git a/integration/concurrent/build.gradle b/integration/concurrent/build.gradle index fbcf2118ca..4b165aeab8 100644 --- a/integration/concurrent/build.gradle +++ b/integration/concurrent/build.gradle @@ -2,23 +2,23 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') - implementation "com.google.guava:guava:${GUAVA_VERSION}" - implementation "androidx.concurrent:concurrent-futures:${ANDROID_X_CONCURRENT_FUTURES_VERSION}" + implementation libs.guava + implementation libs.androidx.futures testImplementation project(':mocks') testImplementation project(':testutil') - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" + testImplementation libs.androidx.test.core + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.robolectric } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName = VERSION_NAME as String } diff --git a/integration/cronet/build.gradle b/integration/cronet/build.gradle index 77431dd2f1..2cf3ac755b 100644 --- a/integration/cronet/build.gradle +++ b/integration/cronet/build.gradle @@ -2,25 +2,25 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') - implementation 'com.google.android.gms:play-services-cronet:17.0.0' - implementation "com.google.guava:guava:${GUAVA_VERSION}" + implementation libs.cronet + implementation libs.guava implementation project(':annotation') annotationProcessor project(':annotation:compiler') - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + api libs.androidx.annotation - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.robolectric + testImplementation libs.mockito } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { minSdk 16 as int - targetSdk TARGET_SDK_VERSION as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/gifencoder/build.gradle b/integration/gifencoder/build.gradle index ca9543beea..ece4e4a913 100644 --- a/integration/gifencoder/build.gradle +++ b/integration/gifencoder/build.gradle @@ -4,17 +4,17 @@ dependencies { implementation project(':library') testImplementation project(":testutil") - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - testImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric + testImplementation libs.androidx.test.core + testImplementation libs.androidx.junit + testImplementation libs.androidx.test.runner } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() sourceSets { main { @@ -23,8 +23,8 @@ android { } defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName = VERSION_NAME as String } diff --git a/integration/ktx/build.gradle b/integration/ktx/build.gradle index 85c61baa8e..b45e28d72e 100644 --- a/integration/ktx/build.gradle +++ b/integration/ktx/build.gradle @@ -4,11 +4,11 @@ plugins { } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -40,18 +40,20 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { dependencies { api project(":library") - implementation "androidx.core:core-ktx:$ANDROID_X_CORE_KTX_VERSION" - implementation "androidx.test:core-ktx:$ANDROID_X_TEST_CORE_KTX_VERSION" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$JETBRAINS_KOTLINX_COROUTINES_VERSION" - testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$JETBRAINS_KOTLIN_VERSION" - testImplementation "androidx.test.ext:junit-ktx:$ANDROID_X_TEST_JUNIT_KTX_VERSION" - testImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION" - testImplementation "org.robolectric:robolectric:$ROBOLECTRIC_VERSION" - testImplementation "androidx.test:runner:$ANDROID_X_TEST_RUNNER_VERSION" - testImplementation "junit:junit:$JUNIT_VERSION" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$JETBRAINS_KOTLINX_COROUTINES_TEST_VERSION" - testImplementation "com.google.truth:truth:$TRUTH_VERSION" - androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION" + implementation libs.androidx.core.ktx + implementation libs.coroutines.core + testImplementation libs.androidx.espresso + testImplementation libs.androidx.espresso.idling + testImplementation libs.androidx.test.ktx + testImplementation libs.kotlin.junit + testImplementation libs.androidx.test.ktx.junit + testImplementation libs.androidx.junit + testImplementation libs.robolectric + testImplementation libs.androidx.test.runner + testImplementation libs.junit + testImplementation libs.coroutines.test + testImplementation libs.truth + androidTestImplementation libs.androidx.junit } apply from: "${rootProject.projectDir}/scripts/upload.gradle" diff --git a/integration/ktx/src/main/java/com/bumptech/glide/integration/ktx/Flows.kt b/integration/ktx/src/main/java/com/bumptech/glide/integration/ktx/Flows.kt index ad937cb796..a0ce7afa76 100644 --- a/integration/ktx/src/main/java/com/bumptech/glide/integration/ktx/Flows.kt +++ b/integration/ktx/src/main/java/com/bumptech/glide/integration/ktx/Flows.kt @@ -13,6 +13,7 @@ import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.requestManager import com.bumptech.glide.util.Util +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -82,17 +83,18 @@ public fun RequestBuilder.flow( /** * Identical to [flow] with dimensions, except that the size is resolved asynchronously using - * [waitForSize]. + * [size]. * * If an override size has been set using [RequestBuilder.override], that size will be used instead - * and [waitForSize] may never be called. + * and [size] may never be called. * - * [Placeholder] values may be emitted prior to [waitForSize] returning. Similarly if + * [Placeholder] values may be emitted prior to [size] returning. Similarly if * [RequestBuilder.thumbnail] requests are present and have overridden sizes, [Resource] values for - * those thumbnails may also be emitted. [waitForSize] will only be used for requests where no + * those thumbnails may also be emitted. [size] will only be used for requests where no * [RequestBuilder.override] size is available. * - * If [waitForSize] does not return, this flow may never return values other than placeholders. + * If [size] never has [AsyncGlideSize.setSize] called, this flow may never return values other than + * placeholders. * * This function is internal only, intended primarily for Compose. The Target API provides similar * functionality for traditional Views. We could consider expanding the visibility if there are use @@ -101,8 +103,8 @@ public fun RequestBuilder.flow( @InternalGlideApi @ExperimentGlideFlows public fun RequestBuilder.flow( - waitForSize: suspend () -> Size, -): Flow> = flow(AsyncGlideSize(waitForSize)) + size: AsyncGlideSize, +): Flow> = flowResolvable(size) /** * Convert a load in Glide into a flow that emits placeholders and resources in the order they'd be @@ -276,7 +278,7 @@ private class FlowTarget( // begin immediately, shaving off some small amount of time. is AsyncGlideSize -> scope.launch { - val localResolvedSize = size.asyncSize() + val localResolvedSize = size.getSize() val callbacksToNotify: List synchronized(this) { resolvedSize = localResolvedSize @@ -387,6 +389,16 @@ public data class Size(val width: Int, val height: Int) { @InternalGlideApi public data class ImmediateGlideSize(val size: Size) : ResolvableGlideSize() @InternalGlideApi -public data class AsyncGlideSize(val asyncSize: suspend () -> Size) : ResolvableGlideSize() +public class AsyncGlideSize : ResolvableGlideSize() { + private val size = CompletableDeferred() + + public fun setSize(size: Size) { + this.size.complete(size) + } + + public suspend fun getSize(): Size { + return size.await() + } +} @InternalGlideApi public fun Int.isValidGlideDimension(): Boolean = Util.isValidDimension(this) diff --git a/integration/ktx/src/test/java/com/bumptech/glide/integration/ktx/FlowsTest.kt b/integration/ktx/src/test/java/com/bumptech/glide/integration/ktx/FlowsTest.kt index bc784cd8e7..acee8028e4 100644 --- a/integration/ktx/src/test/java/com/bumptech/glide/integration/ktx/FlowsTest.kt +++ b/integration/ktx/src/test/java/com/bumptech/glide/integration/ktx/FlowsTest.kt @@ -10,6 +10,7 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.net.Uri import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onIdle import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumptech.glide.Glide import com.bumptech.glide.GlideBuilder @@ -20,6 +21,7 @@ import com.bumptech.glide.load.Options import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.load.engine.cache.MemoryCache import com.bumptech.glide.load.engine.executor.GlideExecutor +import com.bumptech.glide.load.engine.executor.GlideIdlingResources import com.bumptech.glide.load.model.ModelLoader import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory @@ -29,14 +31,11 @@ import com.google.common.truth.Correspondence import com.google.common.truth.IterableSubject import com.google.common.truth.Truth.assertThat import java.io.File -import java.lang.RuntimeException import java.util.concurrent.atomic.AtomicReference import kotlin.reflect.KClass import kotlin.test.assertFailsWith import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flow @@ -47,6 +46,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.test.runTest import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -54,12 +54,17 @@ import org.junit.runner.RunWith // newFile throws IOException, which triggers this warning even though there's no reasonable // alternative :/. -@Suppress("BlockingMethodInNonBlockingContext") +@Suppress("BlockingMethodInNonBlockingContext", "RedundantSuppression") @RunWith(AndroidJUnit4::class) class FlowsTest { private val context = ApplicationProvider.getApplicationContext() @get:Rule val temporaryFolder = TemporaryFolder() + @Before + fun setUp() { + GlideIdlingResources.initGlide() + } + @After fun tearDown() { Glide.tearDown() @@ -303,8 +308,7 @@ class FlowsTest { @Test fun flow_onClose_clearsTarget() = runTest { val inCache = AtomicReference?>() - Glide.init( - context, + GlideIdlingResources.initGlide( GlideBuilder() .setMemoryCache( object : MemoryCache { @@ -327,11 +331,15 @@ class FlowsTest { inCache.set(resource) return null } - } - ) + } + ) ) val data = Glide.with(context).load(newImageFile()).flow(100, 100).firstLoad().toList() assertThat(data).isNotEmpty() + // Glide's executor (in EngineJob's notify loop) and the coroutine race to close the resource. + // If Glide's executor wins, then the coroutine will be able to put the resource in the cache, + // but if not, the item won't be cached until after the coroutine starts back up. + onIdle() assertThat(inCache.get()).isNotNull() } @@ -483,11 +491,13 @@ class FlowsTest { @Test fun flow_withAsyncSize_andOverrideSize_usesOverrideSize() = runTest { val requestedSizeReference = registerSizeCapturingFakeModelLoader() + val asyncSize = AsyncGlideSize() + asyncSize.setSize(Size(1, 2)) Glide.with(context) .load(FakeModel()) .override(200, 100) - .flow { Size(1, 2) } + .flow(asyncSize) .firstLoad() .toList() @@ -514,11 +524,7 @@ class FlowsTest { @Test fun flow_withAsyncSize_concreteSizeForThumbnail_startsMainRequestWhenAsyncSizeIsAvailable() = runTest { - val waitForThumbnailToFinishChannel = Channel() - val waitForThumbnailToFinishSize: suspend () -> Size = { - waitForThumbnailToFinishChannel.receive() - Size(100, 200) - } + val size = AsyncGlideSize() val result = Glide.with(context) @@ -527,9 +533,9 @@ class FlowsTest { Glide.with(context) .load(newImageFile()) .override(75, 50) - .listener(onSuccess { launch { waitForThumbnailToFinishChannel.send(true) } }) + .listener(onSuccess { launch { size.setSize(Size(100, 200)) } }) ) - .flow(waitForThumbnailToFinishSize) + .flow(size) .firstLoad() .toList() @@ -562,10 +568,7 @@ class FlowsTest { assertFailsWith { requestBuilder.flow() } } - private val delayForever: suspend () -> Size = { - delay(kotlin.time.Duration.INFINITE) - throw RuntimeException() - } + private val delayForever = AsyncGlideSize() private fun registerSizeCapturingFakeModelLoader(): AtomicReference { val result = AtomicReference() diff --git a/integration/ktx/src/test/java/com/bumptech/glide/load/engine/executor/GlideIdlingResourceInit.kt b/integration/ktx/src/test/java/com/bumptech/glide/load/engine/executor/GlideIdlingResourceInit.kt new file mode 100644 index 0000000000..84f6508d32 --- /dev/null +++ b/integration/ktx/src/test/java/com/bumptech/glide/load/engine/executor/GlideIdlingResourceInit.kt @@ -0,0 +1,36 @@ +package com.bumptech.glide.load.engine.executor + +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.IdlingRegistry +import androidx.test.espresso.idling.concurrent.IdlingThreadPoolExecutor +import com.bumptech.glide.Glide +import com.bumptech.glide.GlideBuilder +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.TimeUnit + +object GlideIdlingResources { + + fun initGlide(builder: GlideBuilder? = null) { + val registry = IdlingRegistry.getInstance() + val executor = + IdlingThreadPoolExecutor( + "glide_test_thread", + /* corePoolSize = */ 1, + /* maximumPoolSize = */ 1, + /* keepAliveTime = */ 1, + TimeUnit.SECONDS, + LinkedBlockingQueue() + ) { + Thread(it) + } + val glideExecutor = GlideExecutor(executor) + Glide.init( + ApplicationProvider.getApplicationContext(), + (builder ?: GlideBuilder()) + .setSourceExecutor(glideExecutor) + .setAnimationExecutor(glideExecutor) + .setDiskCacheExecutor(glideExecutor) + ) + registry.register(executor) + } +} diff --git a/integration/okhttp/build.gradle b/integration/okhttp/build.gradle index 2ad9df11fa..b3f71f8c19 100644 --- a/integration/okhttp/build.gradle +++ b/integration/okhttp/build.gradle @@ -4,16 +4,16 @@ dependencies { implementation project(':library') annotationProcessor project(':annotation:compiler') - api "com.squareup.okhttp:okhttp:2.7.5" - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + api libs.okhttp2 + api libs.androidx.annotation } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/okhttp3/build.gradle b/integration/okhttp3/build.gradle index 8d69f27b2b..c6e1e02721 100644 --- a/integration/okhttp3/build.gradle +++ b/integration/okhttp3/build.gradle @@ -4,16 +4,16 @@ dependencies { implementation project(':library') annotationProcessor project(':annotation:compiler') - api "com.squareup.okhttp3:okhttp:${OK_HTTP_VERSION}" - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + api libs.okhttp3 + api libs.androidx.annotation } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/okhttp4/build.gradle b/integration/okhttp4/build.gradle index 3ead9875b0..a9da17bb93 100644 --- a/integration/okhttp4/build.gradle +++ b/integration/okhttp4/build.gradle @@ -4,16 +4,16 @@ dependencies { implementation project(':library') annotationProcessor project(':annotation:compiler') - api "com.squareup.okhttp3:okhttp:${OK_HTTP_4_VERSION}" - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + api libs.okhttp4 + api libs.androidx.annotation } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk OK_HTTP_4_MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.okhttp.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/recyclerview/build.gradle b/integration/recyclerview/build.gradle index 3bb4ac4f25..e3d078a198 100644 --- a/integration/recyclerview/build.gradle +++ b/integration/recyclerview/build.gradle @@ -2,16 +2,16 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') - compileOnly "androidx.recyclerview:recyclerview:${ANDROID_X_RECYCLERVIEW_VERSION}" - compileOnly "androidx.fragment:fragment:${ANDROID_X_FRAGMENT_VERSION}" + compileOnly libs.androidx.recyclerview + compileOnly libs.androidx.fragment } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/integration/sqljournaldiskcache/build.gradle b/integration/sqljournaldiskcache/build.gradle index 224f825dcf..af44543f1e 100644 --- a/integration/sqljournaldiskcache/build.gradle +++ b/integration/sqljournaldiskcache/build.gradle @@ -4,11 +4,11 @@ plugins { } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } @@ -21,16 +21,16 @@ android { dependencies { implementation project(':library') - implementation "com.google.errorprone:error_prone_annotations:$ERROR_PRONE_VERSION" + implementation libs.errorprone.annotations - testImplementation "com.google.guava:guava-testlib:${GUAVA_TESTLIB_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - testImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" + testImplementation libs.guava.testlib + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric + testImplementation libs.androidx.test.core + testImplementation libs.androidx.junit + testImplementation libs.androidx.test.runner } apply from: "${rootProject.projectDir}/scripts/upload.gradle" diff --git a/integration/volley/build.gradle b/integration/volley/build.gradle index d0a9c3febb..8120eca2df 100644 --- a/integration/volley/build.gradle +++ b/integration/volley/build.gradle @@ -2,27 +2,27 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') - api "com.android.volley:volley:${VOLLEY_VERSION}" - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + api libs.volley + api libs.androidx.annotation annotationProcessor project(':annotation:compiler') testImplementation project(":testutil") - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "com.squareup.okhttp3:mockwebserver:${MOCKWEBSERVER_VERSION}" - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - testImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric + testImplementation libs.mockwebserver + testImplementation libs.androidx.test.core + testImplementation libs.androidx.junit + testImplementation libs.androidx.test.runner } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/library/build.gradle b/library/build.gradle index b3625fcd89..9c8bd6eabf 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -12,27 +12,27 @@ dependencies { api project(':third_party:gif_decoder') api project(':third_party:disklrucache') api project(':annotation') - api "androidx.fragment:fragment:${ANDROID_X_FRAGMENT_VERSION}" - api "androidx.vectordrawable:vectordrawable-animated:${ANDROID_X_VECTOR_DRAWABLE_ANIMATED_VERSION}" - api "androidx.exifinterface:exifinterface:${ANDROID_X_EXIF_INTERFACE_VERSION}" - api "androidx.tracing:tracing:${ANDROID_X_TRACING_VERSION}" - compileOnly "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" + api libs.androidx.fragment + api libs.androidx.vectordrawable + api libs.androidx.exifinterface + api libs.androidx.tracing + compileOnly libs.androidx.appcompat if (project.plugins.hasPlugin('net.ltgt.errorprone')) { - errorprone "com.google.errorprone:error_prone_core:${ERROR_PRONE_VERSION}" + errorprone libs.errorprone.core } - testImplementation "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" + testImplementation libs.androidx.appcompat testImplementation project(':testutil') - testImplementation "com.google.guava:guava-testlib:${GUAVA_TESTLIB_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "com.squareup.okhttp3:mockwebserver:${MOCKWEBSERVER_VERSION}" - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - testImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" + testImplementation libs.guava.testlib + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric + testImplementation libs.mockwebserver + testImplementation libs.androidx.test.core + testImplementation libs.androidx.junit + testImplementation libs.androidx.test.runner } if (project.plugins.hasPlugin('net.ltgt.errorprone')) { @@ -59,11 +59,11 @@ if (project.plugins.hasPlugin('net.ltgt.errorprone')) { } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String consumerProguardFiles 'proguard-rules.txt' } diff --git a/library/pmd/build.gradle b/library/pmd/build.gradle index 3ef55b2ff2..05748e5bbd 100644 --- a/library/pmd/build.gradle +++ b/library/pmd/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'pmd' def library = project(':library') pmd { - toolVersion PMD_VERSION + toolVersion libs.versions.pmd.get() } tasks.create('pmd', Pmd) { diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index ba9b33ef11..5b3ed2c3fd 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -95,6 +95,8 @@ public void run() { private boolean pauseAllRequestsOnTrimMemoryModerate; + private boolean clearOnStop; + public RequestManager( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @@ -203,6 +205,17 @@ public synchronized RequestManager setDefaultRequestOptions( return this; } + /** + * Clear all resources when onStop() from {@link LifecycleListener} is called. + * + * @return This request manager. + */ + @NonNull + public synchronized RequestManager clearOnStop() { + clearOnStop = true; + return this; + } + /** * Adds a default {@link RequestListener} that will be added to every request started with this * {@link RequestManager}. @@ -354,12 +367,17 @@ public synchronized void onStart() { /** * Lifecycle callback that unregisters for connectivity events (if the - * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads. + * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads + * and clears all resources if {@link #clearOnStop()} is called. */ @Override public synchronized void onStop() { - pauseRequests(); targetTracker.onStop(); + if (clearOnStop) { + clearRequests(); + } else { + pauseRequests(); + } } /** @@ -369,10 +387,7 @@ public synchronized void onStop() { @Override public synchronized void onDestroy() { targetTracker.onDestroy(); - for (Target target : targetTracker.getAll()) { - clear(target); - } - targetTracker.clear(); + clearRequests(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); @@ -703,6 +718,13 @@ public void onLowMemory() { // Nothing to add conditionally. See Glide#onTrimMemory for unconditional behavior. } + private synchronized void clearRequests() { + for (Target target : targetTracker.getAll()) { + clear(target); + } + targetTracker.clear(); + } + @Override public void onConfigurationChanged(Configuration newConfig) {} diff --git a/library/src/main/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtil.java b/library/src/main/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtil.java index bd00853e12..46951a91e7 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtil.java +++ b/library/src/main/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtil.java @@ -20,6 +20,12 @@ public static boolean isMediaStoreUri(Uri uri) { && MediaStore.AUTHORITY.equals(uri.getAuthority()); } + // Android picker uris contain a "picker" segment: + // https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/PickerUriResolver.java#58 + public static boolean isAndroidPickerUri(Uri uri) { + return isMediaStoreUri(uri) && uri.getPathSegments().contains("picker"); + } + private static boolean isVideoUri(Uri uri) { return uri.getPathSegments().contains("video"); } diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/QMediaStoreUriLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/QMediaStoreUriLoader.java index b19d655e3e..0ad102c8aa 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/QMediaStoreUriLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/QMediaStoreUriLoader.java @@ -156,6 +156,11 @@ private LoadData buildDelegateData() throws FileNotFoundException { if (Environment.isExternalStorageLegacy()) { return fileDelegate.buildLoadData(queryForFilePath(uri), width, height, options); } else { + // Android Picker uris have MediaStore authority and does not accept requireOriginal. + if (MediaStoreUtil.isAndroidPickerUri(uri)) { + return uriDelegate.buildLoadData(uri, width, height, options); + } + Uri toLoad = isAccessMediaLocationGranted() ? MediaStore.setRequireOriginal(uri) : uri; return uriDelegate.buildLoadData(toLoad, width, height, options); } diff --git a/library/src/main/java/com/bumptech/glide/module/ManifestParser.java b/library/src/main/java/com/bumptech/glide/module/ManifestParser.java index b3834f3e8c..35fce96e56 100644 --- a/library/src/main/java/com/bumptech/glide/module/ManifestParser.java +++ b/library/src/main/java/com/bumptech/glide/module/ManifestParser.java @@ -60,11 +60,13 @@ public List parse() { } } } + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Finished loading Glide modules"); + } } catch (PackageManager.NameNotFoundException e) { - throw new RuntimeException("Unable to find metadata to parse GlideModules", e); - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Finished loading Glide modules"); + if (Log.isLoggable(TAG, Log.ERROR)) { + Log.e(TAG, "Failed to parse glide modules", e); + } } return modules; diff --git a/library/test/build.gradle b/library/test/build.gradle index ec4ea82854..9a8b568c1d 100644 --- a/library/test/build.gradle +++ b/library/test/build.gradle @@ -1,19 +1,19 @@ apply plugin: 'com.android.library' dependencies { - testImplementation "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" + testImplementation libs.androidx.appcompat testImplementation project(':library') testImplementation project(':mocks') testImplementation project(':testutil') - testImplementation "com.google.guava:guava-testlib:${GUAVA_TESTLIB_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - testImplementation "com.squareup.okhttp3:mockwebserver:${MOCKWEBSERVER_VERSION}" - testImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - testImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - testImplementation "androidx.test:runner:${ANDROID_X_TEST_RUNNER_VERSION}" + testImplementation libs.guava.testlib + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric + testImplementation libs.mockwebserver + testImplementation libs.androidx.test.core + testImplementation libs.androidx.junit + testImplementation libs.androidx.test.runner } tasks.withType(JavaCompile) { @@ -40,11 +40,11 @@ android.testOptions.unitTests.all { Test testTask -> } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/library/test/src/test/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtilTest.java b/library/test/src/test/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtilTest.java new file mode 100644 index 0000000000..6c84f79ac6 --- /dev/null +++ b/library/test/src/test/java/com/bumptech/glide/load/data/mediastore/MediaStoreUtilTest.java @@ -0,0 +1,30 @@ +package com.bumptech.glide.load.data.mediastore; + +import static com.google.common.truth.Truth.assertThat; + +import android.net.Uri; +import android.provider.MediaStore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 18) +public class MediaStoreUtilTest { + + @Test + public void isAndroidPickerUri_notAndroidPickerUri_returnsFalse() { + Uri mediaStoreUri = Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "123"); + + assertThat(MediaStoreUtil.isAndroidPickerUri(mediaStoreUri)).isFalse(); + } + + @Test + public void isAndroidPickerUri_identifiesAndroidPickerUri_returnsTrue() { + Uri androidPickerUri = + Uri.parse("content://media/picker/0/com.android.providers.media.photopicker/media/123"); + + assertThat(MediaStoreUtil.isAndroidPickerUri(androidPickerUri)).isTrue(); + } +} diff --git a/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java b/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java index 7dcdb06374..c4ecf72f98 100644 --- a/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java +++ b/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java @@ -1,7 +1,6 @@ package com.bumptech.glide.module; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -21,7 +20,6 @@ import java.util.List; import org.junit.Before; import org.junit.Test; -import org.junit.function.ThrowingRunnable; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -125,20 +123,12 @@ public void parse_withNullMetadata_doesNotThrow() throws NameNotFoundException { } @Test - public void parse_withMissingName_throwsRuntimeException() throws NameNotFoundException { + public void parse_withMissingName_doesNotThrow() throws NameNotFoundException { PackageManager pm = mock(PackageManager.class); doThrow(new NameNotFoundException("name")).when(pm).getApplicationInfo(anyString(), anyInt()); when(context.getPackageManager()).thenReturn(pm); - assertThrows( - "Unable to find metadata to parse GlideModules", - RuntimeException.class, - new ThrowingRunnable() { - @Override - public void run() { - parser.parse(); - } - }); + parser.parse(); } private void addModuleToManifest(Class moduleClass) { diff --git a/mocks/build.gradle b/mocks/build.gradle index 329b5581f5..19d6e462a7 100644 --- a/mocks/build.gradle +++ b/mocks/build.gradle @@ -2,17 +2,17 @@ apply plugin: 'com.android.library' dependencies { implementation project(':library') - implementation "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" - implementation "com.google.guava:guava:${GUAVA_VERSION}" - implementation "org.mockito:mockito-core:${MOCKITO_VERSION}" + implementation libs.androidx.annotation + implementation libs.guava + implementation libs.mockito } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName = VERSION_NAME as String } diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000..3e936818e8 --- /dev/null +++ b/renovate.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "packageRules": [ + { + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "automerge": true, + "automergeType": "branch" + }, + { + "matchPackageNames": ["androidx.fragment:fragment"], + "allowedVersions": "1.3.6" + }, + { + "matchPackageNames": ["androidx.annotation:annotation"], + "allowedVersions": "<1.6.0" + }, + { + "matchPackageNames": ["androidx.appcompat:appcompat"], + "allowedVersions": "<1.4.0" + } + ] +} diff --git a/samples/contacturi/build.gradle b/samples/contacturi/build.gradle index b76fb33b58..54c14954e5 100644 --- a/samples/contacturi/build.gradle +++ b/samples/contacturi/build.gradle @@ -2,17 +2,17 @@ apply plugin: 'com.android.application' dependencies { implementation project(':library') - implementation "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" + implementation libs.androidx.appcompat annotationProcessor project(':annotation:compiler') } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId 'com.bumptech.glide.samples.contacturi' - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName '1.0' diff --git a/samples/flickr/build.gradle b/samples/flickr/build.gradle index ad61f941d7..d78280f865 100644 --- a/samples/flickr/build.gradle +++ b/samples/flickr/build.gradle @@ -7,18 +7,18 @@ dependencies { } annotationProcessor project(':annotation:compiler') - implementation "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" - implementation "com.android.volley:volley:${VOLLEY_VERSION}" - implementation "androidx.recyclerview:recyclerview:${ANDROID_X_RECYCLERVIEW_VERSION}" + implementation libs.androidx.appcompat + implementation libs.volley + implementation libs.androidx.recyclerview } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId 'com.bumptech.glide.samples.flickr' - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName '1.0' diff --git a/samples/gallery/build.gradle b/samples/gallery/build.gradle index 875578ead9..20fadbedda 100644 --- a/samples/gallery/build.gradle +++ b/samples/gallery/build.gradle @@ -10,14 +10,14 @@ dependencies { transitive = false } - implementation "androidx.recyclerview:recyclerview:$ANDROID_X_RECYCLERVIEW_VERSION" - implementation "androidx.fragment:fragment-ktx:$ANDROID_X_FRAGMENT_VERSION" - implementation "androidx.core:core-ktx:$ANDROID_X_CORE_KTX_VERSION" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$JETBRAINS_KOTLINX_COROUTINES_VERSION" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$JETBRAINS_KOTLINX_COROUTINES_VERSION" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$JETBRAINS_KOTLIN_VERSION" - implementation "androidx.compose.foundation:foundation:$ANDROID_X_COMPOSE_FOUNDATION_VERSION" - implementation "androidx.compose.ui:ui:$ANDROID_X_COMPOSE_VERSION" + implementation libs.androidx.recyclerview + implementation libs.androidx.fragment.ktx + implementation libs.androidx.core.ktx + implementation libs.coroutines.core + implementation libs.coroutines.android + implementation libs.kotlin.jdk7 + implementation libs.compose.foundation + implementation libs.compose.ui ksp project(':annotation:ksp') } @@ -29,12 +29,12 @@ kotlin { } android { - compileSdk 33 + compileSdk 34 defaultConfig { applicationId 'com.bumptech.glide.samples.gallery' minSdk 29 - targetSdk 33 + targetSdk 34 versionCode 1 versionName '1.0' } @@ -45,7 +45,7 @@ android { jvmTarget = "11" } composeOptions { - kotlinCompilerExtensionVersion '1.2.0' + kotlinCompilerExtensionVersion libs.versions.kotlin.compiler.extension.get() } compileOptions { diff --git a/samples/gallery/src/main/AndroidManifest.xml b/samples/gallery/src/main/AndroidManifest.xml index 8b3f7bd172..6ab0378306 100644 --- a/samples/gallery/src/main/AndroidManifest.xml +++ b/samples/gallery/src/main/AndroidManifest.xml @@ -4,10 +4,15 @@ + android:targetSdkVersion="34" + android:compileSdkVersion="34" /> - + + + = Build.VERSION_CODES.TIRAMISU) { + arrayOf(Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO) + } else { + arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE) + } } } \ No newline at end of file diff --git a/samples/giphy/build.gradle b/samples/giphy/build.gradle index 0f6f3b3e14..d58829317b 100644 --- a/samples/giphy/build.gradle +++ b/samples/giphy/build.gradle @@ -6,18 +6,18 @@ dependencies { transitive = false } implementation 'com.google.code.gson:gson:2.8.2' - implementation "androidx.recyclerview:recyclerview:${ANDROID_X_RECYCLERVIEW_VERSION}" - implementation "androidx.fragment:fragment:${ANDROID_X_FRAGMENT_VERSION}" + implementation libs.androidx.recyclerview + implementation libs.androidx.fragment annotationProcessor project(':annotation:compiler') } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId 'com.bumptech.glide.samples.giphy' - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName '1.0' } diff --git a/samples/imgur/build.gradle b/samples/imgur/build.gradle index 2f678528ef..34a7056bd9 100644 --- a/samples/imgur/build.gradle +++ b/samples/imgur/build.gradle @@ -1,17 +1,16 @@ apply plugin: 'com.android.application' android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId "com.bumptech.glide.samples.imgur" - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 @@ -28,29 +27,26 @@ dependencies { implementation project(':library') annotationProcessor project(':annotation:compiler') - implementation "com.google.dagger:dagger:${DAGGER_VERSION}" - annotationProcessor "com.google.dagger:dagger-compiler:${DAGGER_VERSION}" - implementation "com.google.dagger:dagger-android:${DAGGER_VERSION}" - implementation ("com.google.dagger:dagger-android-support:${DAGGER_VERSION}") { - exclude group: "com.android.support" - } - annotationProcessor "com.google.dagger:dagger-android-processor:${DAGGER_VERSION}" + implementation libs.dagger + implementation libs.dagger.android + annotationProcessor libs.dagger.compiler + annotationProcessor libs.dagger.android.processor - implementation "com.squareup.okhttp3:okhttp:${OK_HTTP_VERSION}" - implementation 'com.squareup.retrofit2:retrofit:2.3.0' - implementation 'com.squareup.retrofit2:converter-gson:2.3.0' - implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0' + implementation libs.okhttp3 + implementation libs.retrofit + implementation libs.retrofit.gson + implementation libs.retrofit.rxjava - implementation 'io.reactivex:rxandroid:1.2.1' - implementation 'io.reactivex:rxjava:1.3.4' + implementation libs.rx.android + implementation libs.rx.java - implementation "androidx.appcompat:appcompat:${ANDROID_X_APPCOMPAT_VERSION}" - implementation "androidx.cardview:cardview:${ANDROID_X_CARDVIEW_VERSION}" - implementation "androidx.recyclerview:recyclerview:${ANDROID_X_RECYCLERVIEW_VERSION}" + implementation libs.androidx.appcompat + implementation libs.androidx.cardview + implementation libs.androidx.recyclerview // Fixes a compilation warning related to dagger, see // https://github.com/google/guava/issues/2721. - compileOnly "com.google.errorprone:error_prone_annotations:${ERROR_PRONE_VERSION}" + compileOnly libs.errorprone.annotations } task run(type: Exec, dependsOn: 'installDebug') { diff --git a/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplication.java b/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplication.java index bbb5f58985..fba6537b2f 100644 --- a/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplication.java +++ b/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplication.java @@ -1,7 +1,7 @@ package com.bumptech.glide.samples.imgur; import dagger.android.AndroidInjector; -import dagger.android.support.DaggerApplication; +import dagger.android.DaggerApplication; /** Runs Dagger injection in the Imgur sample. */ public final class ImgurApplication extends DaggerApplication { diff --git a/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplicationComponent.java b/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplicationComponent.java index 67b46f6df5..366e9f1043 100644 --- a/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplicationComponent.java +++ b/samples/imgur/src/main/java/com/bumptech/glide/samples/imgur/ImgurApplicationComponent.java @@ -3,14 +3,14 @@ import com.bumptech.glide.samples.imgur.api.ApiModule; import dagger.Component; import dagger.android.AndroidInjector; -import dagger.android.support.AndroidSupportInjectionModule; +import dagger.android.AndroidInjectionModule; import javax.inject.Singleton; /** Specifies Dagger modules for {@link ImgurApplication}. */ @Singleton @Component( modules = { - AndroidSupportInjectionModule.class, + AndroidInjectionModule.class, MainActivityModule.class, ApplicationModule.class, ApiModule.class diff --git a/samples/svg/build.gradle b/samples/svg/build.gradle index 0bf05d57c7..41a9d5738e 100644 --- a/samples/svg/build.gradle +++ b/samples/svg/build.gradle @@ -3,17 +3,17 @@ apply plugin: 'com.android.application' dependencies { implementation project(':library') annotationProcessor project(':annotation:compiler') - implementation 'com.caverock:androidsvg:1.2.1' - implementation "androidx.fragment:fragment:${ANDROID_X_FRAGMENT_VERSION}" + implementation libs.svg + implementation libs.androidx.fragment } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { applicationId 'com.bumptech.glide.samples.svg' - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionCode 1 versionName '1.0' diff --git a/scripts/ci_unit.sh b/scripts/ci_unit.sh index be89e89f99..4f55ab1062 100755 --- a/scripts/ci_unit.sh +++ b/scripts/ci_unit.sh @@ -2,15 +2,35 @@ set -e -# TODO(judds): Remove the KSP tests when support is available to run them in -# Google3 ./gradlew build \ - -x :samples:flickr:build \ - -x :samples:giphy:build \ - -x :samples:contacturi:build \ - -x :samples:gallery:build \ - -x :samples:imgur:build \ - -x :samples:svg:build \ + -x :library:test:testDebugUnitTest \ + :library:test:assembleDebugUnitTest \ + -x :library:testDebugUnitTest \ + :library:assembleDebugUnitTest \ + -x :annotation:ksp:test:testDebugUnitTest \ + :annotation:ksp:test:assembleDebugUnitTest \ + -x :third_party:disklrucache:testDebugUnitTest \ + :third_party:disklrucache:assembleDebugUnitTest \ + -x :integration:cronet:testDebugUnitTest \ + :integration:cronet:assembleDebugUnitTest \ + -x :integration:gifencoder:testDebugUnitTest \ + :integration:gifencoder:assembleDebugUnitTest \ + -x :integration:ktx:testDebugUnitTest \ + :integration:ktx:assembleDebugUnitTest \ + -x :integration:concurrent:testDebugUnitTest \ + :integration:concurrent:assembleDebugUnitTest \ + -x :integration:volley:testDebugUnitTest \ + :integration:volley:assembleDebugUnitTest \ + -x :integration:sqljournaldiskcache:testDebugUnitTest \ + :integration:sqljournaldiskcache:assembleDebugUnitTest \ + -x :third_party:gif_decoder:testDebugUnitTest \ + :third_party:gif_decoder:assembleDebugUnitTest \ + :samples:flickr:build \ + :samples:giphy:build \ + :samples:contacturi:build \ + :samples:gallery:build \ + :samples:imgur:build \ + :samples:svg:build \ :instrumentation:assembleAndroidTest \ :benchmark:assembleAndroidTest \ :glide:releaseJavadoc \ diff --git a/settings.gradle b/settings.gradle index c4fe9a6083..f3855c65bc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -39,3 +39,116 @@ include ':testutil' include ':mocks' rootProject.name = 'glide-parent' + +dependencyResolutionManagement { + // versionCatalogs end up in the global namespace and we can't nest namespaces, so we end up + // stuffing everything into libs :/. + versionCatalogs { + libs { + // Versions for things other than dependencies + version('compile-sdk-version', 'android-33') + version('min-sdk-version', '14') + version('okhttp-min-sdk-version', '21') + version('target-sdk-version', '32') + version('pmd', '6.0.0') + version('kotlin-compiler-extension', '1.2.0') + + // Versions for dependencies + version('compose', '1.4.3') + version('coroutines', '1.7.2') + version('dagger', '2.46.1') + version('errorprone', '2.18.0') + version('kotlin', '1.7.0') + version('mockito', '5.3.1') + version('retrofit', '2.3.0') + version('androidx-benchmark', '1.1.1') + version('androidx-espresso', '3.5.1') + // At least versions 1.5 and later require java 8 desugaring, which Glide can't + // currently use, so we're stuck on an older version. + version('androidx-fragment', '1.3.6') + version('ksp', '1.7.0-1.0.6') + + library('androidx-multidex', "androidx.multidex:multidex:2.0.1") + library('autoservice', 'com.google.auto.service:auto-service:1.0-rc3') + library('autoservice.annotations', 'com.google.auto.service:auto-service-annotations:1.0.1') + library('android-gradle', 'com.android.tools.build:gradle:7.3.0') + library('androidx-cardview', 'androidx.cardview:cardview:1.0.0') + library('androidx-core', 'androidx.core:core:1.6.0') + // 1.6.0 seems to introduce: + // The dependency contains Java 8 bytecode. Please enable desugaring by adding the following to build.gradle + // in the samples. + library('androidx-annotation', 'androidx.annotation:annotation:1.5.0') + // 1.4+ requires java8. + library('androidx-appcompat', 'androidx.appcompat:appcompat:1.3.1') + library('androidx-benchmark.gradle', 'androidx.benchmark', 'benchmark-gradle-plugin').versionRef('androidx-benchmark') + library('androidx-benchmark.junit', 'androidx.benchmark', 'benchmark-junit4').versionRef('androidx-benchmark') + library('androidx-core.ktx', 'androidx.core:core-ktx:1.8.0') + library('androidx-espresso', 'androidx.test.espresso', 'espresso-core').versionRef('androidx-espresso') + library('androidx-espresso.idling', 'androidx.test.espresso.idling', 'idling-concurrent').versionRef('androidx-espresso') + library('androidx-exifinterface', 'androidx.exifinterface:exifinterface:1.3.6') + library('androidx-fragment', 'androidx.fragment', 'fragment').versionRef('androidx-fragment') + library('androidx-fragment.ktx', 'androidx.fragment', 'fragment-ktx').versionRef('androidx-fragment') + library('androidx-futures', 'androidx.concurrent:concurrent-futures:1.1.0') + library('androidx-junit', 'androidx.test.ext:junit:1.1.5') + library('androidx-recyclerview','androidx.recyclerview:recyclerview:1.2.1') + library('androidx-test.core', 'androidx.test:core:1.4.0') + library('androidx-test.ktx', 'androidx.test:core-ktx:1.4.0') + library('androidx-test.ktx.junit', 'androidx.test.ext:junit-ktx:1.1.5') + library('androidx-test.rules', 'androidx.test:rules:1.4.0') + library('androidx-test.runner', 'androidx.test:runner:1.4.0') + library('androidx-tracing', 'androidx.tracing:tracing:1.0.0') + library('androidx.vectordrawable', 'androidx.vectordrawable:vectordrawable-animated:1.1.0') + library('proguard-gradle', 'com.guardsquare:proguard-gradle:7.1.0') + library('compose-foundation', 'androidx.compose.foundation:foundation:1.3.1') + library('compose-material', 'androidx.compose.material:material:1.3.1') + library('compose-ui', 'androidx.compose.ui', 'ui').versionRef('compose') + library('compose-ui.testmanifest', 'androidx.compose.ui', 'ui-test-manifest').versionRef('compose') + library('compose-ui.testjunit4', 'androidx.compose.ui', 'ui-test-junit4').versionRef('compose') + library('coroutines-binarycompat.gradle', 'org.jetbrains.kotlinx:binary-compatibility-validator:0.11.0') + library('coroutines-android', 'org.jetbrains.kotlinx', 'kotlinx-coroutines-android').versionRef('coroutines') + library('coroutines-core', 'org.jetbrains.kotlinx', 'kotlinx-coroutines-core').versionRef('coroutines') + library('coroutines-test', 'org.jetbrains.kotlinx', 'kotlinx-coroutines-test').versionRef('coroutines') + library('cronet', 'com.google.android.gms:play-services-cronet:17.0.0') + library('dagger', 'com.google.dagger', 'dagger').versionRef('dagger') + library('dagger-compiler', 'com.google.dagger', 'dagger-compiler').versionRef('dagger') + library('dagger-android', 'com.google.dagger', 'dagger-android').versionRef('dagger') + library('dagger-android.support', 'com.google.dagger', 'dagger-android-support').versionRef('dagger') + library('dagger-android.processor', 'com.google.dagger', 'dagger-android-processor').versionRef('dagger') + library('dokka-gradle', 'org.jetbrains.dokka:dokka-gradle-plugin:1.7.10') + library('drawablepainter', 'com.google.accompanist:accompanist-drawablepainter:0.25.1') + library('errorprone-annotations', 'com.google.errorprone', 'error_prone_annotations').versionRef('errorprone') + library('errorprone-core', 'com.google.errorprone', 'error_prone_core').versionRef('errorprone') + library('errorprone-gradle', 'net.ltgt.gradle:gradle-errorprone-plugin:2.0.2') + library('findbugs-jsr305', 'com.google.code.findbugs:jsr305:3.0.2') + library('guava', 'com.google.guava:guava:28.1-android') + library('guava-testlib', 'com.google.guava:guava-testlib:18.0') + library('javapoet', 'com.squareup:javapoet:1.9.0') + library('junit', 'junit:junit:4.13.2') + library('kotlin-junit', 'org.jetbrains.kotlin', 'kotlin-test-junit').versionRef('kotlin') + library('kotlin-jdk7', 'org.jetbrains.kotlin', 'kotlin-stdlib-jdk7').versionRef('kotlin') + library('kotlin-gradle', 'org.jetbrains.kotlin', 'kotlin-gradle-plugin').versionRef('kotlin') + library('kotlin-test', 'org.jetbrains.kotlin:kotlin-test:1.7.0') + library('kotlinpoet', 'com.squareup:kotlinpoet:1.12.0') + library('ksp', 'com.google.devtools.ksp', 'symbol-processing-api').versionRef('ksp') + library('ksp-autoservice', 'dev.zacsweers.autoservice:auto-service-ksp:1.0.0') + library('ksp-compiletesting', 'com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.9') + library('ksp-gradle', 'com.google.devtools.ksp', 'com.google.devtools.ksp.gradle.plugin').versionRef('ksp') + library('mockwebserver', 'com.squareup.okhttp3:mockwebserver:3.0.0-RC1') + library('mockito', 'org.mockito', 'mockito-core').versionRef('mockito') + library('mockito-android', 'org.mockito', 'mockito-android').versionRef('mockito') + library('okhttp2', 'com.squareup.okhttp:okhttp:2.7.5') + library('okhttp3', 'com.squareup.okhttp3:okhttp:3.10.0') + library('okhttp4', 'com.squareup.okhttp3:okhttp:4.10.0') + library('retrofit', 'com.squareup.retrofit2', 'retrofit').versionRef('retrofit') + library('retrofit-gson', 'com.squareup.retrofit2', 'converter-gson').versionRef('retrofit') + library('retrofit-rxjava', 'com.squareup.retrofit2', 'adapter-rxjava').versionRef('retrofit') + library('robolectric', 'org.robolectric:robolectric:4.8.1') + library('rx-android', 'io.reactivex:rxandroid:1.2.1') + library('rx-java', 'io.reactivex:rxjava:1.3.4') + library('svg', 'com.caverock:androidsvg:1.2.1') + library('truth', 'com.google.truth:truth:1.1.3') + library('violations', 'se.bjurr.violations:violations-gradle-plugin:1.8') + library('volley', 'com.android.volley:volley:1.2.0') + } + } +} diff --git a/testutil/build.gradle b/testutil/build.gradle index e570898dc1..8cb2dcebb9 100644 --- a/testutil/build.gradle +++ b/testutil/build.gradle @@ -1,19 +1,19 @@ apply plugin: 'com.android.library' dependencies { - implementation "com.google.truth:truth:${TRUTH_VERSION}" + implementation libs.truth implementation project(":library") - api "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" - api "androidx.core:core:${ANDROID_X_CORE_VERSION}" - api "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" + api libs.androidx.annotation + api libs.androidx.core + api libs.androidx.test.core } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String } diff --git a/third_party/disklrucache/build.gradle b/third_party/disklrucache/build.gradle index 923f99b3f9..baeeb3066d 100644 --- a/third_party/disklrucache/build.gradle +++ b/third_party/disklrucache/build.gradle @@ -6,16 +6,16 @@ checkstyle { } dependencies { - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" + testImplementation libs.junit + testImplementation libs.truth } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int versionName VERSION_NAME as String consumerProguardFiles 'proguard-rules.txt' } diff --git a/third_party/gif_decoder/build.gradle b/third_party/gif_decoder/build.gradle index fc783c776a..c3a4c55e90 100644 --- a/third_party/gif_decoder/build.gradle +++ b/third_party/gif_decoder/build.gradle @@ -1,22 +1,22 @@ apply plugin: 'com.android.library' dependencies { - implementation "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" + implementation libs.androidx.annotation testImplementation project(':testutil') - testImplementation "androidx.annotation:annotation:${ANDROID_X_ANNOTATION_VERSION}" - testImplementation "com.google.truth:truth:${TRUTH_VERSION}" - testImplementation "junit:junit:${JUNIT_VERSION}" - testImplementation "org.mockito:mockito-core:${MOCKITO_VERSION}" - testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" + testImplementation libs.androidx.annotation + testImplementation libs.truth + testImplementation libs.junit + testImplementation libs.mockito + testImplementation libs.robolectric } android { - compileSdk COMPILE_SDK_VERSION as int + compileSdkVersion libs.versions.compile.sdk.version.get() defaultConfig { - minSdk MIN_SDK_VERSION as int - targetSdk TARGET_SDK_VERSION as int + minSdk libs.versions.min.sdk.version.get() as int + targetSdk libs.versions.target.sdk.version.get() as int } }