Unverified Commit 7301cde4 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge pull request #1611 from RocketChat/fix/HandlerContext-error

[FIX] Temporary workaround for HandlerContext error.
parents 54b6b4ca 031d6536
......@@ -16,7 +16,7 @@ import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.support.HasSupportFragmentInjector
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.launch
import javax.inject.Inject
......
......@@ -70,7 +70,7 @@ import chat.rocket.core.model.Command
import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
......
......@@ -17,7 +17,7 @@ import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.realtime.socket.model.State
import chat.rocket.core.internal.rest.spotlight
import chat.rocket.core.model.SpotlightResult
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.isActive
import kotlinx.coroutines.experimental.launch
......
......@@ -4,7 +4,6 @@ import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput
import android.widget.Toast
import chat.rocket.android.R
......@@ -12,7 +11,7 @@ import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.sendMessage
import dagger.android.AndroidInjection
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import java.util.*
......
......@@ -4,7 +4,7 @@ import android.os.Looper
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.launch
inline fun Fragment.ui(crossinline block: (activity: FragmentActivity) -> Unit): Job? {
......
......@@ -4,12 +4,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
import kotlin.coroutines.experimental.CoroutineContext
class TransformedLiveData<Source, Output>(
private val runContext: CoroutineContext = CommonPool,
private val source: LiveData<Source>,
......
......@@ -26,6 +26,8 @@ android {
}
dependencies {
implementation project(':util')
implementation libraries.androidKtx
implementation libraries.appCompat
implementation libraries.kotlin
......
......@@ -17,11 +17,10 @@ import chat.rocket.android.emoji.R
import kotlinx.android.synthetic.main.emoji_category_layout.view.*
import kotlinx.android.synthetic.main.emoji_row_item.view.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) : PagerAdapter() {
private val adapters = hashMapOf<EmojiCategory, EmojiAdapter>()
......
package chat.rocket.android.util.extension
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.util.temp.UI
import kotlinx.coroutines.experimental.CoroutineScope
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
/**
......
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
/**
* Workaround for https://github.com/Kotlin/kotlinx.coroutines/issues/367#issuecomment-414185769
*
* TODO: Remove after issue is resolved.
*/
package chat.rocket.android.util.temp
import android.os.Handler
import android.os.Looper
import android.view.Choreographer
import androidx.annotation.Keep
import kotlinx.coroutines.experimental.BlockingChecker
import kotlinx.coroutines.experimental.CancellableContinuation
import kotlinx.coroutines.experimental.CoroutineDispatcher
import kotlinx.coroutines.experimental.Delay
import kotlinx.coroutines.experimental.DisposableHandle
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
import java.util.concurrent.TimeUnit
import kotlin.coroutines.experimental.CoroutineContext
/**
* Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support.
*/
val UI = HandlerContext(Handler(Looper.getMainLooper()), "UI")
/**
* Represents an arbitrary [Handler] as a implementation of [CoroutineDispatcher].
*/
fun Handler.asCoroutineDispatcher() = HandlerContext(this)
private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android
/**
* Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler].
*/
public class HandlerContext private constructor(
private val handler: Handler,
private val name: String?,
private val invokeImmediately: Boolean
) : CoroutineDispatcher(), Delay {
/**
* Creates [CoroutineDispatcher] for the given Android [handler].
*
* @param handler a handler.
* @param name an optional name for debugging.
*/
public constructor(
handler: Handler,
name: String? = null
) : this(handler, name, false)
@Volatile
private var _immediate: HandlerContext? = if (invokeImmediately) this else null
/**
* Returns dispatcher that executes coroutines immediately when it is already in the right handler context
* (current looper is the same as [handler] looper). See [isDispatchNeeded] documentation on
* why this should not be done by default.
*/
public val immediate: HandlerContext = _immediate ?:
HandlerContext(handler, name, true).also { _immediate = it }
@Volatile
private var _choreographer: Choreographer? = null
override fun isDispatchNeeded(context: CoroutineContext): Boolean {
return !invokeImmediately || Looper.myLooper() != handler.looper
}
override fun dispatch(context: CoroutineContext, block: Runnable) {
handler.post(block)
}
override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
handler.postDelayed({
with(continuation) { resumeUndispatched(Unit) }
}, unit.toMillis(time).coerceAtMost(MAX_DELAY))
}
override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
handler.postDelayed(block, unit.toMillis(time).coerceAtMost(MAX_DELAY))
return object : DisposableHandle {
override fun dispose() {
handler.removeCallbacks(block)
}
}
}
/**
* Awaits the next animation frame and returns frame time in nanoseconds.
*/
public suspend fun awaitFrame(): Long {
// fast path when choreographer is already known
val choreographer = _choreographer
if (choreographer != null) {
return suspendCancellableCoroutine { cont ->
postFrameCallback(choreographer, cont)
}
}
// post into looper thread thread to figure it out
return suspendCancellableCoroutine { cont ->
handler.post {
updateChoreographerAndPostFrameCallback(cont)
}
}
}
private fun updateChoreographerAndPostFrameCallback(cont: CancellableContinuation<Long>) {
val choreographer = _choreographer ?:
Choreographer.getInstance()!!.also { _choreographer = it }
postFrameCallback(choreographer, cont)
}
private fun postFrameCallback(choreographer: Choreographer, cont: CancellableContinuation<Long>) {
choreographer.postFrameCallback { nanos ->
with(cont) { resumeUndispatched(nanos) }
}
}
override fun toString() = name ?: handler.toString()
override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler
override fun hashCode(): Int = System.identityHashCode(handler)
}
/**
* @suppress This is an internal impl class.
*/
@Keep
class MainLooperChecker : BlockingChecker {
override fun checkRunBlocking() =
check(Looper.myLooper() != Looper.getMainLooper()) { "runBlocking is not allowed in Android main looper thread" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment