From 065769e2e5c44dc68202d175b16753fb3397d71d Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Wed, 10 Oct 2018 15:01:48 -0700 Subject: [PATCH] Use an older version of SurfaceTexture.setOnFrameAvailableListener when running on pre-Lollipop devices (flutter/engine#6489) Fixes https://github.com/flutter/flutter/issues/21730 --- .../android/io/flutter/view/FlutterView.java | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java index 072a5b462a..fe7002c3be 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java @@ -1041,24 +1041,33 @@ public class FlutterView extends SurfaceView SurfaceTextureRegistryEntry(long id, SurfaceTexture surfaceTexture) { this.id = id; this.surfaceTexture = surfaceTexture; - this.surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { - @Override - public void onFrameAvailable(SurfaceTexture texture) { - if (released) { - // Even though we make sure to unregister the callback before releasing, as of Android O - // SurfaceTexture has a data race when accessing the callback, so the callback may - // still be called by a stale reference after released==true and mNativeView==null. - return; - } - nativeMarkTextureFrameAvailable(mNativeView.get(), SurfaceTextureRegistryEntry.this.id); - } - }, - // The callback relies on being executed on the UI thread (unsynchronised read of mNativeView - // and also the engine code check for platform thread in Shell::OnPlatformViewMarkTextureFrameAvailable), - // so we explicitly pass a Handler for the current thread. - new Handler()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // The callback relies on being executed on the UI thread (unsynchronised read of mNativeView + // and also the engine code check for platform thread in Shell::OnPlatformViewMarkTextureFrameAvailable), + // so we explicitly pass a Handler for the current thread. + this.surfaceTexture.setOnFrameAvailableListener(onFrameListener, new Handler()); + } else { + // Android documentation states that the listener can be called on an arbitrary thread. + // But in practice, versions of Android that predate the newer API will call the listener + // on the thread where the SurfaceTexture was constructed. + this.surfaceTexture.setOnFrameAvailableListener(onFrameListener); + } } + private SurfaceTexture.OnFrameAvailableListener onFrameListener = new SurfaceTexture.OnFrameAvailableListener() { + @Override + public void onFrameAvailable(SurfaceTexture texture) { + if (released) { + // Even though we make sure to unregister the callback before releasing, as of Android O + // SurfaceTexture has a data race when accessing the callback, so the callback may + // still be called by a stale reference after released==true and mNativeView==null. + return; + } + nativeMarkTextureFrameAvailable(mNativeView.get(), SurfaceTextureRegistryEntry.this.id); + } + }; + @Override public SurfaceTexture surfaceTexture() { return surfaceTexture;