Skip to content

Commit

Permalink
fix: refactor event dispatch logic on android to fix fabric crash (#1000
Browse files Browse the repository at this point in the history
)

* fix: refactor event dispatch on android to fix fabric crash

* chore: remove unused code
  • Loading branch information
AlexanderEggers committed Mar 26, 2023
1 parent b9ee943 commit ebb8006
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 81 deletions.
Expand Up @@ -2,7 +2,6 @@ package com.airbnb.android.react.lottie

import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.widget.ImageView
Expand All @@ -12,16 +11,15 @@ import com.airbnb.lottie.RenderMode
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.util.RNLog
import kotlinx.coroutines.*
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.URL
import kotlin.concurrent.thread

internal object LottieAnimationViewManagerImpl {
const val REACT_CLASS = "LottieAnimationView"
val coroutineScope = CoroutineScope(Dispatchers.Main)

@JvmStatic
val exportedViewConstants: Map<String, Any>
Expand All @@ -37,10 +35,23 @@ internal object LottieAnimationViewManagerImpl {
}

@JvmStatic
fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
fun sendOnAnimationFinishEvent(view: LottieAnimationView, isCancelled: Boolean) {
val screenContext = view.context as ThemedReactContext
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(screenContext, view.id)
eventDispatcher?.dispatchEvent(
OnAnimationFinishEvent(
screenContext.surfaceId,
view.id,
isCancelled
)
)
}

@JvmStatic
fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
return MapBuilder.of(
"animationFinish",
MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", "onAnimationFinish"))
OnAnimationFinishEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onAnimationFinish"),
)
}

Expand Down
Expand Up @@ -13,6 +13,6 @@ class LottiePackage : ReactPackage {
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return listOf(LottieAnimationViewManager(reactContext))
return listOf(LottieAnimationViewManager())
}
}
@@ -0,0 +1,26 @@
package com.airbnb.android.react.lottie

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.Event

class OnAnimationFinishEvent
constructor(surfaceId: Int, viewId: Int, private val isCancelled: Boolean) :
Event<OnAnimationFinishEvent>(surfaceId, viewId) {

override fun getEventName(): String {
return EVENT_NAME
}

override fun getCoalescingKey(): Short = 0

override fun getEventData(): WritableMap? {
val event = Arguments.createMap()
event.putBoolean("isCancelled", isCancelled)
return event
}

companion object {
const val EVENT_NAME = "topAnimationFinish"
}
}
@@ -1,7 +1,6 @@
package com.airbnb.android.react.lottie

import android.animation.Animator
import android.util.Log
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setColorFilters
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setEnableMergePaths
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setHardwareAcceleration
Expand All @@ -17,25 +16,19 @@ import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setSpeed
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setTextFilters
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setAutoPlay
import com.airbnb.lottie.LottieAnimationView
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.uimanager.events.Event
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.facebook.react.uimanager.events.RCTModernEventEmitter
import com.facebook.react.viewmanagers.LottieAnimationViewManagerDelegate
import com.facebook.react.viewmanagers.LottieAnimationViewManagerInterface
import java.util.*

@ReactModule(name = LottieAnimationViewManagerImpl.REACT_CLASS)
class LottieAnimationViewManager(val reactContext: ReactContext) :
class LottieAnimationViewManager :
SimpleViewManager<LottieAnimationView>(),
LottieAnimationViewManagerInterface<LottieAnimationView> {
private val propManagersMap =
Expand All @@ -55,22 +48,6 @@ class LottieAnimationViewManager(val reactContext: ReactContext) :
return result
}

private fun sendOnAnimationFinishEvent(view: LottieAnimationView, isCancelled: Boolean) {
val event = Arguments.createMap()
event.putBoolean("isCancelled", isCancelled)

val screenContext = view.context as ThemedReactContext

Log.d("Lottie", "view surface id ${screenContext.surfaceId} - view id ${view.id}")
reactContext.getJSModule(RCTModernEventEmitter::class.java)
?.receiveEvent(
screenContext.surfaceId,
view.id,
"animationFinish",
event
)
}

override fun getDelegate(): ViewManagerDelegate<LottieAnimationView> {
return delegate
}
Expand All @@ -91,13 +68,11 @@ class LottieAnimationViewManager(val reactContext: ReactContext) :
}

override fun onAnimationEnd(animation: Animator) {
// TODO: fix crash
// sendOnAnimationFinishEvent(view, false)
LottieAnimationViewManagerImpl.sendOnAnimationFinishEvent(view, false)
}

override fun onAnimationCancel(animation: Animator) {
// TODO: fix crash
// sendOnAnimationFinishEvent(view, true)
LottieAnimationViewManagerImpl.sendOnAnimationFinishEvent(view, true)
}

override fun onAnimationRepeat(animation: Animator) {
Expand All @@ -107,8 +82,8 @@ class LottieAnimationViewManager(val reactContext: ReactContext) :
return view
}

override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return LottieAnimationViewManagerImpl.getExportedCustomBubblingEventTypeConstants()
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any>? {
return LottieAnimationViewManagerImpl.getExportedCustomDirectEventTypeConstants()
}

override fun onAfterUpdateTransaction(view: LottieAnimationView) {
Expand Down
@@ -1,5 +1,3 @@
@file:Suppress("unused", "DEPRECATION")

package com.airbnb.android.react.lottie

import android.animation.Animator
Expand All @@ -22,21 +20,18 @@ import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setSourceU
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setSpeed
import com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.setTextFilters
import com.airbnb.lottie.LottieAnimationView
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.uimanager.events.RCTEventEmitter
import java.util.*

class LottieAnimationViewManager(val reactContext: ReactContext): SimpleViewManager<LottieAnimationView>() {
class LottieAnimationViewManager : SimpleViewManager<LottieAnimationView>() {
private val propManagersMap =
WeakHashMap<LottieAnimationView, LottieAnimationViewPropertyManager>()
WeakHashMap<LottieAnimationView, LottieAnimationViewPropertyManager>()

private fun getOrCreatePropertyManager(
view: LottieAnimationView
view: LottieAnimationView
): LottieAnimationViewPropertyManager {
var result = propManagersMap[view]
if (result == null) {
Expand All @@ -46,18 +41,6 @@ class LottieAnimationViewManager(val reactContext: ReactContext): SimpleViewMana
return result
}

private fun sendOnAnimationFinishEvent(view: LottieAnimationView, isCancelled: Boolean) {
val event = Arguments.createMap()
event.putBoolean("isCancelled", isCancelled)

val screenContext = view.context
if (screenContext is ThemedReactContext) {
screenContext
.getJSModule(RCTEventEmitter::class.java)
?.receiveEvent(view.id, "animationFinish", event)
}
}

override fun getExportedViewConstants(): Map<String, Any> {
return LottieAnimationViewManagerImpl.exportedViewConstants
}
Expand All @@ -69,35 +52,35 @@ class LottieAnimationViewManager(val reactContext: ReactContext): SimpleViewMana
public override fun createViewInstance(context: ThemedReactContext): LottieAnimationView {
val view = LottieAnimationViewManagerImpl.createViewInstance(context)
view.addAnimatorListener(
object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
// do nothing
}

override fun onAnimationEnd(animation: Animator) {
sendOnAnimationFinishEvent(view, false)
}

override fun onAnimationCancel(animation: Animator) {
sendOnAnimationFinishEvent(view, true)
}

override fun onAnimationRepeat(animation: Animator) {
// do nothing
}
object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
// do nothing
}

override fun onAnimationEnd(animation: Animator) {
LottieAnimationViewManagerImpl.sendOnAnimationFinishEvent(view, false)
}

override fun onAnimationCancel(animation: Animator) {
LottieAnimationViewManagerImpl.sendOnAnimationFinishEvent(view, true)
}

override fun onAnimationRepeat(animation: Animator) {
// do nothing
}
}
)
return view
}

override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return LottieAnimationViewManagerImpl.getExportedCustomBubblingEventTypeConstants()
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any>? {
return LottieAnimationViewManagerImpl.getExportedCustomDirectEventTypeConstants()
}

override fun receiveCommand(
view: LottieAnimationView,
commandName: String,
args: ReadableArray?
view: LottieAnimationView,
commandName: String,
args: ReadableArray?
) {
when (commandName) {
"play" -> play(view, args?.getInt(0) ?: -1, args?.getInt(1) ?: -1)
Expand Down Expand Up @@ -142,8 +125,8 @@ class LottieAnimationViewManager(val reactContext: ReactContext): SimpleViewMana

@ReactProp(name = "hardwareAccelerationAndroid")
fun setHardwareAccelerationAndroid(
view: LottieAnimationView,
hardwareAccelerationAndroid: Boolean?
view: LottieAnimationView,
hardwareAccelerationAndroid: Boolean?
) {
setHardwareAcceleration(hardwareAccelerationAndroid!!, getOrCreatePropertyManager(view))
}
Expand Down

0 comments on commit ebb8006

Please sign in to comment.