Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit d80cb15
Author: Guilherme Iscaro <[email protected]>
Date:   Wed Dec 12 18:56:08 2018 -0200

    ARTSurfaceViewShadowNode: Avoid not drawing the Surface View

    Calls updateExtraData(), which registers the surface texture listener may arrive too late,
    thus the SurfaceTexture may already have been created which will case onSurfaceTextureAvailable()
    to never be called, ultimatilly causing the surface to not be drawed.

    As a fix this patch checks if the SurfaceTexture is ready to use and if so draw the surface right away.

commit c767175
Author: Guilherme Iscaro <[email protected]>
Date:   Wed Dec 12 18:45:55 2018 -0200

    ARTSurfaceViewShadowNode: redraw itself if the host resumed the execution

    Starting on API level 25, Android will destroy the TextureView's TextureLayer when the
    an app is sent to the background and automatically create a new one once the TextureView is
    drawed again. This causes a problem for ARTSurfaceView, because this component does not draw itself
    and the Android API explicitly forbids to do such action. Since there's no listeners available to know
    when the new TextureLayer was created, the ARTSufurfaceViewShadowNode will listen for life cycle events
    and redraw its children once the activity is resumed.

    It's was also discussed that ARTSurfaceView should extends SurfaceView and not TextureView, however
    this may introduce two problems:

    * SurfaceView is not hardware accelerated, which may cause impact on performance
    * SurfaceView does not support opacity, so it will be impossible to set the ARTSufraceView as
    transparent

    With this problems in mind, this commit keeps the ARTSurfaceView extending TextureView.

    Fixes facebook#17565

commit 793669f
Author: Guilherme Iscaro <[email protected]>
Date:   Wed Dec 12 18:43:54 2018 -0200

    ARTSurfaceViewShadowNode: Properly release mSurface

    Since onSurfaceTextureDestroyed() returns true, the SurfaceTexture object will be released
    by the Android automatically so there's no need to call release on it. However,
    the node should release its refereces to the Surface object.
  • Loading branch information
pennersr committed Jun 23, 2019
1 parent 43945c1 commit d68a52a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ protected ARTSurfaceView createViewInstance(ThemedReactContext reactContext) {

@Override
public void updateExtraData(ARTSurfaceView root, Object extraData) {
root.setSurfaceTextureListener((ARTSurfaceViewShadowNode) extraData);
ARTSurfaceViewShadowNode shadowNode = (ARTSurfaceViewShadowNode) extraData;
shadowNode.setupSurfaceTextureListener(root);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,23 @@
import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture;
import android.view.TextureView;
import android.os.Build;

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;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.bridge.LifecycleEventListener;

/**
* Shadow node for ART virtual tree root - ARTSurfaceView
*/
public class ARTSurfaceViewShadowNode extends LayoutShadowNode
implements TextureView.SurfaceTextureListener {
implements TextureView.SurfaceTextureListener, LifecycleEventListener {

private @Nullable Surface mSurface;

Expand All @@ -54,11 +57,11 @@ public boolean isVirtualAnchor() {
@Override
public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
super.onCollectExtraUpdates(uiUpdater);
drawOutput();
drawOutput(false);
uiUpdater.enqueueUpdateExtraData(getReactTag(), this);
}

private void drawOutput() {
private void drawOutput(boolean markAsUpdated) {
if (mSurface == null || !mSurface.isValid()) {
markChildrenUpdatesSeen(this);
return;
Expand All @@ -75,19 +78,31 @@ private void drawOutput() {
for (int i = 0; i < getChildCount(); i++) {
ARTVirtualNode child = (ARTVirtualNode) getChildAt(i);
child.draw(canvas, paint, 1f);
child.markUpdateSeen();
if (markAsUpdated) {
child.markUpdated();
} else {
child.markUpdateSeen();
}
}

if (mSurface == null) {
return;
}

mSurface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException | IllegalStateException e) {
FLog.e(ReactConstants.TAG, e.getClass().getSimpleName() + " in Surface.unlockCanvasAndPost");
}
}

public void setupSurfaceTextureListener(ARTSurfaceView surfaceView) {
SurfaceTexture surface = surfaceView.getSurfaceTexture();
surfaceView.setSurfaceTextureListener(this);
if (surface != null && mSurface == null) {
mSurface = new Surface(surface);
drawOutput(true);
}
}

private void markChildrenUpdatesSeen(ReactShadowNode shadowNode) {
for (int i = 0; i < shadowNode.getChildCount(); i++) {
ReactShadowNode child = shadowNode.getChildAt(i);
Expand All @@ -96,15 +111,42 @@ private void markChildrenUpdatesSeen(ReactShadowNode shadowNode) {
}
}

@Override
public void setThemedContext(ThemedReactContext themedContext) {
super.setThemedContext(themedContext);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
themedContext.addLifecycleEventListener(this);
}
}

@Override
public void dispose() {
super.dispose();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
getThemedContext().removeLifecycleEventListener(this);
}
}

@Override
public void onHostResume() {
drawOutput(false);
}

@Override
public void onHostPause() {}

@Override
public void onHostDestroy() {}

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurface = new Surface(surface);
drawOutput();
drawOutput(false);
}

@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
surface.release();
mSurface.release();
mSurface = null;
return true;
}
Expand Down

0 comments on commit d68a52a

Please sign in to comment.