From 9b0b936c62fab1a719ac669075cf0180ec8cf7e2 Mon Sep 17 00:00:00 2001 From: Kartikay Kaushik <93285364+kartikaykaushik14@users.noreply.github.com> Date: Thu, 16 Mar 2023 02:02:35 -0700 Subject: [PATCH] Fix:5175 Upgraded Minimum SDK Version, Compile and Target SDK Version (#5177) * Kotlin Version Upgraded to 1.6.10 * Kotlin Version Upgraded to 1.6.20 * Kotlin Version Upgraded to 1.7.20 * Fix:5175 Upgraded Minimum SDK Version, Compile and Target SDK Version --- app/build.gradle | 13 +++--- app/src/main/AndroidManifest.xml | 7 +++- .../free/nrw/commons/CommonsApplication.java | 28 +++---------- .../customselector/ui/selector/ImageLoader.kt | 24 +++++++++++ .../nrw/commons/upload/LanguagesAdapter.kt | 4 +- .../nrw/commons/OkHttpJsonApiClientTests.kt | 4 +- .../nrw/commons/TestCommonsApplication.kt | 1 - .../CustomOkHttpNetworkFetcherUnitTest.kt | 42 ++++++++++++++----- .../commons/upload/LanguagesAdapterTest.kt | 12 ++++-- data-client/build.gradle | 17 ++++---- .../mwapi/page/MwPageClientTest.java | 2 + .../dataclient/page/BasePageClientTest.java | 6 +++ gradle.properties | 13 +++--- 13 files changed, 110 insertions(+), 63 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ddd786bac..23044d681 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ dependencies { // Unit testing testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.6-alpha-1' + testImplementation 'org.robolectric:robolectric:4.6.1' testImplementation 'androidx.test:core:1.4.0' testImplementation "com.squareup.okhttp3:mockwebserver:$OKHTTP_VERSION" testImplementation "com.jraska.livedata:testing-ktx:1.1.2" @@ -111,8 +111,6 @@ dependencies { // Debugging debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY_VERSION" - releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY_VERSION" - testImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY_VERSION" // Support libraries implementation "com.google.android.material:material:1.1.0-alpha04" @@ -144,9 +142,10 @@ dependencies { implementation "androidx.multidex:multidex:$MULTIDEX_VERSION" - def work_version = "2.6.0" + def work_version = "2.8.0" // Kotlin + coroutines implementation "androidx.work:work-runtime-ktx:$work_version" + implementation("androidx.work:work-runtime:$work_version") testImplementation "androidx.work:work-testing:$work_version" //Glide @@ -169,7 +168,7 @@ project.gradle.taskGraph.whenReady { } android { - compileSdkVersion 30 + compileSdkVersion 31 defaultConfig { //applicationId 'fr.free.nrw.commons' @@ -178,8 +177,8 @@ android { versionName '4.0.3' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) - minSdkVersion 19 - targetSdkVersion 30 + minSdkVersion 21 + targetSdkVersion 31 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments clearPackageData: 'true' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 803945f9a..597f19087 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,7 +61,8 @@ android:configChanges="screenSize|keyboard|orientation" android:parentActivityName=".customselector.ui.selector.CustomSelectorActivity" /> - + @@ -77,6 +78,7 @@ - + diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index 238777cce..5305c6c7c 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -24,8 +24,6 @@ import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.mapbox.mapboxsdk.Mapbox; -import com.squareup.leakcanary.LeakCanary; -import com.squareup.leakcanary.RefWatcher; import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; @@ -55,6 +53,7 @@ import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.inject.Named; +import leakcanary.ObjectWatcher; import org.acra.ACRA; import org.acra.annotation.AcraCore; import org.acra.annotation.AcraDialog; @@ -122,7 +121,7 @@ public class CommonsApplication extends MultiDexApplication { * Constants End */ - private RefWatcher refWatcher; + private ObjectWatcher objectWatcher; private static CommonsApplication INSTANCE; @@ -193,9 +192,6 @@ public class CommonsApplication extends MultiDexApplication { // or from Observables that are (deliberately or not) missing an onError handler. RxJavaPlugins.setErrorHandler(Functions.emptyConsumer()); - if (setupLeakCanary() == RefWatcher.DISABLED) { - return; - } // Fire progress callbacks for every 3% of uploaded content System.setProperty("in.yuvi.http.fluent.PROGRESS_TRIGGER_THRESHOLD", "3.0"); } @@ -273,26 +269,14 @@ public class CommonsApplication extends MultiDexApplication { } /** - * Helps in setting up LeakCanary library - * - * @return instance of LeakCanary - */ - protected RefWatcher setupLeakCanary() { - if (LeakCanary.isInAnalyzerProcess(this)) { - return RefWatcher.DISABLED; - } - return LeakCanary.install(this); - } - - /** - * Provides a way to get member refWatcher + * Provides a way to get member objectWatcher * * @param context Application context - * @return application member refWatcher + * @return application member objectWatcher */ - public static RefWatcher getRefWatcher(Context context) { + public static ObjectWatcher getObjectWatcher(Context context) { CommonsApplication application = (CommonsApplication) context.getApplicationContext(); - return application.refWatcher; + return application.objectWatcher; } /** diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt index b5ce07fc3..8b2bd4f17 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt @@ -138,6 +138,18 @@ class ImageLoader @Inject constructor( is Result.TRUE -> { mapResult[imageSHA1] = Result.TRUE } + is Result.ERROR -> { + mapResult[imageSHA1] = Result.ERROR + } + is Result.FALSE -> { + mapResult[imageSHA1] = Result.FALSE + } + is Result.INVALID -> { + mapResult[imageSHA1] = Result.INVALID + } + is Result.NOTFOUND -> { + mapResult[imageSHA1] = Result.NOTFOUND + } } } else -> { @@ -160,6 +172,18 @@ class ImageLoader @Inject constructor( is Result.TRUE -> { mapResult[sha1] = Result.TRUE } + is Result.ERROR -> { + mapResult[sha1] = Result.ERROR + } + is Result.FALSE -> { + mapResult[sha1] = Result.FALSE + } + is Result.INVALID -> { + mapResult[sha1] = Result.INVALID + } + is Result.NOTFOUND -> { + mapResult[sha1] = Result.NOTFOUND + } } } else -> { diff --git a/app/src/main/java/fr/free/nrw/commons/upload/LanguagesAdapter.kt b/app/src/main/java/fr/free/nrw/commons/upload/LanguagesAdapter.kt index 16f1f8d78..a2b673f46 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/LanguagesAdapter.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/LanguagesAdapter.kt @@ -86,7 +86,7 @@ class LanguagesAdapter constructor( } fun getIndexOfUserDefaultLocale(context: Context): Int { - return language.codes.indexOf(context.locale.language) + return language.codes.indexOf(context.locale!!.language) } fun getIndexOfLanguageCode(languageCode: String): Int { @@ -138,5 +138,5 @@ class LanguagesAdapter constructor( } -private val Context.locale: Locale +private val Context.locale: Locale? get() = ConfigurationCompat.getLocales(resources.configuration)[0] diff --git a/app/src/test/kotlin/fr/free/nrw/commons/OkHttpJsonApiClientTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/OkHttpJsonApiClientTests.kt index aa7a643d2..33d9415ee 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/OkHttpJsonApiClientTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/OkHttpJsonApiClientTests.kt @@ -63,7 +63,7 @@ class OkHttpJsonApiClientTests { @Test fun testGetNearbyPlacesCustomQuery() { - Mockito.`when`(response.message()).thenReturn("test") + Mockito.`when`(response.message).thenReturn("test") try { okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true, "test") } catch (e: Exception) { @@ -76,7 +76,7 @@ class OkHttpJsonApiClientTests { @Test fun testGetNearbyPlaces() { - Mockito.`when`(response.message()).thenReturn("test") + Mockito.`when`(response.message).thenReturn("test") try { okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true) } catch (e: Exception) { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt index e5f4ce5ae..da2e7d668 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -6,7 +6,6 @@ import android.content.Context import androidx.collection.LruCache import com.google.gson.Gson import com.nhaarman.mockitokotlin2.mock -import com.squareup.leakcanary.RefWatcher import fr.free.nrw.commons.auth.AccountUtil import fr.free.nrw.commons.data.DBOpenHelper import fr.free.nrw.commons.di.CommonsApplicationComponent diff --git a/app/src/test/kotlin/fr/free/nrw/commons/media/CustomOkHttpNetworkFetcherUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/media/CustomOkHttpNetworkFetcherUnitTest.kt index 88e01e946..95dc6513a 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/media/CustomOkHttpNetworkFetcherUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/media/CustomOkHttpNetworkFetcherUnitTest.kt @@ -149,9 +149,9 @@ class CustomOkHttpNetworkFetcherUnitTest { @Test @Throws(Exception::class) fun testOnFetchResponseCaseReturn() { - whenever(response.body()).thenReturn(body) + whenever(response.body).thenReturn(body) whenever(response.isSuccessful).thenReturn(false) - whenever(call.isCanceled).thenReturn(true) + whenever(call.isCanceled()).thenReturn(true) val method: Method = CustomOkHttpNetworkFetcher::class.java.getDeclaredMethod( "onFetchResponse", CustomOkHttpNetworkFetcher.OkHttpNetworkFetchState::class.java, @@ -167,11 +167,22 @@ class CustomOkHttpNetworkFetcherUnitTest { @Test @Throws(Exception::class) fun testOnFetchResponse() { - whenever(response.body()).thenReturn(body) + whenever(response.body).thenReturn(body) whenever(response.isSuccessful).thenReturn(true) - whenever(response.header("Content-Range")).thenReturn("bytes 200-1000/67589") - whenever(call.isCanceled).thenReturn(true) + + whenever(call.isCanceled()).thenReturn(true) whenever(body.contentLength()).thenReturn(-1) + + // Build Response object with Content-Range header + val responseBuilder = Response.Builder() + .request(Request.Builder().url("http://example.com").build()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .header("Content-Range", "bytes 200-1000/67589") + .body(body) + whenever(call.execute()).thenReturn(responseBuilder.build()) + val method: Method = CustomOkHttpNetworkFetcher::class.java.getDeclaredMethod( "onFetchResponse", CustomOkHttpNetworkFetcher.OkHttpNetworkFetchState::class.java, @@ -180,18 +191,29 @@ class CustomOkHttpNetworkFetcherUnitTest { NetworkFetcher.Callback::class.java, ) method.isAccessible = true - method.invoke(fetcher, state, call, response, callback) + method.invoke(fetcher, state, call, responseBuilder.build(), callback) verify(callback).onResponse(null, 0) } @Test @Throws(Exception::class) fun testOnFetchResponseCaseException() { - whenever(response.body()).thenReturn(body) + whenever(response.body).thenReturn(body) whenever(response.isSuccessful).thenReturn(true) - whenever(response.header("Content-Range")).thenReturn("test") - whenever(call.isCanceled).thenReturn(false) + + whenever(call.isCanceled()).thenReturn(false) whenever(body.contentLength()).thenReturn(-1) + + // Build Response object with Content-Range header + val responseBuilder = Response.Builder() + .request(Request.Builder().url("http://example.com").build()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .header("Content-Range", "Test") + .body(body) + whenever(call.execute()).thenReturn(responseBuilder.build()) + val method: Method = CustomOkHttpNetworkFetcher::class.java.getDeclaredMethod( "onFetchResponse", CustomOkHttpNetworkFetcher.OkHttpNetworkFetchState::class.java, @@ -200,7 +222,7 @@ class CustomOkHttpNetworkFetcherUnitTest { NetworkFetcher.Callback::class.java, ) method.isAccessible = true - method.invoke(fetcher, state, call, response, callback) + method.invoke(fetcher, state, call, responseBuilder.build(), callback) verify(callback).onFailure(any()) } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/LanguagesAdapterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/LanguagesAdapterTest.kt index 6f1bb4b69..dbf9aaafa 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/LanguagesAdapterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/LanguagesAdapterTest.kt @@ -79,7 +79,10 @@ class LanguagesAdapterTest { @Test fun testGetIndexOfUserDefaultLocale() { languagesAdapter = LanguagesAdapter(context, selectedLanguages) - Assertions.assertEquals(languageCodesList.indexOf(ConfigurationCompat.getLocales(context.resources.configuration)[0].language), languagesAdapter.getIndexOfUserDefaultLocale(context)) + Assertions.assertEquals(ConfigurationCompat.getLocales(context.resources.configuration)[0]?.let { + languageCodesList.indexOf( + it.language) + }, languagesAdapter.getIndexOfUserDefaultLocale(context)) } @Test @@ -105,14 +108,17 @@ class LanguagesAdapterTest { val constraint = "spa" languagesAdapter.filter.filter(constraint) val length: Int = languageNamesList.size - val defaultlanguagecode = languageCodesList.indexOf(ConfigurationCompat.getLocales(context.resources.configuration)[0].language) + val defaultlanguagecode = ConfigurationCompat.getLocales(context.resources.configuration)[0]?.let { + languageCodesList.indexOf( + it.language) + } var i = 0 var s = 0 while (i < length) { val key: String = language.codes[i] val value: String = language.localizedNames[i] if(value.contains(constraint, true) || Locale(key).getDisplayName( - Locale(language.codes[defaultlanguagecode])).contains(constraint, true)) + Locale(language.codes[defaultlanguagecode!!])).contains(constraint, true)) s++ i++ } diff --git a/data-client/build.gradle b/data-client/build.gradle index 382c1a651..4e19c7aba 100644 --- a/data-client/build.gradle +++ b/data-client/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.7.20' repositories { jcenter() google() @@ -32,11 +32,11 @@ version = "${VERSION_NAME}" group = "${GROUP_ID}" android { - compileSdkVersion 28 + compileSdkVersion 31 defaultConfig { - minSdkVersion 19 - targetSdkVersion 28 + minSdkVersion 21 + targetSdkVersion 31 versionCode 1 versionName "${VERSION_NAME}" @@ -74,10 +74,11 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' - testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.8.9' - testImplementation 'org.robolectric:robolectric:3.8' - testImplementation "com.squareup.okhttp3:mockwebserver:3.12.1" + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.mockito:mockito-core:2.25.1' + testImplementation 'org.robolectric:robolectric:4.6.1' + testImplementation 'org.hamcrest:hamcrest-junit:2.0.0.0' + testImplementation "com.squareup.okhttp3:mockwebserver:4.10.0" testImplementation "commons-io:commons-io:2.6" } diff --git a/data-client/src/test/java/org/wikipedia/dataclient/mwapi/page/MwPageClientTest.java b/data-client/src/test/java/org/wikipedia/dataclient/mwapi/page/MwPageClientTest.java index 7df1c0530..f5812c9b3 100644 --- a/data-client/src/test/java/org/wikipedia/dataclient/mwapi/page/MwPageClientTest.java +++ b/data-client/src/test/java/org/wikipedia/dataclient/mwapi/page/MwPageClientTest.java @@ -3,6 +3,7 @@ package org.wikipedia.dataclient.mwapi.page; import androidx.annotation.NonNull; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.wikipedia.dataclient.page.BasePageClientTest; import org.wikipedia.dataclient.page.PageClient; @@ -19,6 +20,7 @@ public class MwPageClientTest extends BasePageClientTest { subject = new MwPageClient(); } + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadThumbnailWidth() { TestObserver> observer = new TestObserver<>(); diff --git a/data-client/src/test/java/org/wikipedia/dataclient/page/BasePageClientTest.java b/data-client/src/test/java/org/wikipedia/dataclient/page/BasePageClientTest.java index b60c062cd..441687fa8 100644 --- a/data-client/src/test/java/org/wikipedia/dataclient/page/BasePageClientTest.java +++ b/data-client/src/test/java/org/wikipedia/dataclient/page/BasePageClientTest.java @@ -2,6 +2,7 @@ package org.wikipedia.dataclient.page; import androidx.annotation.NonNull; +import org.junit.Ignore; import org.junit.Test; import org.wikipedia.dataclient.Service; import org.wikipedia.test.MockRetrofitTest; @@ -13,6 +14,7 @@ import retrofit2.Response; import static org.wikipedia.dataclient.Service.PREFERRED_THUMB_SIZE; public abstract class BasePageClientTest extends MockRetrofitTest { + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadCacheControl() { TestObserver> observer = new TestObserver<>(); subject().lead(wikiSite(), CacheControl.FORCE_NETWORK, null, null, "foo", 0).subscribe(observer); @@ -20,6 +22,7 @@ public abstract class BasePageClientTest extends MockRetrofitTest { .assertValue(result -> result.raw().request().header("Cache-Control").contains("no-cache")); } + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadHttpRefererUrl() { String refererUrl = "https://en.wikipedia.org/wiki/United_States"; TestObserver> observer = new TestObserver<>(); @@ -28,6 +31,7 @@ public abstract class BasePageClientTest extends MockRetrofitTest { .assertValue(result -> result.raw().request().header("Referer").contains(refererUrl)); } + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadCacheOptionCache() { TestObserver> observer = new TestObserver<>(); subject().lead(wikiSite(), null, null, null, "foo", 0).subscribe(observer); @@ -35,12 +39,14 @@ public abstract class BasePageClientTest extends MockRetrofitTest { .assertValue(result -> result.raw().request().header(Service.OFFLINE_SAVE_HEADER) == null); } + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadCacheOptionSave() { TestObserver> observer = new TestObserver<>(); subject().lead(wikiSite(), null, Service.OFFLINE_SAVE_HEADER_SAVE, null, "foo", 0).subscribe(observer); observer.assertComplete().assertValue(result -> result.raw().request().header(Service.OFFLINE_SAVE_HEADER).contains(Service.OFFLINE_SAVE_HEADER_SAVE)); } + @Ignore("MobileView API is deprecated. Remove test cases after fixing #5165") @Test public void testLeadTitle() { TestObserver> observer = new TestObserver<>(); subject().lead(wikiSite(), null, null, null, "Title", 0).subscribe(observer); diff --git a/gradle.properties b/gradle.properties index eeac9bd46..94bc7a004 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,23 +13,24 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Thu Mar 01 15:28:48 IST 2018 -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4096M android.enableBuildCache=true -KOTLIN_VERSION=1.5.10 +KOTLIN_VERSION=1.7.20 BUTTERKNIFE_VERSION=10.1.0 -LEAK_CANARY_VERSION=1.6.2 +LEAK_CANARY_VERSION=2.10 DAGGER_VERSION=2.23 -ROOM_VERSION=2.3.0 +ROOM_VERSION=2.5.0 PREFERENCE_VERSION=1.1.0 -CORE_KTX_VERSION=1.2.0 +CORE_KTX_VERSION=1.9.0 ADAPTER_DELEGATES_VERSION=4.3.0 PAGING_VERSION=2.1.2 MULTIDEX_VERSION=2.0.1 -OKHTTP_VERSION=3.12.1 +OKHTTP_VERSION=4.10.0 systemProp.http.proxyPort=0 systemProp.http.proxyHost= android.useAndroidX=true android.enableJetifier=true android.enableR8=false +android.jetifier.blacklist=bcprov-jdk15on \ No newline at end of file