Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ jdk_toolchain_version=11
animalsniffer_version=2.0.0

# Android versions
android_version=4.1.1.4
android_for_testing_version=4.1.1.4
# We're using a non-default Android artifact for building.
# See https://github.com/Kotlin/kotlinx.coroutines/issues/4158#issuecomment-2758057691
android_via_robolectric_version=9-robolectric-4799589
androidx_annotation_version=1.1.0
robolectric_version=4.9
baksmali_version=2.2.7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ project.configureAar()
dependencies {
configureAarUnpacking()

testImplementation("com.google.android:android:${version("android")}")
testImplementation("com.google.android:android:${version("android_for_testing")}")
testImplementation("org.robolectric:robolectric:${version("robolectric")}")
// Required by robolectric
testImplementation("androidx.test:core:1.2.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
import org.junit.Test
import org.junit.runner.*
import android.os.Looper
import org.robolectric.*
import org.robolectric.annotation.*
import org.robolectric.shadows.*
Expand Down Expand Up @@ -43,7 +44,7 @@ class CustomizedRobolectricTest : TestBase() {


private fun checkComponent(component: TestComponent) {
val mainLooper = ShadowLooper.getShadowMainLooper()
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
mainLooper.pause()
component.launchSomething()
assertFalse(component.launchCompleted)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
import org.junit.Test
import org.junit.runner.*
import android.os.Looper
import org.robolectric.*
import org.robolectric.annotation.*
import org.robolectric.shadows.*
Expand Down Expand Up @@ -32,7 +33,7 @@ open class FirstRobolectricTest {
@Test
fun testDelay() {
val component = TestComponent()
val mainLooper = ShadowLooper.getShadowMainLooper()
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
mainLooper.pause()
component.launchDelayed()
mainLooper.runToNextTask()
Expand All @@ -42,7 +43,7 @@ open class FirstRobolectricTest {
}

private fun checkComponent(component: TestComponent) {
val mainLooper = ShadowLooper.getShadowMainLooper()
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
mainLooper.pause()
component.launchSomething()
assertFalse(component.launchCompleted)
Expand Down
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ project.configureAar()
dependencies {
configureAarUnpacking()

compileOnly("com.google.android:android:${version("android")}")
compileOnly("org.robolectric:android-all:${version("android_via_robolectric")}")
compileOnly("androidx.annotation:annotation:${version("androidx_annotation")}")

testImplementation("com.google.android:android:${version("android")}")
testImplementation("com.google.android:android:${version("android_for_testing")}")
testImplementation("org.robolectric:robolectric:${version("robolectric")}")
// Required by robolectric
testImplementation("androidx.test:core:1.2.0")
Expand Down
26 changes: 7 additions & 19 deletions ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import android.view.*
import androidx.annotation.*
import kotlinx.coroutines.*
import kotlinx.coroutines.internal.*
import java.lang.reflect.*
import kotlin.coroutines.*

/**
Expand Down Expand Up @@ -77,27 +76,16 @@ public fun Handler.asCoroutineDispatcher(name: String? = null): HandlerDispatche
private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android

@VisibleForTesting
internal fun Looper.asHandler(async: Boolean): Handler {
internal fun Looper.asHandler(async: Boolean): Handler = when {
// Async support was added in API 16.
if (!async || Build.VERSION.SDK_INT < 16) {
return Handler(this)
}

if (Build.VERSION.SDK_INT >= 28) {
// TODO compile against API 28 so this can be invoked without reflection.
val factoryMethod = Handler::class.java.getDeclaredMethod("createAsync", Looper::class.java)
return factoryMethod.invoke(null, this) as Handler
}

val constructor: Constructor<Handler>
try {
constructor = Handler::class.java.getDeclaredConstructor(Looper::class.java,
Handler.Callback::class.java, Boolean::class.javaPrimitiveType)
} catch (ignored: NoSuchMethodException) {
!async || Build.VERSION.SDK_INT < 16 -> Handler(this)
Build.VERSION.SDK_INT >= 28 -> Handler.createAsync(this)
else -> try {
Handler(this, null, true)
} catch (ignored: NoSuchMethodError) {
// Hidden constructor absent. Fall back to non-async constructor.
return Handler(this)
Handler(this)
}
return constructor.newInstance(this, null, true)
}

@JvmField
Expand Down
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-android/test/HandlerDispatcherTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class HandlerDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
}

private fun CoroutineScope.doTestAwaitFrame() {
ShadowChoreographer.setPostFrameCallbackDelay(100)
ShadowLegacyChoreographer.setPostFrameCallbackDelay(100)
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
mainLooper.pause()
launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
Expand All @@ -96,7 +96,7 @@ class HandlerDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
}

private fun CoroutineScope.doTestAwaitWithDetectedChoreographer() {
ShadowChoreographer.setPostFrameCallbackDelay(100)
ShadowLegacyChoreographer.setPostFrameCallbackDelay(100)
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
expect(1)
Expand Down