Skip to content

Commit 13076d9

Browse files
committed
pick from v1.12.13_xianyu
1 parent 3d40b08 commit 13076d9

File tree

2 files changed

+184
-2
lines changed

2 files changed

+184
-2
lines changed
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package com.idlefish.flutterboost;
2+
import android.content.Context;
3+
import android.graphics.SurfaceTexture;
4+
import android.util.AttributeSet;
5+
import android.view.Surface;
6+
import android.view.TextureView;
7+
8+
import androidx.annotation.NonNull;
9+
import androidx.annotation.Nullable;
10+
import io.flutter.Log;
11+
import io.flutter.embedding.engine.renderer.FlutterRenderer;
12+
import io.flutter.embedding.engine.renderer.RenderSurface;
13+
14+
public class XFlutterTextureView extends TextureView implements RenderSurface {
15+
private static final String TAG = "FlutterTextureView";
16+
17+
private boolean isSurfaceAvailableForRendering = false;
18+
private boolean isAttachedToFlutterRenderer = false;
19+
@Nullable
20+
private FlutterRenderer flutterRenderer;
21+
22+
private Surface renderSurface;
23+
24+
// Connects the {@code SurfaceTexture} beneath this {@code TextureView} with Flutter's native code.
25+
// Callbacks are received by this Object and then those messages are forwarded to our
26+
// FlutterRenderer, and then on to the JNI bridge over to native Flutter code.
27+
private final SurfaceTextureListener surfaceTextureListener = new SurfaceTextureListener() {
28+
@Override
29+
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
30+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureAvailable()");
31+
isSurfaceAvailableForRendering = true;
32+
33+
// If we're already attached to a FlutterRenderer then we're now attached to both a renderer
34+
// and the Android window, so we can begin rendering now.
35+
if (isAttachedToFlutterRenderer) {
36+
connectSurfaceToRenderer();
37+
}
38+
}
39+
40+
@Override
41+
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
42+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureSizeChanged()");
43+
if (isAttachedToFlutterRenderer) {
44+
changeSurfaceSize(width, height);
45+
}
46+
}
47+
48+
@Override
49+
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
50+
// Invoked every time a new frame is available. We don't care.
51+
}
52+
53+
@Override
54+
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
55+
Log.v(TAG, "SurfaceTextureListener.onSurfaceTextureDestroyed()");
56+
isSurfaceAvailableForRendering = false;
57+
58+
// If we're attached to a FlutterRenderer then we need to notify it that our SurfaceTexture
59+
// has been destroyed.
60+
if (isAttachedToFlutterRenderer) {
61+
disconnectSurfaceFromRenderer();
62+
}
63+
64+
// Return true to indicate that no further painting will take place
65+
// within this SurfaceTexture.
66+
return true;
67+
}
68+
};
69+
70+
/**
71+
* Constructs a {@code FlutterTextureView} programmatically, without any XML attributes.
72+
*/
73+
public XFlutterTextureView(@NonNull Context context) {
74+
this(context, null);
75+
}
76+
77+
/**
78+
* Constructs a {@code FlutterTextureView} in an XML-inflation-compliant manner.
79+
*/
80+
public XFlutterTextureView(@NonNull Context context, @Nullable AttributeSet attrs) {
81+
super(context, attrs);
82+
init();
83+
}
84+
85+
private void init() {
86+
// Listen for when our underlying SurfaceTexture becomes available, changes size, or
87+
// gets destroyed, and take the appropriate actions.
88+
setSurfaceTextureListener(surfaceTextureListener);
89+
}
90+
91+
@Nullable
92+
@Override
93+
public FlutterRenderer getAttachedRenderer() {
94+
return flutterRenderer;
95+
}
96+
97+
/**
98+
* Invoked by the owner of this {@code FlutterTextureView} when it wants to begin rendering
99+
* a Flutter UI to this {@code FlutterTextureView}.
100+
*
101+
* If an Android {@link SurfaceTexture} is available, this method will give that
102+
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
103+
* Flutter's UI to this {@code FlutterTextureView}.
104+
*
105+
* If no Android {@link SurfaceTexture} is available yet, this {@code FlutterTextureView}
106+
* will wait until a {@link SurfaceTexture} becomes available and then give that
107+
* {@link SurfaceTexture} to the given {@link FlutterRenderer} to begin rendering
108+
* Flutter's UI to this {@code FlutterTextureView}.
109+
*/
110+
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
111+
Log.v(TAG, "Attaching to FlutterRenderer.");
112+
if (this.flutterRenderer != null) {
113+
Log.v(TAG, "Already connected to a FlutterRenderer. Detaching from old one and attaching to new one.");
114+
this.flutterRenderer.stopRenderingToSurface();
115+
}
116+
117+
this.flutterRenderer = flutterRenderer;
118+
isAttachedToFlutterRenderer = true;
119+
120+
// If we're already attached to an Android window then we're now attached to both a renderer
121+
// and the Android window. We can begin rendering now.
122+
if (isSurfaceAvailableForRendering) {
123+
Log.v(TAG, "Surface is available for rendering. Connecting FlutterRenderer to Android surface.");
124+
connectSurfaceToRenderer();
125+
}
126+
}
127+
128+
/**
129+
* Invoked by the owner of this {@code FlutterTextureView} when it no longer wants to render
130+
* a Flutter UI to this {@code FlutterTextureView}.
131+
*
132+
* This method will cease any on-going rendering from Flutter to this {@code FlutterTextureView}.
133+
*/
134+
public void detachFromRenderer() {
135+
if (flutterRenderer != null) {
136+
// If we're attached to an Android window then we were rendering a Flutter UI. Now that
137+
// this FlutterTextureView is detached from the FlutterRenderer, we need to stop rendering.
138+
// TODO(mattcarroll): introduce a isRendererConnectedToSurface() to wrap "getWindowToken() != null"
139+
if (getWindowToken() != null) {
140+
Log.v(TAG, "Disconnecting FlutterRenderer from Android surface.");
141+
disconnectSurfaceFromRenderer();
142+
}
143+
144+
flutterRenderer = null;
145+
isAttachedToFlutterRenderer = false;
146+
} else {
147+
Log.w(TAG, "detachFromRenderer() invoked when no FlutterRenderer was attached.");
148+
}
149+
}
150+
151+
// FlutterRenderer and getSurfaceTexture() must both be non-null.
152+
private void connectSurfaceToRenderer() {
153+
if (flutterRenderer == null || getSurfaceTexture() == null) {
154+
throw new IllegalStateException("connectSurfaceToRenderer() should only be called when flutterRenderer and getSurfaceTexture() are non-null.");
155+
}
156+
157+
// flutterRenderer.startRenderingToSurface(new Surface(getSurfaceTexture()));
158+
159+
renderSurface = new Surface(getSurfaceTexture());
160+
flutterRenderer.startRenderingToSurface(renderSurface);
161+
}
162+
163+
// FlutterRenderer must be non-null.
164+
private void changeSurfaceSize(int width, int height) {
165+
if (flutterRenderer == null) {
166+
throw new IllegalStateException("changeSurfaceSize() should only be called when flutterRenderer is non-null.");
167+
}
168+
169+
Log.v(TAG, "Notifying FlutterRenderer that Android surface size has changed to " + width + " x " + height);
170+
flutterRenderer.surfaceChanged(width, height);
171+
}
172+
173+
// FlutterRenderer must be non-null.
174+
private void disconnectSurfaceFromRenderer() {
175+
if (flutterRenderer == null) {
176+
throw new IllegalStateException("disconnectSurfaceFromRenderer() should only be called when flutterRenderer is non-null.");
177+
}
178+
179+
flutterRenderer.stopRenderingToSurface();
180+
renderSurface.release();
181+
renderSurface = null;
182+
}
183+
}

android/src/main/java/com/idlefish/flutterboost/XFlutterView.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import io.flutter.embedding.engine.renderer.FlutterRenderer;
3939
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
4040
import io.flutter.embedding.engine.renderer.RenderSurface;
41-
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
4241
import io.flutter.plugin.editing.TextInputPlugin;
4342
import io.flutter.plugin.platform.PlatformViewsController;
4443
import io.flutter.view.AccessibilityBridge;
@@ -183,7 +182,7 @@ private void init() {
183182
break;
184183
case texture:
185184
Log.v(TAG, "Internally using a FlutterTextureView.");
186-
FlutterTextureView flutterTextureView = new FlutterTextureView(getContext());
185+
XFlutterTextureView flutterTextureView = new XFlutterTextureView(getContext());
187186
renderSurface = flutterTextureView;
188187
addView(flutterTextureView);
189188
break;

0 commit comments

Comments
 (0)