diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java index 68949f82f77..2046458470c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java @@ -7,7 +7,9 @@ package com.facebook.react.animated; +import android.content.Context; import android.graphics.Color; +import android.view.View; import com.facebook.react.bridge.ColorPropConverter; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; @@ -22,7 +24,8 @@ import com.facebook.react.views.view.ColorUtil; private final int mGNodeId; private final int mBNodeId; private final int mANodeId; - private int mColor; + private final ReadableMap mNativeColor; + private boolean mNativeColorApplied; public ColorAnimatedNode( ReadableMap config, @@ -34,15 +37,13 @@ import com.facebook.react.views.view.ColorUtil; mGNodeId = config.getInt("g"); mBNodeId = config.getInt("b"); mANodeId = config.getInt("a"); - setNativeColor(config.getMap("nativeColor")); + mNativeColor = config.getMap("nativeColor"); + tryApplyNativeColor(); } public int getColor() { - return mColor; - } + tryApplyNativeColor(); - @Override - public void update() { ValueAnimatedNode rNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mRNodeId); ValueAnimatedNode gNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mGNodeId); ValueAnimatedNode bNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mBNodeId); @@ -53,7 +54,7 @@ import com.facebook.react.views.view.ColorUtil; double b = bNode.getValue(); double a = aNode.getValue(); - mColor = ColorUtil.normalize(r, g, b, a); + return ColorUtil.normalize(r, g, b, a); } @Override @@ -70,13 +71,17 @@ import com.facebook.react.views.view.ColorUtil; + mANodeId; } - private void setNativeColor(ReadableMap nativeColor) { - if (nativeColor == null) { + private void tryApplyNativeColor() { + if (mNativeColor == null || mNativeColorApplied) { return; } - int color = - ColorPropConverter.getColor(nativeColor, mReactApplicationContext.getCurrentActivity()); + Context context = getContext(); + if (context == null) { + return; + } + + int color = ColorPropConverter.getColor(mNativeColor, context); ValueAnimatedNode rNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mRNodeId); ValueAnimatedNode gNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mGNodeId); @@ -88,6 +93,33 @@ import com.facebook.react.views.view.ColorUtil; bNode.mValue = Color.blue(color); aNode.mValue = Color.alpha(color) / 255.0; - update(); + mNativeColorApplied = true; + } + + private Context getContext() { + Context context = mReactApplicationContext.getCurrentActivity(); + if (context != null) { + return context; + } + + // There are cases where the activity may not exist (such as for VRShell panel apps). In this + // case we will search for a view associated with a PropsAnimatedNode to get the context. + return getContextHelper(this); + } + + private static Context getContextHelper(AnimatedNode node) { + // Search children depth-first until we get to a PropsAnimatedNode, from which we can + // get the view and its context + if (node.mChildren != null) { + for (AnimatedNode child : node.mChildren) { + if (child instanceof PropsAnimatedNode) { + View view = ((PropsAnimatedNode) child).getConnectedView(); + return view != null ? view.getContext() : null; + } else { + return getContextHelper(child); + } + } + } + return null; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java index 759675e661a..aacf6bf1c3f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java @@ -7,12 +7,14 @@ package com.facebook.react.animated; +import android.view.View; import androidx.annotation.Nullable; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMapKeySetIterator; import com.facebook.react.bridge.UIManager; +import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.common.ViewUtil; import java.util.HashMap; @@ -116,6 +118,16 @@ import java.util.Map; mUIManager.synchronouslyUpdateViewOnUIThread(mConnectedViewTag, mPropMap); } + public View getConnectedView() { + try { + return mUIManager.resolveView(mConnectedViewTag); + } catch (IllegalViewOperationException ex) { + // resolveView throws an {@link IllegalViewOperationException} when the view doesn't exist + // (this can happen if the surface is being deallocated). + return null; + } + } + public String prettyPrint() { return "PropsAnimatedNode[" + mTag