Repository: Kotlin/kotlinx.coroutines
File: ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt (Kotlin)

Code before:
     *   }
     *   // Do context-independent logic such as logging
     * }
     * ```
     */
    public abstract override val immediate: HandlerDispatcher
}

internal class AndroidDispatcherFactory : MainDispatcherFactory {

    override fun createDispatcher(allFactories: List<MainDispatcherFactory>) =
        HandlerContext(Looper.getMainLooper().asHandler(async = true))

    override fun hintOnError(): String = "For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used"

    override val loadPriority: Int
        get() = Int.MAX_VALUE / 2
}

/**
 * Represents an arbitrary [Handler] as an implementation of [CoroutineDispatcher]
 * with an optional [name] for nicer debugging
 *
 * ## Rejected execution
 *
 * If the underlying handler is closed and its post-related methods start to return `false` on
 * an attempt to submit a continuation task to the resulting dispatcher,
 * then the [Job] of the affected task is [cancelled][Job.cancel] and the task is submitted to the
 * [Dispatchers.IO], so that the affected coroutine can cleanup its resources and promptly complete.
 */
@JvmName("from") // this is for a nice Java API, see issue #255
@JvmOverloads
public fun Handler.asCoroutineDispatcher(name: String? = null): HandlerDispatcher =
    HandlerContext(this, name)

private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android

@VisibleForTesting
internal fun Looper.asHandler(async: Boolean): Handler {
    // 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>

Review comment (suggestion):
> post-related methods

I think this could be worded better, as I had to look this up to understand what's being said. For example, there are also `send*` methods that return `false` in the same scenarios as `post*`. [The docs](https://developer.android.com/reference/android/os/Handler) call this "scheduling messages", so I propose

> methods that schedule messages

Code after:
     *   }
     *   // Do context-independent logic such as logging
     * }
     * ```
     */
    public abstract override val immediate: HandlerDispatcher
}

internal class AndroidDispatcherFactory : MainDispatcherFactory {

    override fun createDispatcher(allFactories: List<MainDispatcherFactory>) =
        HandlerContext(Looper.getMainLooper().asHandler(async = true))

    override fun hintOnError(): String = "For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used"

    override val loadPriority: Int
        get() = Int.MAX_VALUE / 2
}

/**
 * Represents an arbitrary [Handler] as an implementation of [CoroutineDispatcher]
 * with an optional [name] for nicer debugging
 *
 * ## Rejected execution
 *
 * If the underlying handler is closed and its message-scheduling methods start to return `false` on
 * an attempt to submit a continuation task to the resulting dispatcher,
 * then the [Job] of the affected task is [cancelled][Job.cancel] and the task is submitted to the
 * [Dispatchers.IO], so that the affected coroutine can cleanup its resources and promptly complete.
 */
@JvmName("from") // this is for a nice Java API, see issue #255
@JvmOverloads
public fun Handler.asCoroutineDispatcher(name: String? = null): HandlerDispatcher =
    HandlerContext(this, name)

private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android

@VisibleForTesting
internal fun Looper.asHandler(async: Boolean): Handler {
    // 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>