question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The ART '<Surface>' becomes invisible in Android

See original GitHub issue

Is this a bug report?

Yes.

Have you read the Contributing Guidelines?

Yes.

Environment

Environment: OS: macOS Sierra 10.12.6 Node: 8.4.0 Yarn: 1.3.2 Watchman: 4.9.0

Packages: (wanted => installed) react-native: 0.50.1 => 0.50.1 react: 16.0.0 => 16.0.0

Target Platform: Android 7.1.1

Steps to Reproduce

  1. generate a pathh and draw if with ART, it works correctly on the first render;
  2. put the phone to sleep;
  3. awake the phone;
  4. the <Surface> area becomes invisable;

Expected Behavior

it should just look like same with the first render.

Actual Behavior

the <Surface> area becomes invisable;

Reproducible Demo

the main just like below:

<Surface width={ 300 } height={ 200 }>
  <Shape  d={ new Path()
      .moveTo(0, 0)
      .lineTo(0, 200)
      .lineTo(300, 200)
      .lineTo(300, 0)
      .close() } fill={ '#f00' } />
</Surface>

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:7
  • Comments:28 (7 by maintainers)

github_iconTop GitHub Comments

8reactions
chufengmacommented, Oct 18, 2018

I think I solved this problem by modifying the implementation of ART on Android Native Code. The code changes very little. Use View instead of SurfaceView or TextureView

Potential risk: Texurate used to be rendered in sub threads, and View is now in the main thread. But testing, it has almost no effect on rendering speed.

code: com.facebook.react.views.art.ARTSurfaceView.java :

public class ARTSurfaceView extends View {

  private ARTSurfaceViewShadowNode.OnDrawCallback onDrawCallback;

  public ARTSurfaceView(Context context) {
    super(context);
//    setOpaque(false);
  }

  public void setOnDrawCallback(ARTSurfaceViewShadowNode.OnDrawCallback onDrawCallback) {
    this.onDrawCallback = onDrawCallback;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (onDrawCallback != null) {
      onDrawCallback.drawOutput(canvas);
    }
  }
}

com.facebook.react.views.art.ARTSurfaceViewShadowNode.java :

public class ARTSurfaceViewShadowNode extends LayoutShadowNode {

  private @Nullable Integer mBackgroundColor;

  @ReactProp(name = ViewProps.BACKGROUND_COLOR, customType = "Color")
  public void setBackgroundColor(Integer color) {
    mBackgroundColor = color;
    markUpdated();
  }

  @Override
  public boolean isVirtual() {
    return false;
  }

  @Override
  public boolean isVirtualAnchor() {
    return true;
  }

  @Override
  public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
    super.onCollectExtraUpdates(uiUpdater);
//    drawOutput();
    uiUpdater.enqueueUpdateExtraData(getReactTag(), this);
  }

  public interface OnDrawCallback {
    void drawOutput(Canvas canvas);
  }

  public OnDrawCallback getOnDrawCallback() {
    return onDrawCallback;
  }

  private OnDrawCallback onDrawCallback = new OnDrawCallback() {
    @Override
    public void drawOutput(Canvas canvas) {
      ARTSurfaceViewShadowNode.this.drawOutput(canvas);
    }
  };

  private void drawOutput(Canvas canvas) {
//    if (mSurface == null || !mSurface.isValid()) {
//      markChildrenUpdatesSeen(this);
//      return;
//    }

    try {
      canvas.drawColor(Color.TRANSPARENT);
      if (mBackgroundColor != null) {
        canvas.drawColor(mBackgroundColor);
      }

      Paint paint = new Paint();
      for (int i = 0; i < getChildCount(); i++) {
        ARTVirtualNode child = (ARTVirtualNode) getChildAt(i);
        child.draw(canvas, paint, 1f);
        child.markUpdateSeen();
      }

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

}

com.facebook.react.views.art.ARTSurfaceViewManager.java :

...
@Override
  public void updateExtraData(ARTSurfaceView root, Object extraData) {
//    root.getHolder().addCallback((ARTSurfaceViewShadowNode) extraData);
//    root.getHolder().addCallback((ARTSurfaceViewShadowNode) extraData);
    root.setOnDrawCallback(((ARTSurfaceViewShadowNode) extraData).getOnDrawCallback());
  }
...
7reactions
sophiebitscommented, May 18, 2018

Results from an internal investigation here:

From API level 25 onwards the hardware layer is deleted with the below call stack

screenshot of call stack including TextureView destroyHardwareResources  Screen on -> TextureView’s draw gets called –

boolean createNewSurface = (mSurface == null);
if (createNewSurface) {
// Create a new SurfaceTexture for the layer.
mSurface = new SurfaceTexture(false);
nCreateNativeWindow(mSurface);
}
mLayer.setSurfaceTexture(mSurface);

So, if there is a surface existing from before sleep, use that. A regular Textureview proceeds to draw on preexisting surface and has no problem.

In the case of ARTSurfaceView we are doing all the drawing here -

https://github.com/facebook/react-native/blob/v0.55.4/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java#L61

(Oh btw, Android says not to actually - Subclasses of TextureView cannot do their own rendering with the {@link Canvas} object.)

So, ARTSurfaceView is not aware of the whole sleep and destroy, there is no redraw after screen gets switched on and hence the blank screen.

It sounds like the best path forwards may be to switch from TextureView to SurfaceView since the latter appears intended for software drawing which is what we’re doing (vs video/camera use cases recommended in TextureView docs).

It’s not clear if we’ll have time to work on this at FB soon but if someone in the community wants to try their hand at making the switch then that would be valuable towards getting this bug fixed.

cc @himabindugadupudi

Read more comments on GitHub >

github_iconTop Results From Across the Web

The ART Surface becomes invisible in Android - YouTube
The ART Surface becomes invisible in Android. 23 views Dec 18, 2018 this is screen record for pull request #22624 in react-native repo...
Read more >
GL Surface and Visibility: Gone - android - Stack Overflow
The surface is in an invisible RelativeLayout (visibility: gone). When I change the visibility to "visible" then back to "gone", the layout ...
Read more >
SurfaceView | Android Developers
The transparent region that makes the surface visible is based on the layout positions in the view hierarchy. If the post-layout transform properties...
Read more >
Why is Waze now defaulting to Invisible Mode? It's happening ...
Why is Waze now defaulting to Invisible Mode? It's happening on iPhone and Android. Getting real tired of having to manually change ...
Read more >
Map artwork over 3D objects in Illustrator - Adobe Support
To view only the artwork map without the geometry of a 3D object, select Invisible Geometry in Properties. You can use this effect...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found