diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java index ce8b5e1362c..770739f394c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java @@ -15,6 +15,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; +import android.graphics.DashPathEffect; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -158,8 +159,7 @@ public class ARTShapeShadowNode extends ARTVirtualNode { (int) (mStrokeColor[1] * 255), (int) (mStrokeColor[2] * 255)); if (mStrokeDash != null && mStrokeDash.length > 0) { - // TODO(6352067): Support dashes - FLog.w(ReactConstants.TAG, "ART: Dashes are not supported yet!"); + paint.setPathEffect(new DashPathEffect(mStrokeDash, 0)); } return true; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java index 42aecf3927e..ea55d0b415f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java @@ -9,37 +9,15 @@ package com.facebook.react.views.art; -import javax.annotation.Nullable; - import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.view.View; +import android.view.TextureView; /** * Custom {@link View} implementation that draws an ARTSurface React view and its children. */ -public class ARTSurfaceView extends View { - - private @Nullable Bitmap mBitmap; - +public class ARTSurfaceView extends TextureView { public ARTSurfaceView(Context context) { super(context); - } - - public void setBitmap(Bitmap bitmap) { - if (mBitmap != null) { - mBitmap.recycle(); - } - mBitmap = bitmap; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (mBitmap != null) { - canvas.drawBitmap(mBitmap, 0, 0, null); - } + setOpaque(false); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java index 729fff291df..607f240bda7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java @@ -9,8 +9,6 @@ package com.facebook.react.views.art; -import android.graphics.Bitmap; - import com.facebook.csslayout.CSSMeasureMode; import com.facebook.csslayout.CSSNodeAPI; import com.facebook.csslayout.MeasureOutput; @@ -63,6 +61,6 @@ public class ARTSurfaceViewManager extends @Override public void updateExtraData(ARTSurfaceView root, Object extraData) { - root.setBitmap((Bitmap) extraData); + root.setSurfaceTextureListener((ARTSurfaceViewShadowNode) extraData); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java index b6004efa88b..538c0792fad 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java @@ -9,17 +9,29 @@ package com.facebook.react.views.art; -import android.graphics.Bitmap; +import javax.annotation.Nullable; + import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Color; +import android.view.Surface; +import android.graphics.PorterDuff; +import android.graphics.SurfaceTexture; +import android.view.TextureView; +import com.facebook.common.logging.FLog; +import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.LayoutShadowNode; import com.facebook.react.uimanager.UIViewOperationQueue; +import com.facebook.react.uimanager.ReactShadowNode; /** * Shadow node for ART virtual tree root - ARTSurfaceView */ -public class ARTSurfaceViewShadowNode extends LayoutShadowNode { +public class ARTSurfaceViewShadowNode extends LayoutShadowNode + implements TextureView.SurfaceTextureListener { + + private @Nullable Surface mSurface; @Override public boolean isVirtual() { @@ -34,23 +46,61 @@ public class ARTSurfaceViewShadowNode extends LayoutShadowNode { @Override public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) { super.onCollectExtraUpdates(uiUpdater); - uiUpdater.enqueueUpdateExtraData(getReactTag(), drawOutput()); + drawOutput(); + uiUpdater.enqueueUpdateExtraData(getReactTag(), this); } - private Object drawOutput() { - // TODO(7255985): Use TextureView and pass Surface from the view to draw on it asynchronously - // instead of passing the bitmap (which is inefficient especially in terms of memory usage) - Bitmap bitmap = Bitmap.createBitmap( - (int) getLayoutWidth(), - (int) getLayoutHeight(), - Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - for (int i = 0; i < getChildCount(); i++) { - ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); - child.draw(canvas, paint, 1f); - child.markUpdateSeen(); + private void drawOutput() { + if (mSurface == null || !mSurface.isValid()) { + markChildrenUpdatesSeen(this); + return; + } + + try { + Canvas canvas = mSurface.lockCanvas(null); + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + + Paint paint = new Paint(); + for (int i = 0; i < getChildCount(); i++) { + ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); + child.draw(canvas, paint, 1f); + child.markUpdateSeen(); + } + + if (mSurface == null) { + return; + } + + mSurface.unlockCanvasAndPost(canvas); + } catch (IllegalArgumentException | IllegalStateException e) { + FLog.e(ReactConstants.TAG, e.getClass().getSimpleName() + " in Surface.unlockCanvasAndPost"); } - return bitmap; } + + private void markChildrenUpdatesSeen(ReactShadowNode shadowNode) { + for (int i = 0; i < shadowNode.getChildCount(); i++) { + ReactShadowNode child = shadowNode.getChildAt(i); + child.markUpdateSeen(); + markChildrenUpdatesSeen(child); + } + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + mSurface = new Surface(surface); + drawOutput(); + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + surface.release(); + mSurface = null; + return true; + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) {} }