mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
This commit is contained in:
@@ -603,7 +603,8 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugin
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/OnFirstFrameRenderedListener.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/renderer/RenderSurface.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/KeyEventChannel.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/systemchannels/LifecycleChannel.java
|
||||
|
||||
@@ -170,7 +170,8 @@ action("flutter_shell_java") {
|
||||
"io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java",
|
||||
"io/flutter/embedding/engine/plugins/shim/ShimRegistrar.java",
|
||||
"io/flutter/embedding/engine/renderer/FlutterRenderer.java",
|
||||
"io/flutter/embedding/engine/renderer/OnFirstFrameRenderedListener.java",
|
||||
"io/flutter/embedding/engine/renderer/FlutterUiDisplayListener.java",
|
||||
"io/flutter/embedding/engine/renderer/RenderSurface.java",
|
||||
"io/flutter/embedding/engine/systemchannels/AccessibilityChannel.java",
|
||||
"io/flutter/embedding/engine/systemchannels/KeyEventChannel.java",
|
||||
"io/flutter/embedding/engine/systemchannels/LifecycleChannel.java",
|
||||
@@ -412,6 +413,9 @@ action("robolectric_tests") {
|
||||
"test/io/flutter/embedding/android/FlutterActivityTest.java",
|
||||
"test/io/flutter/embedding/android/FlutterFragmentTest.java",
|
||||
"test/io/flutter/embedding/engine/FlutterEngineCacheTest.java",
|
||||
"test/io/flutter/embedding/engine/FlutterJNITest.java",
|
||||
"test/io/flutter/embedding/engine/RenderingComponentTest.java",
|
||||
"test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java",
|
||||
"test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java",
|
||||
"test/io/flutter/util/PreconditionsTest.java",
|
||||
]
|
||||
|
||||
@@ -886,7 +886,18 @@ public class FlutterActivity extends Activity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstFrameRendered() {}
|
||||
public void onFlutterUiDisplayed() {
|
||||
// Notifies Android that we're fully drawn so that performance metrics can be collected by
|
||||
// Flutter performance tests.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
reportFullyDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* The mode of the background of a {@code FlutterActivity}, either opaque or transparent.
|
||||
|
||||
+20
-11
@@ -25,7 +25,7 @@ import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.FlutterEngineCache;
|
||||
import io.flutter.embedding.engine.FlutterShellArgs;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.view.FlutterMain;
|
||||
|
||||
@@ -83,10 +83,15 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
private boolean isFlutterEngineFromHost;
|
||||
|
||||
@NonNull
|
||||
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
host.onFirstFrameRendered();
|
||||
public void onFlutterUiDisplayed() {
|
||||
host.onFlutterUiDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
host.onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -228,7 +233,7 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
* <p>
|
||||
* {@code inflater} and {@code container} may be null when invoked from an {@code Activity}.
|
||||
* <p>
|
||||
* This method creates a new {@link FlutterView}, adds a {@link OnFirstFrameRenderedListener} to
|
||||
* This method creates a new {@link FlutterView}, adds a {@link FlutterUiDisplayListener} to
|
||||
* it, and then returns it.
|
||||
*/
|
||||
@NonNull
|
||||
@@ -236,7 +241,7 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
Log.v(TAG, "Creating FlutterView.");
|
||||
ensureAlive();
|
||||
flutterView = new FlutterView(host.getActivity(), host.getRenderMode(), host.getTransparencyMode());
|
||||
flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
|
||||
|
||||
flutterSplashView = new FlutterSplashView(host.getContext());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
@@ -391,12 +396,12 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
/**
|
||||
* Invoke this from {@code Activity#onDestroy()} or {@code Fragment#onDestroyView()}.
|
||||
* <p>
|
||||
* This method removes this delegate's {@link FlutterView}'s {@link OnFirstFrameRenderedListener}.
|
||||
* This method removes this delegate's {@link FlutterView}'s {@link FlutterUiDisplayListener}.
|
||||
*/
|
||||
void onDestroyView() {
|
||||
Log.v(TAG, "onDestroyView()");
|
||||
ensureAlive();
|
||||
flutterView.removeOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
flutterView.removeOnFirstFrameRenderedListener(flutterUiDisplayListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,9 +700,13 @@ import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
|
||||
boolean shouldAttachEngineToActivity();
|
||||
|
||||
/**
|
||||
* Invoked by this delegate when its {@link FlutterView} has rendered its first Flutter
|
||||
* frame.
|
||||
* Invoked by this delegate when its {@link FlutterView} starts painting pixels.
|
||||
*/
|
||||
void onFirstFrameRendered();
|
||||
void onFlutterUiDisplayed();
|
||||
|
||||
/**
|
||||
* Invoked by this delegate when its {@link FlutterView} stops painting pixels.
|
||||
*/
|
||||
void onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.view.ViewGroup;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.FlutterShellArgs;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.view.FlutterMain;
|
||||
|
||||
@@ -567,21 +567,6 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
|
||||
// implementation for details about why it exists.
|
||||
private FlutterActivityAndFragmentDelegate delegate;
|
||||
|
||||
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
// Notify our subclasses that the first frame has been rendered.
|
||||
FlutterFragment.this.onFirstFrameRendered();
|
||||
|
||||
// Notify our owning Activity that the first frame has been rendered.
|
||||
FragmentActivity fragmentActivity = getActivity();
|
||||
if (fragmentActivity instanceof OnFirstFrameRenderedListener) {
|
||||
OnFirstFrameRenderedListener activityAsListener = (OnFirstFrameRenderedListener) fragmentActivity;
|
||||
activityAsListener.onFirstFrameRendered();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public FlutterFragment() {
|
||||
// Ensure that we at least have an empty Bundle of arguments so that we don't
|
||||
// need to continually check for null arguments before grabbing one.
|
||||
@@ -951,21 +936,40 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} renders its first
|
||||
* frame.
|
||||
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} starts rendering
|
||||
* pixels to the screen.
|
||||
* <p>
|
||||
* This method forwards {@code onFirstFrameRendered()} to its attached {@code Activity}, if
|
||||
* the attached {@code Activity} implements {@link OnFirstFrameRenderedListener}.
|
||||
* This method forwards {@code onFlutterUiDisplayed()} to its attached {@code Activity}, if
|
||||
* the attached {@code Activity} implements {@link FlutterUiDisplayListener}.
|
||||
* <p>
|
||||
* Subclasses that override this method must call through to the {@code super} method.
|
||||
* <p>
|
||||
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
|
||||
*/
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
public void onFlutterUiDisplayed() {
|
||||
FragmentActivity attachedActivity = getActivity();
|
||||
if (attachedActivity instanceof OnFirstFrameRenderedListener) {
|
||||
((OnFirstFrameRenderedListener) attachedActivity).onFirstFrameRendered();
|
||||
if (attachedActivity instanceof FlutterUiDisplayListener) {
|
||||
((FlutterUiDisplayListener) attachedActivity).onFlutterUiDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} stops rendering
|
||||
* pixels to the screen.
|
||||
* <p>
|
||||
* This method forwards {@code onFlutterUiNoLongerDisplayed()} to its attached {@code Activity},
|
||||
* if the attached {@code Activity} implements {@link FlutterUiDisplayListener}.
|
||||
* <p>
|
||||
* Subclasses that override this method must call through to the {@code super} method.
|
||||
* <p>
|
||||
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
|
||||
*/
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
FragmentActivity attachedActivity = getActivity();
|
||||
if (attachedActivity instanceof FlutterUiDisplayListener) {
|
||||
((FlutterUiDisplayListener) attachedActivity).onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import android.widget.FrameLayout;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
|
||||
/**
|
||||
* {@code View} that displays a {@link SplashScreen} until a given {@link FlutterView}
|
||||
@@ -51,13 +51,18 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
};
|
||||
|
||||
@NonNull
|
||||
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
public void onFlutterUiDisplayed() {
|
||||
if (splashScreen != null) {
|
||||
transitionToFlutter();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
@@ -114,7 +119,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
) {
|
||||
// If we were displaying a previous FlutterView, remove it.
|
||||
if (this.flutterView != null) {
|
||||
this.flutterView.removeOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
this.flutterView.removeOnFirstFrameRenderedListener(flutterUiDisplayListener);
|
||||
removeView(this.flutterView);
|
||||
}
|
||||
// If we were displaying a previous splash screen View, remove it.
|
||||
@@ -136,7 +141,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
// waiting for the first frame to render. Show a splash UI until that happens.
|
||||
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
|
||||
addView(this.splashScreenView);
|
||||
flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
|
||||
} else if (isSplashScreenTransitionNeededNow()) {
|
||||
Log.v(TAG, "Showing an immediate splash transition to Flutter due to previously interrupted transition.");
|
||||
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
|
||||
|
||||
@@ -12,12 +12,10 @@ import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
|
||||
/**
|
||||
* Paints a Flutter UI on a {@link android.view.Surface}.
|
||||
@@ -34,7 +32,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
* desired, consider using a {@link FlutterView} which provides all of these behaviors and
|
||||
* utilizes a {@code FlutterSurfaceView} internally.
|
||||
*/
|
||||
public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.RenderSurface {
|
||||
public class FlutterSurfaceView extends SurfaceView implements RenderSurface {
|
||||
private static final String TAG = "FlutterSurfaceView";
|
||||
|
||||
private final boolean renderTransparently;
|
||||
@@ -42,8 +40,6 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
private boolean isAttachedToFlutterRenderer = false;
|
||||
@Nullable
|
||||
private FlutterRenderer flutterRenderer;
|
||||
@NonNull
|
||||
private Set<OnFirstFrameRenderedListener> onFirstFrameRenderedListeners = new HashSet<>();
|
||||
|
||||
// Connects the {@code Surface} beneath this {@code SurfaceView} with Flutter's native code.
|
||||
// Callbacks are received by this Object and then those messages are forwarded to our
|
||||
@@ -51,7 +47,7 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
private final SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
Log.v(TAG, "SurfaceHolder.Callback.surfaceCreated()");
|
||||
Log.v(TAG, "SurfaceHolder.Callback.startRenderingToSurface()");
|
||||
isSurfaceAvailableForRendering = true;
|
||||
|
||||
if (isAttachedToFlutterRenderer) {
|
||||
@@ -69,7 +65,7 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
|
||||
Log.v(TAG, "SurfaceHolder.Callback.surfaceDestroyed()");
|
||||
Log.v(TAG, "SurfaceHolder.Callback.stopRenderingToSurface()");
|
||||
isSurfaceAvailableForRendering = false;
|
||||
|
||||
if (isAttachedToFlutterRenderer) {
|
||||
@@ -78,6 +74,24 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
}
|
||||
};
|
||||
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFlutterUiDisplayed() {
|
||||
Log.v(TAG, "onFlutterUiDisplayed()");
|
||||
// Now that a frame is ready to display, take this SurfaceView from transparent to opaque.
|
||||
setAlpha(1.0f);
|
||||
|
||||
if (flutterRenderer != null) {
|
||||
flutterRenderer.removeIsDisplayingFlutterUiListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes.
|
||||
*/
|
||||
@@ -123,6 +137,12 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
setAlpha(0.0f);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public FlutterRenderer getAttachedRenderer() {
|
||||
return flutterRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the owner of this {@code FlutterSurfaceView} when it wants to begin rendering
|
||||
* a Flutter UI to this {@code FlutterSurfaceView}.
|
||||
@@ -140,12 +160,15 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
Log.v(TAG, "Attaching to FlutterRenderer.");
|
||||
if (this.flutterRenderer != null) {
|
||||
Log.v(TAG, "Already connected to a FlutterRenderer. Detaching from old one and attaching to new one.");
|
||||
this.flutterRenderer.detachFromRenderSurface();
|
||||
this.flutterRenderer.stopRenderingToSurface();
|
||||
this.flutterRenderer.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
}
|
||||
|
||||
this.flutterRenderer = flutterRenderer;
|
||||
isAttachedToFlutterRenderer = true;
|
||||
|
||||
this.flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
|
||||
// If we're already attached to an Android window then we're now attached to both a renderer
|
||||
// and the Android window. We can begin rendering now.
|
||||
if (isSurfaceAvailableForRendering) {
|
||||
@@ -173,6 +196,8 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
// Make the SurfaceView invisible to avoid showing a black rectangle.
|
||||
setAlpha(0.0f);
|
||||
|
||||
this.flutterRenderer.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
|
||||
flutterRenderer = null;
|
||||
isAttachedToFlutterRenderer = false;
|
||||
} else {
|
||||
@@ -186,7 +211,7 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
throw new IllegalStateException("connectSurfaceToRenderer() should only be called when flutterRenderer and getHolder() are non-null.");
|
||||
}
|
||||
|
||||
flutterRenderer.surfaceCreated(getHolder().getSurface());
|
||||
flutterRenderer.startRenderingToSurface(getHolder().getSurface());
|
||||
}
|
||||
|
||||
// FlutterRenderer must be non-null.
|
||||
@@ -205,36 +230,6 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
|
||||
throw new IllegalStateException("disconnectSurfaceFromRenderer() should only be called when flutterRenderer is non-null.");
|
||||
}
|
||||
|
||||
flutterRenderer.surfaceDestroyed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code listener} to this {@code FlutterSurfaceView}, to be notified upon Flutter's
|
||||
* first rendered frame.
|
||||
*/
|
||||
@Override
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@code listener}, which was previously added with
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
*/
|
||||
@Override
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
// TODO(mattcarroll): decide where this method should live and what it needs to do.
|
||||
Log.v(TAG, "onFirstFrameRendered()");
|
||||
// Now that a frame is ready to display, take this SurfaceView from transparent to opaque.
|
||||
setAlpha(1.0f);
|
||||
|
||||
for (OnFirstFrameRenderedListener listener : onFirstFrameRenderedListeners) {
|
||||
listener.onFirstFrameRendered();
|
||||
}
|
||||
flutterRenderer.stopRenderingToSurface();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,9 @@ import android.util.AttributeSet;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
|
||||
/**
|
||||
* Paints a Flutter UI on a {@link SurfaceTexture}.
|
||||
@@ -34,15 +31,13 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
* desired, consider using a {@link FlutterView} which provides all of these behaviors and
|
||||
* utilizes a {@code FlutterTextureView} internally.
|
||||
*/
|
||||
public class FlutterTextureView extends TextureView implements FlutterRenderer.RenderSurface {
|
||||
public class FlutterTextureView extends TextureView implements RenderSurface {
|
||||
private static final String TAG = "FlutterTextureView";
|
||||
|
||||
private boolean isSurfaceAvailableForRendering = false;
|
||||
private boolean isAttachedToFlutterRenderer = false;
|
||||
@Nullable
|
||||
private FlutterRenderer flutterRenderer;
|
||||
@NonNull
|
||||
private Set<OnFirstFrameRenderedListener> onFirstFrameRenderedListeners = new HashSet<>();
|
||||
|
||||
// Connects the {@code SurfaceTexture} beneath this {@code TextureView} with Flutter's native code.
|
||||
// Callbacks are received by this Object and then those messages are forwarded to our
|
||||
@@ -111,6 +106,12 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
|
||||
setSurfaceTextureListener(surfaceTextureListener);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public FlutterRenderer getAttachedRenderer() {
|
||||
return flutterRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the owner of this {@code FlutterTextureView} when it wants to begin rendering
|
||||
* a Flutter UI to this {@code FlutterTextureView}.
|
||||
@@ -128,7 +129,7 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
|
||||
Log.v(TAG, "Attaching to FlutterRenderer.");
|
||||
if (this.flutterRenderer != null) {
|
||||
Log.v(TAG, "Already connected to a FlutterRenderer. Detaching from old one and attaching to new one.");
|
||||
this.flutterRenderer.detachFromRenderSurface();
|
||||
this.flutterRenderer.stopRenderingToSurface();
|
||||
}
|
||||
|
||||
this.flutterRenderer = flutterRenderer;
|
||||
@@ -171,7 +172,7 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
|
||||
throw new IllegalStateException("connectSurfaceToRenderer() should only be called when flutterRenderer and getSurfaceTexture() are non-null.");
|
||||
}
|
||||
|
||||
flutterRenderer.surfaceCreated(new Surface(getSurfaceTexture()));
|
||||
flutterRenderer.startRenderingToSurface(new Surface(getSurfaceTexture()));
|
||||
}
|
||||
|
||||
// FlutterRenderer must be non-null.
|
||||
@@ -190,34 +191,6 @@ public class FlutterTextureView extends TextureView implements FlutterRenderer.R
|
||||
throw new IllegalStateException("disconnectSurfaceFromRenderer() should only be called when flutterRenderer is non-null.");
|
||||
}
|
||||
|
||||
flutterRenderer.surfaceDestroyed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code listener} to this {@code FlutterTextureView}, to be notified upon Flutter's
|
||||
* first rendered frame.
|
||||
*/
|
||||
@Override
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@code listener}, which was previously added with
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
*/
|
||||
@Override
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
// TODO(mattcarroll): decide where this method should live and what it needs to do.
|
||||
Log.v(TAG, "onFirstFrameRendered()");
|
||||
|
||||
for (OnFirstFrameRenderedListener listener : onFirstFrameRenderedListeners) {
|
||||
listener.onFirstFrameRendered();
|
||||
}
|
||||
flutterRenderer.stopRenderingToSurface();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ import java.util.Set;
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import io.flutter.view.AccessibilityBridge;
|
||||
@@ -74,9 +75,9 @@ public class FlutterView extends FrameLayout {
|
||||
|
||||
// Internal view hierarchy references.
|
||||
@Nullable
|
||||
private FlutterRenderer.RenderSurface renderSurface;
|
||||
private final Set<OnFirstFrameRenderedListener> onFirstFrameRenderedListeners = new HashSet<>();
|
||||
private boolean didRenderFirstFrame;
|
||||
private RenderSurface renderSurface;
|
||||
private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners = new HashSet<>();
|
||||
private boolean isFlutterUiDisplayed;
|
||||
|
||||
// Connections to a Flutter execution context.
|
||||
@Nullable
|
||||
@@ -108,13 +109,22 @@ public class FlutterView extends FrameLayout {
|
||||
}
|
||||
};
|
||||
|
||||
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
didRenderFirstFrame = true;
|
||||
public void onFlutterUiDisplayed() {
|
||||
isFlutterUiDisplayed = true;
|
||||
|
||||
for (OnFirstFrameRenderedListener listener : onFirstFrameRenderedListeners) {
|
||||
listener.onFirstFrameRendered();
|
||||
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
|
||||
listener.onFlutterUiDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
isFlutterUiDisplayed = false;
|
||||
|
||||
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
|
||||
listener.onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -228,23 +238,23 @@ public class FlutterView extends FrameLayout {
|
||||
* </ol>
|
||||
*/
|
||||
public boolean hasRenderedFirstFrame() {
|
||||
return didRenderFirstFrame;
|
||||
return isFlutterUiDisplayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code listener} to this {@code FlutterView}, to be notified upon Flutter's
|
||||
* first rendered frame.
|
||||
*/
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.add(listener);
|
||||
public void addOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
flutterUiDisplayListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@code listener}, which was previously added with
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
* {@link #addOnFirstFrameRenderedListener(FlutterUiDisplayListener)}.
|
||||
*/
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
onFirstFrameRenderedListeners.remove(listener);
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
flutterUiDisplayListeners.remove(listener);
|
||||
}
|
||||
|
||||
//------- Start: Process View configuration that Flutter cares about. ------
|
||||
@@ -580,9 +590,9 @@ public class FlutterView extends FrameLayout {
|
||||
|
||||
// Instruct our FlutterRenderer that we are now its designated RenderSurface.
|
||||
FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer();
|
||||
didRenderFirstFrame = flutterRenderer.hasRenderedFirstFrame();
|
||||
flutterRenderer.attachToRenderSurface(renderSurface);
|
||||
flutterRenderer.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi();
|
||||
renderSurface.attachToRenderer(flutterRenderer);
|
||||
flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
|
||||
// Initialize various components that know how to process Android View I/O
|
||||
// in a way that Flutter understands.
|
||||
@@ -631,8 +641,8 @@ public class FlutterView extends FrameLayout {
|
||||
// If the first frame has already been rendered, notify all first frame listeners.
|
||||
// Do this after all other initialization so that listeners don't inadvertently interact
|
||||
// with a FlutterView that is only partially attached to a FlutterEngine.
|
||||
if (didRenderFirstFrame) {
|
||||
onFirstFrameRenderedListener.onFirstFrameRendered();
|
||||
if (isFlutterUiDisplayed) {
|
||||
flutterUiDisplayListener.onFlutterUiDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,9 +684,9 @@ public class FlutterView extends FrameLayout {
|
||||
|
||||
// Instruct our FlutterRenderer that we are no longer interested in being its RenderSurface.
|
||||
FlutterRenderer flutterRenderer = flutterEngine.getRenderer();
|
||||
didRenderFirstFrame = false;
|
||||
flutterRenderer.removeOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
flutterRenderer.detachFromRenderSurface();
|
||||
isFlutterUiDisplayed = false;
|
||||
flutterRenderer.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
flutterRenderer.stopRenderingToSurface();
|
||||
flutterEngine = null;
|
||||
}
|
||||
|
||||
@@ -685,7 +695,8 @@ public class FlutterView extends FrameLayout {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public boolean isAttachedToFlutterEngine() {
|
||||
return flutterEngine != null && flutterEngine.getRenderer().isAttachedTo(renderSurface);
|
||||
return flutterEngine != null
|
||||
&& flutterEngine.getRenderer() == renderSurface.getAttachedRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverCo
|
||||
import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderControlSurface;
|
||||
import io.flutter.embedding.engine.plugins.service.ServiceControlSurface;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
|
||||
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
|
||||
@@ -51,8 +52,8 @@ import io.flutter.plugin.platform.PlatformViewsController;
|
||||
* invoked twice on the same {@code FlutterEngine}.
|
||||
*
|
||||
* To start rendering Flutter content to the screen, use {@link #getRenderer()} to obtain a
|
||||
* {@link FlutterRenderer} and then attach a {@link FlutterRenderer.RenderSurface}. Consider using
|
||||
* a {@link io.flutter.embedding.android.FlutterView} as a {@link FlutterRenderer.RenderSurface}.
|
||||
* {@link FlutterRenderer} and then attach a {@link RenderSurface}. Consider using
|
||||
* a {@link io.flutter.embedding.android.FlutterView} as a {@link RenderSurface}.
|
||||
*/
|
||||
// TODO(mattcarroll): re-evaluate system channel APIs - some are not well named or differentiated
|
||||
public class FlutterEngine implements LifecycleOwner {
|
||||
@@ -118,8 +119,8 @@ public class FlutterEngine implements LifecycleOwner {
|
||||
* to begin executing Dart code within this {@code FlutterEngine}.
|
||||
*
|
||||
* A new {@code FlutterEngine} will not display any UI until a
|
||||
* {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} is registered. See
|
||||
* {@link #getRenderer()} and {@link FlutterRenderer#attachToRenderSurface(FlutterRenderer.RenderSurface)}.
|
||||
* {@link RenderSurface} is registered. See
|
||||
* {@link #getRenderer()} and {@link FlutterRenderer#startRenderingToSurface(RenderSurface)}.
|
||||
*
|
||||
* A new {@code FlutterEngine} does not come with any Flutter plugins attached. To attach plugins,
|
||||
* see {@link #getPlugins()}.
|
||||
@@ -221,7 +222,7 @@ public class FlutterEngine implements LifecycleOwner {
|
||||
* The rendering system associated with this {@code FlutterEngine}.
|
||||
*
|
||||
* To render a Flutter UI that is produced by this {@code FlutterEngine}'s Dart code, attach
|
||||
* a {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} to this
|
||||
* a {@link RenderSurface} to this
|
||||
* {@link FlutterRenderer}.
|
||||
*/
|
||||
@NonNull
|
||||
|
||||
@@ -12,18 +12,19 @@ import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener;
|
||||
import io.flutter.embedding.engine.dart.PlatformMessageHandler;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.embedding.engine.renderer.RenderSurface;
|
||||
import io.flutter.plugin.common.StandardMessageCodec;
|
||||
import io.flutter.view.AccessibilityBridge;
|
||||
import io.flutter.view.FlutterCallbackInformation;
|
||||
@@ -72,13 +73,13 @@ import io.flutter.view.FlutterCallbackInformation;
|
||||
* }
|
||||
*
|
||||
* To provide a visual, interactive surface for Flutter rendering and touch events, register a
|
||||
* {@link FlutterRenderer.RenderSurface} with {@link #setRenderSurface(FlutterRenderer.RenderSurface)}
|
||||
* {@link RenderSurface} with {@link #setRenderSurface(RenderSurface)}
|
||||
*
|
||||
* To receive callbacks for certain events that occur on the native side, register listeners:
|
||||
*
|
||||
* <ol>
|
||||
* <li>{@link #addEngineLifecycleListener(EngineLifecycleListener)}</li>
|
||||
* <li>{@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}</li>
|
||||
* <li>{@link #addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)}</li>
|
||||
* </ol>
|
||||
*
|
||||
* To facilitate platform messages between Java and Dart running in Flutter, register a handler:
|
||||
@@ -155,15 +156,13 @@ public class FlutterJNI {
|
||||
@Nullable
|
||||
private Long nativePlatformViewId;
|
||||
@Nullable
|
||||
private FlutterRenderer.RenderSurface renderSurface;
|
||||
@Nullable
|
||||
private AccessibilityDelegate accessibilityDelegate;
|
||||
@Nullable
|
||||
private PlatformMessageHandler platformMessageHandler;
|
||||
@NonNull
|
||||
private final Set<EngineLifecycleListener> engineLifecycleListeners = new HashSet<>();
|
||||
private final Set<EngineLifecycleListener> engineLifecycleListeners = new CopyOnWriteArraySet<>();
|
||||
@NonNull
|
||||
private final Set<OnFirstFrameRenderedListener> firstFrameListeners = new HashSet<>();
|
||||
private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners = new CopyOnWriteArraySet<>();
|
||||
@NonNull
|
||||
private final Looper mainLooper; // cached to avoid synchronization on repeat access.
|
||||
|
||||
@@ -233,58 +232,46 @@ public class FlutterJNI {
|
||||
|
||||
//----- Start Render Surface Support -----
|
||||
/**
|
||||
* Sets the {@link FlutterRenderer.RenderSurface} delegate for the attached Flutter context.
|
||||
* <p>
|
||||
* Flutter expects a user interface to exist on the platform side (Android), and that interface
|
||||
* is expected to offer some capabilities that Flutter depends upon. The {@link FlutterRenderer.RenderSurface}
|
||||
* interface represents those expectations.
|
||||
* <p>
|
||||
* If an app includes a user interface that renders a Flutter UI then a {@link FlutterRenderer.RenderSurface}
|
||||
* should be set (this is the typical Flutter scenario). If no UI is being rendered, such as a
|
||||
* Flutter app that is running Dart code in the background, then no registration may be necessary.
|
||||
* <p>
|
||||
* If no {@link FlutterRenderer.RenderSurface} is registered, then related messages coming from
|
||||
* Flutter will be dropped (ignored).
|
||||
* Adds a {@link FlutterUiDisplayListener}, which receives a callback when Flutter's
|
||||
* engine notifies {@code FlutterJNI} that Flutter is painting pixels to the {@link Surface} that
|
||||
* was provided to Flutter.
|
||||
*/
|
||||
@UiThread
|
||||
public void setRenderSurface(@Nullable FlutterRenderer.RenderSurface renderSurface) {
|
||||
public void addIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
ensureRunningOnMainThread();
|
||||
this.renderSurface = renderSurface;
|
||||
flutterUiDisplayListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link OnFirstFrameRenderedListener}, which receives a callback when Flutter's
|
||||
* engine notifies {@code FlutterJNI} that the first frame of a Flutter UI has been rendered
|
||||
* to the {@link Surface} that was provided to Flutter.
|
||||
* Removes a {@link FlutterUiDisplayListener} that was added with
|
||||
* {@link #addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)}.
|
||||
*/
|
||||
@UiThread
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
public void removeIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
ensureRunningOnMainThread();
|
||||
firstFrameListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a {@link OnFirstFrameRenderedListener} that was added with
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
*/
|
||||
@UiThread
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
ensureRunningOnMainThread();
|
||||
firstFrameListeners.remove(listener);
|
||||
flutterUiDisplayListeners.remove(listener);
|
||||
}
|
||||
|
||||
// Called by native to notify first Flutter frame rendered.
|
||||
@SuppressWarnings("unused")
|
||||
@VisibleForTesting
|
||||
@UiThread
|
||||
private void onFirstFrame() {
|
||||
void onFirstFrame() {
|
||||
ensureRunningOnMainThread();
|
||||
if (renderSurface != null) {
|
||||
renderSurface.onFirstFrameRendered();
|
||||
}
|
||||
// TODO(mattcarroll): log dropped messages when in debug mode (https://github.com/flutter/flutter/issues/25391)
|
||||
|
||||
for (OnFirstFrameRenderedListener listener : firstFrameListeners) {
|
||||
listener.onFirstFrameRendered();
|
||||
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
|
||||
listener.onFlutterUiDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mattcarroll): get native to call this when rendering stops.
|
||||
@VisibleForTesting
|
||||
@UiThread
|
||||
void onRenderingStopped() {
|
||||
ensureRunningOnMainThread();
|
||||
|
||||
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
|
||||
listener.onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +318,7 @@ public class FlutterJNI {
|
||||
public void onSurfaceDestroyed() {
|
||||
ensureRunningOnMainThread();
|
||||
ensureAttachedToNative();
|
||||
onRenderingStopped();
|
||||
nativeSurfaceDestroyed(nativePlatformViewId);
|
||||
}
|
||||
|
||||
@@ -431,7 +419,6 @@ public class FlutterJNI {
|
||||
* See {@link AccessibilityBridge} for an example of an {@link AccessibilityDelegate} and the
|
||||
* surrounding responsibilities.
|
||||
*/
|
||||
// TODO(mattcarroll): move AccessibilityDelegate definition into FlutterJNI. FlutterJNI should be the basis of dependencies, not the other way round.
|
||||
@UiThread
|
||||
public void setAccessibilityDelegate(@Nullable AccessibilityDelegate accessibilityDelegate) {
|
||||
ensureRunningOnMainThread();
|
||||
@@ -772,7 +759,7 @@ public class FlutterJNI {
|
||||
|
||||
/**
|
||||
* Removes the given {@code engineLifecycleListener}, which was previously added using
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
* {@link #addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)}.
|
||||
*/
|
||||
@UiThread
|
||||
public void removeEngineLifecycleListener(@NonNull EngineLifecycleListener engineLifecycleListener) {
|
||||
|
||||
@@ -17,95 +17,85 @@ import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import io.flutter.Log;
|
||||
import io.flutter.embedding.android.FlutterView;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.view.TextureRegistry;
|
||||
|
||||
/**
|
||||
* WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
|
||||
* IF YOU USE IT, WE WILL BREAK YOU.
|
||||
*
|
||||
* {@code FlutterRenderer} works in tandem with a provided {@link RenderSurface} to create an
|
||||
* interactive Flutter UI.
|
||||
*
|
||||
* {@code FlutterRenderer} manages textures for rendering, and forwards some Java calls to native Flutter
|
||||
* code via JNI. The corresponding {@link RenderSurface} is used as a delegate to carry out
|
||||
* certain actions on behalf of this {@code FlutterRenderer} within an Android view hierarchy.
|
||||
*
|
||||
* {@link FlutterView} is an implementation of a {@link RenderSurface}.
|
||||
* Represents the rendering responsibilities of a {@code FlutterEngine}.
|
||||
* <p>
|
||||
* {@code FlutterRenderer} works in tandem with a provided {@link RenderSurface} to paint Flutter
|
||||
* pixels to an Android {@code View} hierarchy.
|
||||
* <p>
|
||||
* {@code FlutterRenderer} manages textures for rendering, and forwards some Java calls to native
|
||||
* Flutter code via JNI. The corresponding {@link RenderSurface} provides the Android
|
||||
* {@link Surface} that this renderer paints.
|
||||
* <p>
|
||||
* {@link io.flutter.embedding.android.FlutterSurfaceView} and
|
||||
* {@link io.flutter.embedding.android.FlutterTextureView} are implementations of
|
||||
* {@link RenderSurface}.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
public class FlutterRenderer implements TextureRegistry {
|
||||
private static final String TAG = "FlutterRenderer";
|
||||
|
||||
@NonNull
|
||||
private final FlutterJNI flutterJNI;
|
||||
@NonNull
|
||||
private final AtomicLong nextTextureId = new AtomicLong(0L);
|
||||
private RenderSurface renderSurface;
|
||||
private boolean hasRenderedFirstFrame = false;
|
||||
@Nullable
|
||||
private Surface surface;
|
||||
private boolean isDisplayingFlutterUi = false;
|
||||
|
||||
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
|
||||
@NonNull
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
hasRenderedFirstFrame = true;
|
||||
public void onFlutterUiDisplayed() {
|
||||
isDisplayingFlutterUi = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
isDisplayingFlutterUi = false;
|
||||
}
|
||||
};
|
||||
|
||||
public FlutterRenderer(@NonNull FlutterJNI flutterJNI) {
|
||||
this.flutterJNI = flutterJNI;
|
||||
this.flutterJNI.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
|
||||
this.flutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this {@code FlutterRenderer} is attached to the given {@link RenderSurface},
|
||||
* false otherwise.
|
||||
* Returns true if this {@code FlutterRenderer} is painting pixels to an Android {@code View}
|
||||
* hierarchy, false otherwise.
|
||||
*/
|
||||
public boolean isAttachedTo(@NonNull RenderSurface renderSurface) {
|
||||
return this.renderSurface == renderSurface;
|
||||
public boolean isDisplayingFlutterUi() {
|
||||
return isDisplayingFlutterUi;
|
||||
}
|
||||
|
||||
public void attachToRenderSurface(@NonNull RenderSurface renderSurface) {
|
||||
Log.v(TAG, "Attaching to RenderSurface.");
|
||||
// TODO(mattcarroll): determine desired behavior when attaching to an already attached renderer
|
||||
if (this.renderSurface != null) {
|
||||
Log.v(TAG, "Already attached to a RenderSurface. Detaching from old one and attaching to new one.");
|
||||
detachFromRenderSurface();
|
||||
}
|
||||
/**
|
||||
* Adds a listener that is invoked whenever this {@code FlutterRenderer} starts and stops painting
|
||||
* pixels to an Android {@code View} hierarchy.
|
||||
*/
|
||||
public void addIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
flutterJNI.addIsDisplayingFlutterUiListener(listener);
|
||||
|
||||
this.renderSurface = renderSurface;
|
||||
this.renderSurface.attachToRenderer(this);
|
||||
this.flutterJNI.setRenderSurface(renderSurface);
|
||||
}
|
||||
|
||||
public void detachFromRenderSurface() {
|
||||
Log.v(TAG, "Detaching from RenderSurface.");
|
||||
// TODO(mattcarroll): determine desired behavior if we're asked to detach without first being attached
|
||||
if (this.renderSurface != null) {
|
||||
this.renderSurface.detachFromRenderer();
|
||||
this.renderSurface = null;
|
||||
surfaceDestroyed();
|
||||
this.flutterJNI.setRenderSurface(null);
|
||||
if (isDisplayingFlutterUi) {
|
||||
listener.onFlutterUiDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRenderedFirstFrame() {
|
||||
return hasRenderedFirstFrame;
|
||||
}
|
||||
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
flutterJNI.addOnFirstFrameRenderedListener(listener);
|
||||
|
||||
if (hasRenderedFirstFrame) {
|
||||
listener.onFirstFrameRendered();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
|
||||
flutterJNI.removeOnFirstFrameRenderedListener(listener);
|
||||
/**
|
||||
* Removes a listener added via
|
||||
* {@link #addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)}.
|
||||
*/
|
||||
public void removeIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener) {
|
||||
flutterJNI.removeIsDisplayingFlutterUiListener(listener);
|
||||
}
|
||||
|
||||
//------ START TextureRegistry IMPLEMENTATION -----
|
||||
// TODO(mattcarroll): detachFromGLContext requires API 16. Create solution for earlier APIs.
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
/**
|
||||
* Creates and returns a new {@link SurfaceTexture} that is also made available to Flutter code.
|
||||
*/
|
||||
@Override
|
||||
public SurfaceTextureEntry createSurfaceTexture() {
|
||||
Log.v(TAG, "Creating a SurfaceTexture.");
|
||||
@@ -180,19 +170,57 @@ public class FlutterRenderer implements TextureRegistry {
|
||||
}
|
||||
//------ END TextureRegistry IMPLEMENTATION ----
|
||||
|
||||
// TODO(mattcarroll): describe the native behavior that this invokes
|
||||
public void surfaceCreated(@NonNull Surface surface) {
|
||||
/**
|
||||
* Notifies Flutter that the given {@code surface} was created and is available for Flutter
|
||||
* rendering.
|
||||
* <p>
|
||||
* See {@link android.view.SurfaceHolder.Callback} and
|
||||
* {@link android.view.TextureView.SurfaceTextureListener}
|
||||
*/
|
||||
public void startRenderingToSurface(@NonNull Surface surface) {
|
||||
if (this.surface != null) {
|
||||
stopRenderingToSurface();
|
||||
}
|
||||
|
||||
this.surface = surface;
|
||||
|
||||
flutterJNI.onSurfaceCreated(surface);
|
||||
}
|
||||
|
||||
// TODO(mattcarroll): describe the native behavior that this invokes
|
||||
/**
|
||||
* Notifies Flutter that a {@code surface} previously registered with
|
||||
* {@link #startRenderingToSurface(Surface)} has changed size to the given {@code width} and
|
||||
* {@code height}.
|
||||
* <p>
|
||||
* See {@link android.view.SurfaceHolder.Callback} and
|
||||
* {@link android.view.TextureView.SurfaceTextureListener}
|
||||
*/
|
||||
public void surfaceChanged(int width, int height) {
|
||||
flutterJNI.onSurfaceChanged(width, height);
|
||||
}
|
||||
|
||||
// TODO(mattcarroll): describe the native behavior that this invokes
|
||||
public void surfaceDestroyed() {
|
||||
/**
|
||||
* Notifies Flutter that a {@code surface} previously registered with
|
||||
* {@link #startRenderingToSurface(Surface)} has been destroyed and needs to be released and
|
||||
* cleaned up on the Flutter side.
|
||||
* <p>
|
||||
* See {@link android.view.SurfaceHolder.Callback} and
|
||||
* {@link android.view.TextureView.SurfaceTextureListener}
|
||||
*/
|
||||
public void stopRenderingToSurface() {
|
||||
flutterJNI.onSurfaceDestroyed();
|
||||
|
||||
surface = null;
|
||||
|
||||
// TODO(mattcarroll): the source of truth for this call should be FlutterJNI, which is where
|
||||
// the call to onFlutterUiDisplayed() comes from. However, no such native callback exists yet,
|
||||
// so until the engine and FlutterJNI are configured to call us back when rendering stops,
|
||||
// we will manually monitor that change here.
|
||||
if (isDisplayingFlutterUi) {
|
||||
flutterUiDisplayListener.onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
|
||||
isDisplayingFlutterUi = false;
|
||||
}
|
||||
|
||||
// TODO(mattcarroll): describe the native behavior that this invokes
|
||||
@@ -279,61 +307,6 @@ public class FlutterRenderer implements TextureRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate used in conjunction with a {@link FlutterRenderer} to create an interactive Flutter
|
||||
* UI.
|
||||
*
|
||||
* A {@code RenderSurface} is responsible for carrying out behaviors that are needed by a
|
||||
* corresponding {@link FlutterRenderer}.
|
||||
*
|
||||
* A {@code RenderSurface} also receives callbacks for important events, e.g.,
|
||||
* {@link #onFirstFrameRendered()}.
|
||||
*/
|
||||
public interface RenderSurface {
|
||||
/**
|
||||
* Invoked by the owner of this {@code RenderSurface} when it wants to begin rendering
|
||||
* a Flutter UI to this {@code RenderSurface}.
|
||||
*
|
||||
* The details of how rendering is handled is an implementation detail.
|
||||
*/
|
||||
void attachToRenderer(@NonNull FlutterRenderer renderer);
|
||||
|
||||
/**
|
||||
* Invoked by the owner of this {@code RenderSurface} when it no longer wants to render
|
||||
* a Flutter UI to this {@code RenderSurface}.
|
||||
*
|
||||
* This method will cease any on-going rendering from Flutter to this {@code RenderSurface}.
|
||||
*/
|
||||
void detachFromRenderer();
|
||||
|
||||
// TODO(mattcarroll): convert old FlutterView to use FlutterEngine instead of individual
|
||||
// components, then use FlutterEngine's FlutterRenderer to watch for the first frame and
|
||||
// remove the following methods from this interface.
|
||||
/**
|
||||
* The {@link FlutterRenderer} corresponding to this {@code RenderSurface} has painted its
|
||||
* first frame since being initialized.
|
||||
*
|
||||
* "Initialized" refers to Flutter engine initialization, not the first frame after attaching
|
||||
* to the {@link FlutterRenderer}. Therefore, the first frame may have already rendered by
|
||||
* the time a {@code RenderSurface} has called {@link #attachToRenderSurface(RenderSurface)}
|
||||
* on a {@link FlutterRenderer}. In such a situation, {@code #onFirstFrameRendered()} will
|
||||
* never be called.
|
||||
*/
|
||||
void onFirstFrameRendered();
|
||||
|
||||
/**
|
||||
* Adds the given {@code listener} to this {@code FlutterRenderer}, to be notified upon Flutter's
|
||||
* first rendered frame.
|
||||
*/
|
||||
void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener);
|
||||
|
||||
/**
|
||||
* Removes the given {@code listener}, which was previously added with
|
||||
* {@link #addOnFirstFrameRenderedListener(OnFirstFrameRenderedListener)}.
|
||||
*/
|
||||
void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable data structure that holds all viewport metrics properties that Flutter cares about.
|
||||
*
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package io.flutter.embedding.engine.renderer;
|
||||
|
||||
/**
|
||||
* Listener invoked when Flutter starts and stops rendering pixels to an Android {@code View}
|
||||
* hierarchy.
|
||||
*/
|
||||
public interface FlutterUiDisplayListener {
|
||||
/**
|
||||
* Flutter started painting pixels to an Android {@code View} hierarchy.
|
||||
* <p>
|
||||
* This method will not be invoked if this listener is added after the {@link FlutterRenderer}
|
||||
* has started painting pixels.
|
||||
*/
|
||||
void onFlutterUiDisplayed();
|
||||
|
||||
/**
|
||||
* Flutter stopped painting pixels to an Android {@code View} hierarchy.
|
||||
*/
|
||||
void onFlutterUiNoLongerDisplayed();
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package io.flutter.embedding.engine.renderer;
|
||||
|
||||
/**
|
||||
* Listener invoked after Flutter paints its first frame since being initialized.
|
||||
*
|
||||
* WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
|
||||
* IF YOU USE IT, WE WILL BREAK YOU.
|
||||
*/
|
||||
public interface OnFirstFrameRenderedListener {
|
||||
/**
|
||||
* A {@link FlutterRenderer} has painted its first frame since being initialized.
|
||||
*
|
||||
* This method will not be invoked if this listener is added after the first frame is rendered.
|
||||
*/
|
||||
void onFirstFrameRendered();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package io.flutter.embedding.engine.renderer;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.Surface;
|
||||
|
||||
/**
|
||||
* Owns a {@code Surface} that {@code FlutterRenderer} would like to paint.
|
||||
* <p>
|
||||
* {@code RenderSurface} is responsible for providing a {@code Surface} to a given
|
||||
* {@code FlutterRenderer} when requested, and then notify that {@code FlutterRenderer} when
|
||||
* the {@code Surface} changes, or is destroyed.
|
||||
* <p>
|
||||
* The behavior of providing a {@code Surface} is delegated to this interface because the timing
|
||||
* of a {@code Surface}'s availability is determined by Android. Therefore, an accessor method
|
||||
* would not fulfill the requirements. Therefore, a {@code RenderSurface} is given a
|
||||
* {@code FlutterRenderer}, which the {@code RenderSurface} is expected to notify as a
|
||||
* {@code Surface} becomes available, changes, or is destroyed.
|
||||
*/
|
||||
public interface RenderSurface {
|
||||
/**
|
||||
* Returns the {@code FlutterRenderer} that is attached to this {@code RenderSurface}, or
|
||||
* null if no {@code FlutterRenderer} is currently attached.
|
||||
*/
|
||||
@Nullable
|
||||
FlutterRenderer getAttachedRenderer();
|
||||
|
||||
/**
|
||||
* Instructs this {@code RenderSurface} to give its {@code Surface} to the given
|
||||
* {@code FlutterRenderer} so that Flutter can paint pixels on it.
|
||||
* <p>
|
||||
* After this call, {@code RenderSurface} is expected to invoke the following methods on
|
||||
* {@link FlutterRenderer} at the appropriate times:
|
||||
* <ol>
|
||||
* <li>{@link FlutterRenderer#startRenderingToSurface(Surface)}</li>
|
||||
* <li>{@link FlutterRenderer#surfaceChanged(int, int)}}</li>
|
||||
* <li>{@link FlutterRenderer#stopRenderingToSurface()}</li>
|
||||
* </ol>
|
||||
*/
|
||||
void attachToRenderer(@NonNull FlutterRenderer renderer);
|
||||
|
||||
/**
|
||||
* Instructs this {@code RenderSurface} to stop forwarding {@code Surface} notifications to the
|
||||
* {@code FlutterRenderer} that was previously connected with
|
||||
* {@link #attachToRenderer(FlutterRenderer)}.
|
||||
* <p>
|
||||
* This {@code RenderSurface} should also clean up any references related to the previously
|
||||
* connected {@code FlutterRenderer}.
|
||||
*/
|
||||
void detachFromRenderer();
|
||||
}
|
||||
@@ -13,16 +13,9 @@ import io.flutter.app.FlutterPluginRegistry;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener;
|
||||
import io.flutter.embedding.engine.dart.DartExecutor;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface;
|
||||
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
|
||||
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
|
||||
import io.flutter.plugin.common.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.embedding.engine.dart.PlatformMessageHandler;
|
||||
|
||||
public class FlutterNativeView implements BinaryMessenger {
|
||||
private static final String TAG = "FlutterNativeView";
|
||||
@@ -34,6 +27,21 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
private final Context mContext;
|
||||
private boolean applicationIsRunning;
|
||||
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener = new FlutterUiDisplayListener() {
|
||||
@Override
|
||||
public void onFlutterUiDisplayed() {
|
||||
if (mFlutterView == null) {
|
||||
return;
|
||||
}
|
||||
mFlutterView.onFirstFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlutterUiNoLongerDisplayed() {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
public FlutterNativeView(@NonNull Context context) {
|
||||
this(context, false);
|
||||
}
|
||||
@@ -42,7 +50,7 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
mContext = context;
|
||||
mPluginRegistry = new FlutterPluginRegistry(this, context);
|
||||
mFlutterJNI = new FlutterJNI();
|
||||
mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
|
||||
mFlutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
this.dartExecutor = new DartExecutor(mFlutterJNI, context.getAssets());
|
||||
mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
|
||||
attach(this, isBackgroundView);
|
||||
@@ -58,6 +66,7 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
mPluginRegistry.destroy();
|
||||
dartExecutor.onDetachedFromJNI();
|
||||
mFlutterView = null;
|
||||
mFlutterJNI.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
|
||||
mFlutterJNI.detachFromNativeAndReleaseResources();
|
||||
applicationIsRunning = false;
|
||||
}
|
||||
@@ -143,48 +152,6 @@ public class FlutterNativeView implements BinaryMessenger {
|
||||
dartExecutor.onAttachedToJNI();
|
||||
}
|
||||
|
||||
private final class RenderSurfaceImpl implements RenderSurface {
|
||||
@Override
|
||||
public void attachToRenderer(@NonNull FlutterRenderer renderer) {
|
||||
// Not relevant for v1 embedding.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachFromRenderer() {
|
||||
// Not relevant for v1 embedding.
|
||||
}
|
||||
|
||||
// Called by native to update the semantics/accessibility tree.
|
||||
public void updateSemantics(ByteBuffer buffer, String[] strings) {
|
||||
if (mFlutterView == null) {
|
||||
return;
|
||||
}
|
||||
mFlutterView.updateSemantics(buffer, strings);
|
||||
}
|
||||
|
||||
// Called by native to update the custom accessibility actions.
|
||||
public void updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings) {
|
||||
if (mFlutterView == null) {
|
||||
return;
|
||||
}
|
||||
mFlutterView.updateCustomAccessibilityActions(buffer, strings);
|
||||
}
|
||||
|
||||
// Called by native to notify first Flutter frame rendered.
|
||||
public void onFirstFrameRendered() {
|
||||
if (mFlutterView == null) {
|
||||
return;
|
||||
}
|
||||
mFlutterView.onFirstFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {}
|
||||
|
||||
@Override
|
||||
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {}
|
||||
}
|
||||
|
||||
private final class EngineLifecycleListenerImpl implements EngineLifecycleListener {
|
||||
// Called by native to notify when the engine is restarted (cold reload).
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -679,29 +679,6 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
);
|
||||
}
|
||||
|
||||
// Called by native to update the semantics/accessibility tree.
|
||||
public void updateSemantics(ByteBuffer buffer, String[] strings) {
|
||||
try {
|
||||
if (mAccessibilityNodeProvider != null) {
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
mAccessibilityNodeProvider.updateSemantics(buffer, strings);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Uncaught exception while updating semantics", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCustomAccessibilityActions(ByteBuffer buffer, String[] strings) {
|
||||
try {
|
||||
if (mAccessibilityNodeProvider != null) {
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
mAccessibilityNodeProvider.updateCustomAccessibilityActions(buffer, strings);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Uncaught exception while updating local context actions", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by FlutterNativeView to notify first Flutter frame rendered.
|
||||
public void onFirstFrame() {
|
||||
didRenderFirstFrame = true;
|
||||
|
||||
@@ -6,6 +6,7 @@ package io.flutter.view;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
|
||||
// TODO(mattcarroll): re-evalute docs in this class and add nullability annotations.
|
||||
/**
|
||||
* Registry of backend textures used with a single {@link FlutterView} instance.
|
||||
* Entries may be embedded into the Flutter view using the
|
||||
|
||||
@@ -486,7 +486,7 @@ static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env,
|
||||
|
||||
bool RegisterApi(JNIEnv* env) {
|
||||
static const JNINativeMethod flutter_jni_methods[] = {
|
||||
// Start of methods from FlutterNativeView
|
||||
// Start of methods from FlutterJNI
|
||||
{
|
||||
.name = "nativeAttach",
|
||||
.signature = "(Lio/flutter/embedding/engine/FlutterJNI;Z)J",
|
||||
|
||||
@@ -13,7 +13,10 @@ import io.flutter.embedding.android.FlutterActivityTest;
|
||||
import io.flutter.embedding.android.FlutterFragmentTest;
|
||||
import io.flutter.embedding.engine.FlutterEngineCacheTest;
|
||||
import io.flutter.embedding.engine.systemchannels.PlatformChannelTest;
|
||||
import io.flutter.embedding.engine.RenderingComponentTest;
|
||||
import io.flutter.embedding.engine.renderer.FlutterRendererTest;
|
||||
import io.flutter.util.PreconditionsTest;
|
||||
import io.flutter.embedding.engine.FlutterJNITest;
|
||||
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({
|
||||
@@ -23,6 +26,9 @@ import io.flutter.util.PreconditionsTest;
|
||||
FlutterFragmentTest.class,
|
||||
// FlutterActivityAndFragmentDelegateTest.class, TODO(mklim): Fix and re-enable this
|
||||
FlutterEngineCacheTest.class,
|
||||
FlutterJNITest.class,
|
||||
RenderingComponentTest.class,
|
||||
FlutterRendererTest.class,
|
||||
PlatformChannelTest.class
|
||||
})
|
||||
/** Runs all of the unit tests listed in the {@code @SuiteClasses} annotation. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user