Exposes FlutterSurfaceView, and FlutterTextureView to FlutterActivity and FlutterFragment. (#41984, #47557) (flutter/engine#16552)

This commit is contained in:
Matt Carroll 2020-02-12 19:21:00 -08:00 committed by GitHub
parent ef030acc55
commit bd50ab762a
14 changed files with 396 additions and 172 deletions

View File

@ -655,8 +655,10 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flutt
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/RenderMode.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/SplashScreen.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/SplashScreenProvider.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/TransparencyMode.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngineCache.java
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java

View File

@ -138,8 +138,10 @@ android_java_sources = [
"io/flutter/embedding/android/FlutterSurfaceView.java",
"io/flutter/embedding/android/FlutterTextureView.java",
"io/flutter/embedding/android/FlutterView.java",
"io/flutter/embedding/android/RenderMode.java",
"io/flutter/embedding/android/SplashScreen.java",
"io/flutter/embedding/android/SplashScreenProvider.java",
"io/flutter/embedding/android/TransparencyMode.java",
"io/flutter/embedding/engine/FlutterEngine.java",
"io/flutter/embedding/engine/FlutterEngineCache.java",
"io/flutter/embedding/engine/FlutterEnginePluginRegistry.java",

View File

@ -782,28 +782,26 @@ public class FlutterActivity extends Activity
/**
* {@link FlutterActivityAndFragmentDelegate.Host} method that is used by {@link
* FlutterActivityAndFragmentDelegate} to obtain the desired {@link FlutterView.RenderMode} that
* should be used when instantiating a {@link FlutterView}.
* FlutterActivityAndFragmentDelegate} to obtain the desired {@link RenderMode} that should be
* used when instantiating a {@link FlutterView}.
*/
@NonNull
@Override
public FlutterView.RenderMode getRenderMode() {
return getBackgroundMode() == BackgroundMode.opaque
? FlutterView.RenderMode.surface
: FlutterView.RenderMode.texture;
public RenderMode getRenderMode() {
return getBackgroundMode() == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
}
/**
* {@link FlutterActivityAndFragmentDelegate.Host} method that is used by {@link
* FlutterActivityAndFragmentDelegate} to obtain the desired {@link FlutterView.TransparencyMode}
* that should be used when instantiating a {@link FlutterView}.
* FlutterActivityAndFragmentDelegate} to obtain the desired {@link TransparencyMode} that should
* be used when instantiating a {@link FlutterView}.
*/
@NonNull
@Override
public FlutterView.TransparencyMode getTransparencyMode() {
public TransparencyMode getTransparencyMode() {
return getBackgroundMode() == BackgroundMode.opaque
? FlutterView.TransparencyMode.opaque
: FlutterView.TransparencyMode.transparent;
? TransparencyMode.opaque
: TransparencyMode.transparent;
}
/**
@ -917,6 +915,16 @@ public class FlutterActivity extends Activity
return true;
}
@Override
public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {
// Hook for subclasses.
}
@Override
public void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView) {
// Hook for subclasses.
}
@Override
public void onFlutterUiDisplayed() {
// Notifies Android that we're fully drawn so that performance metrics can be collected by

View File

@ -251,8 +251,28 @@ import java.util.Arrays;
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.v(TAG, "Creating FlutterView.");
ensureAlive();
flutterView =
new FlutterView(host.getActivity(), host.getRenderMode(), host.getTransparencyMode());
if (host.getRenderMode() == RenderMode.surface) {
FlutterSurfaceView flutterSurfaceView =
new FlutterSurfaceView(
host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
// Allow our host to customize FlutterSurfaceView, if desired.
host.onFlutterSurfaceViewCreated(flutterSurfaceView);
// Create the FlutterView that owns the FlutterSurfaceView.
flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
} else {
FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
// Allow our host to customize FlutterSurfaceView, if desired.
host.onFlutterTextureViewCreated(flutterTextureView);
// Create the FlutterView that owns the FlutterTextureView.
flutterView = new FlutterView(host.getActivity(), flutterTextureView);
}
// Add listener to be notified when Flutter renders its first frame.
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
flutterSplashView = new FlutterSplashView(host.getContext());
@ -702,18 +722,18 @@ import java.util.Arrays;
String getInitialRoute();
/**
* Returns the {@link FlutterView.RenderMode} used by the {@link FlutterView} that displays the
* {@link FlutterEngine}'s content.
* Returns the {@link RenderMode} used by the {@link FlutterView} that displays the {@link
* FlutterEngine}'s content.
*/
@NonNull
FlutterView.RenderMode getRenderMode();
RenderMode getRenderMode();
/**
* Returns the {@link FlutterView.TransparencyMode} used by the {@link FlutterView} that
* displays the {@link FlutterEngine}'s content.
* Returns the {@link TransparencyMode} used by the {@link FlutterView} that displays the {@link
* FlutterEngine}'s content.
*/
@NonNull
FlutterView.TransparencyMode getTransparencyMode();
TransparencyMode getTransparencyMode();
@Nullable
SplashScreen provideSplashScreen();
@ -749,6 +769,36 @@ import java.util.Arrays;
*/
boolean shouldAttachEngineToActivity();
/**
* Invoked by this delegate when the {@link FlutterSurfaceView} that renders the Flutter UI is
* initially instantiated.
*
* <p>This method is only invoked if the {@link
* io.flutter.embedding.android.FlutterView.RenderMode} is set to {@link
* io.flutter.embedding.android.FlutterView.RenderMode#surface}. Otherwise, {@link
* #onFlutterTextureViewCreated(FlutterTextureView)} is invoked.
*
* <p>This method is invoked before the given {@link FlutterSurfaceView} is attached to the
* {@code View} hierarchy. Implementers should not attempt to climb the {@code View} hierarchy
* or make assumptions about relationships with other {@code View}s.
*/
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView);
/**
* Invoked by this delegate when the {@link FlutterTextureView} that renders the Flutter UI is
* initially instantiated.
*
* <p>This method is only invoked if the {@link
* io.flutter.embedding.android.FlutterView.RenderMode} is set to {@link
* io.flutter.embedding.android.FlutterView.RenderMode#texture}. Otherwise, {@link
* #onFlutterSurfaceViewCreated(FlutterSurfaceView)} is invoked.
*
* <p>This method is invoked before the given {@link FlutterTextureView} is attached to the
* {@code View} hierarchy. Implementers should not attempt to climb the {@code View} hierarchy
* or make assumptions about relationships with other {@code View}s.
*/
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView);
/** Invoked by this delegate when its {@link FlutterView} starts painting pixels. */
void onFlutterUiDisplayed();

View File

@ -68,9 +68,11 @@ import io.flutter.view.FlutterMain;
* <p>The following illustrates how to pre-warm and cache a {@link FlutterEngine}:
*
* <pre>{@code
* // Create and pre-warm a FlutterEngine. FlutterEngine flutterEngine = new
* FlutterEngine(context);
* flutterEngine.getDartExecutor().executeDartEntrypoint(DartEntrypoint.createDefault());
* // Create and pre-warm a FlutterEngine.
* FlutterEngine flutterEngine = new FlutterEngine(context);
* flutterEngine
* .getDartExecutor()
* .executeDartEntrypoint(DartEntrypoint.createDefault());
*
* // Cache the pre-warmed FlutterEngine in the FlutterEngineCache.
* FlutterEngineCache.getInstance().put("my_engine", flutterEngine);
@ -91,14 +93,10 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
protected static final String ARG_APP_BUNDLE_PATH = "app_bundle_path";
/** Flutter shell arguments. */
protected static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args";
/**
* {@link FlutterView.RenderMode} to be used for the {@link FlutterView} in this {@code
* FlutterFragment}
*/
/** {@link RenderMode} to be used for the {@link FlutterView} in this {@code FlutterFragment} */
protected static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode";
/**
* {@link FlutterView.TransparencyMode} to be used for the {@link FlutterView} in this {@code
* FlutterFragment}
* {@link TransparencyMode} to be used for the {@link FlutterView} in this {@code FlutterFragment}
*/
protected static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode";
/** See {@link #shouldAttachEngineToActivity()}. */
@ -185,9 +183,8 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
private String initialRoute = "/";
private String appBundlePath = null;
private FlutterShellArgs shellArgs = null;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface;
private FlutterView.TransparencyMode transparencyMode =
FlutterView.TransparencyMode.transparent;
private RenderMode renderMode = RenderMode.surface;
private TransparencyMode transparencyMode = TransparencyMode.transparent;
private boolean shouldAttachEngineToActivity = true;
/**
@ -241,27 +238,25 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
}
/**
* Render Flutter either as a {@link FlutterView.RenderMode#surface} or a {@link
* FlutterView.RenderMode#texture}. You should use {@code surface} unless you have a specific
* reason to use {@code texture}. {@code texture} comes with a significant performance impact,
* but {@code texture} can be displayed beneath other Android {@code View}s and animated,
* whereas {@code surface} cannot.
* Render Flutter either as a {@link RenderMode#surface} or a {@link RenderMode#texture}. You
* should use {@code surface} unless you have a specific reason to use {@code texture}. {@code
* texture} comes with a significant performance impact, but {@code texture} can be displayed
* beneath other Android {@code View}s and animated, whereas {@code surface} cannot.
*/
@NonNull
public NewEngineFragmentBuilder renderMode(@NonNull FlutterView.RenderMode renderMode) {
public NewEngineFragmentBuilder renderMode(@NonNull RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
/**
* Support a {@link FlutterView.TransparencyMode#transparent} background within {@link
* FlutterView}, or force an {@link FlutterView.TransparencyMode#opaque} background.
* Support a {@link TransparencyMode#transparent} background within {@link FlutterView}, or
* force an {@link TransparencyMode#opaque} background.
*
* <p>See {@link FlutterView.TransparencyMode} for implications of this selection.
* <p>See {@link TransparencyMode} for implications of this selection.
*/
@NonNull
public NewEngineFragmentBuilder transparencyMode(
@NonNull FlutterView.TransparencyMode transparencyMode) {
public NewEngineFragmentBuilder transparencyMode(@NonNull TransparencyMode transparencyMode) {
this.transparencyMode = transparencyMode;
return this;
}
@ -326,12 +321,10 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
}
args.putString(
ARG_FLUTTERVIEW_RENDER_MODE,
renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
renderMode != null ? renderMode.name() : RenderMode.surface.name());
args.putString(
ARG_FLUTTERVIEW_TRANSPARENCY_MODE,
transparencyMode != null
? transparencyMode.name()
: FlutterView.TransparencyMode.transparent.name());
transparencyMode != null ? transparencyMode.name() : TransparencyMode.transparent.name());
args.putBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY, shouldAttachEngineToActivity);
args.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, true);
return args;
@ -412,9 +405,8 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
private final Class<? extends FlutterFragment> fragmentClass;
private final String engineId;
private boolean destroyEngineWithFragment = false;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface;
private FlutterView.TransparencyMode transparencyMode =
FlutterView.TransparencyMode.transparent;
private RenderMode renderMode = RenderMode.surface;
private TransparencyMode transparencyMode = TransparencyMode.transparent;
private boolean shouldAttachEngineToActivity = true;
private CachedEngineFragmentBuilder(@NonNull String engineId) {
@ -440,27 +432,26 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
}
/**
* Render Flutter either as a {@link FlutterView.RenderMode#surface} or a {@link
* FlutterView.RenderMode#texture}. You should use {@code surface} unless you have a specific
* reason to use {@code texture}. {@code texture} comes with a significant performance impact,
* but {@code texture} can be displayed beneath other Android {@code View}s and animated,
* whereas {@code surface} cannot.
* Render Flutter either as a {@link RenderMode#surface} or a {@link RenderMode#texture}. You
* should use {@code surface} unless you have a specific reason to use {@code texture}. {@code
* texture} comes with a significant performance impact, but {@code texture} can be displayed
* beneath other Android {@code View}s and animated, whereas {@code surface} cannot.
*/
@NonNull
public CachedEngineFragmentBuilder renderMode(@NonNull FlutterView.RenderMode renderMode) {
public CachedEngineFragmentBuilder renderMode(@NonNull RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
/**
* Support a {@link FlutterView.TransparencyMode#transparent} background within {@link
* FlutterView}, or force an {@link FlutterView.TransparencyMode#opaque} background.
* Support a {@link TransparencyMode#transparent} background within {@link FlutterView}, or
* force an {@link TransparencyMode#opaque} background.
*
* <p>See {@link FlutterView.TransparencyMode} for implications of this selection.
* <p>See {@link TransparencyMode} for implications of this selection.
*/
@NonNull
public CachedEngineFragmentBuilder transparencyMode(
@NonNull FlutterView.TransparencyMode transparencyMode) {
@NonNull TransparencyMode transparencyMode) {
this.transparencyMode = transparencyMode;
return this;
}
@ -519,12 +510,10 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
args.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, destroyEngineWithFragment);
args.putString(
ARG_FLUTTERVIEW_RENDER_MODE,
renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
renderMode != null ? renderMode.name() : RenderMode.surface.name());
args.putString(
ARG_FLUTTERVIEW_TRANSPARENCY_MODE,
transparencyMode != null
? transparencyMode.name()
: FlutterView.TransparencyMode.transparent.name());
transparencyMode != null ? transparencyMode.name() : TransparencyMode.transparent.name());
args.putBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY, shouldAttachEngineToActivity);
return args;
}
@ -832,38 +821,36 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
}
/**
* Returns the desired {@link FlutterView.RenderMode} for the {@link FlutterView} displayed in
* this {@code FlutterFragment}.
* Returns the desired {@link RenderMode} for the {@link FlutterView} displayed in this {@code
* FlutterFragment}.
*
* <p>Defaults to {@link FlutterView.RenderMode#surface}.
* <p>Defaults to {@link RenderMode#surface}.
*
* <p>Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public FlutterView.RenderMode getRenderMode() {
public RenderMode getRenderMode() {
String renderModeName =
getArguments()
.getString(ARG_FLUTTERVIEW_RENDER_MODE, FlutterView.RenderMode.surface.name());
return FlutterView.RenderMode.valueOf(renderModeName);
getArguments().getString(ARG_FLUTTERVIEW_RENDER_MODE, RenderMode.surface.name());
return RenderMode.valueOf(renderModeName);
}
/**
* Returns the desired {@link FlutterView.TransparencyMode} for the {@link FlutterView} displayed
* in this {@code FlutterFragment}.
* Returns the desired {@link TransparencyMode} for the {@link FlutterView} displayed in this
* {@code FlutterFragment}.
*
* <p>Defaults to {@link FlutterView.TransparencyMode#transparent}.
* <p>Defaults to {@link TransparencyMode#transparent}.
*
* <p>Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public FlutterView.TransparencyMode getTransparencyMode() {
public TransparencyMode getTransparencyMode() {
String transparencyModeName =
getArguments()
.getString(
ARG_FLUTTERVIEW_TRANSPARENCY_MODE, FlutterView.TransparencyMode.transparent.name());
return FlutterView.TransparencyMode.valueOf(transparencyModeName);
.getString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, TransparencyMode.transparent.name());
return TransparencyMode.valueOf(transparencyModeName);
}
@Override
@ -983,6 +970,16 @@ public class FlutterFragment extends Fragment implements FlutterActivityAndFragm
return getArguments().getBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY);
}
@Override
public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {
// Hook for subclasses.
}
@Override
public void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView) {
// Hook for subclasses.
}
/**
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} starts rendering
* pixels to the screen.

View File

@ -399,14 +399,12 @@ public class FlutterFragmentActivity extends FragmentActivity
@NonNull
protected FlutterFragment createFlutterFragment() {
BackgroundMode backgroundMode = getBackgroundMode();
FlutterView.RenderMode renderMode =
RenderMode renderMode =
backgroundMode == BackgroundMode.opaque ? RenderMode.surface : RenderMode.texture;
TransparencyMode transparencyMode =
backgroundMode == BackgroundMode.opaque
? FlutterView.RenderMode.surface
: FlutterView.RenderMode.texture;
FlutterView.TransparencyMode transparencyMode =
backgroundMode == BackgroundMode.opaque
? FlutterView.TransparencyMode.opaque
: FlutterView.TransparencyMode.transparent;
? TransparencyMode.opaque
: TransparencyMode.transparent;
if (getCachedEngineId() != null) {
Log.v(

View File

@ -47,21 +47,23 @@ import java.util.Set;
*
* <p>A {@code FlutterView}'s UI is painted by a corresponding {@link FlutterEngine}.
*
* <p>A {@code FlutterView} can operate in 2 different {@link RenderMode}s:
* <p>A {@code FlutterView} can operate in 2 different {@link
* io.flutter.embedding.android.RenderMode}s:
*
* <ol>
* <li>{@link RenderMode#surface}, which paints a Flutter UI to a {@link
* android.view.SurfaceView}. This mode has the best performance, but a {@code FlutterView} in
* this mode cannot be positioned between 2 other Android {@code View}s in the z-index, nor
* can it be animated/transformed. Unless the special capabilities of a {@link
* <li>{@link io.flutter.embedding.android.RenderMode#surface}, which paints a Flutter UI to a
* {@link android.view.SurfaceView}. This mode has the best performance, but a {@code
* FlutterView} in this mode cannot be positioned between 2 other Android {@code View}s in the
* z-index, nor can it be animated/transformed. Unless the special capabilities of a {@link
* android.graphics.SurfaceTexture} are required, developers should strongly prefer this
* render mode.
* <li>{@link RenderMode#texture}, which paints a Flutter UI to a {@link
* android.graphics.SurfaceTexture}. This mode is not as performant as {@link
* RenderMode#surface}, but a {@code FlutterView} in this mode can be animated and
* transformed, as well as positioned in the z-index between 2+ other Android {@code Views}.
* Unless the special capabilities of a {@link android.graphics.SurfaceTexture} are required,
* developers should strongly prefer the {@link RenderMode#surface} render mode.
* <li>{@link io.flutter.embedding.android.RenderMode#texture}, which paints a Flutter UI to a
* {@link android.graphics.SurfaceTexture}. This mode is not as performant as {@link
* io.flutter.embedding.android.RenderMode#surface}, but a {@code FlutterView} in this mode
* can be animated and transformed, as well as positioned in the z-index between 2+ other
* Android {@code Views}. Unless the special capabilities of a {@link
* android.graphics.SurfaceTexture} are required, developers should strongly prefer the {@link
* io.flutter.embedding.android.RenderMode#surface} render mode.
* </ol>
*
* See <a>https://source.android.com/devices/graphics/arch-tv#surface_or_texture</a> for more
@ -70,11 +72,9 @@ import java.util.Set;
public class FlutterView extends FrameLayout {
private static final String TAG = "FlutterView";
// Behavior configuration of this FlutterView.
@NonNull private RenderMode renderMode;
@Nullable private TransparencyMode transparencyMode;
// Internal view hierarchy references.
@Nullable private FlutterSurfaceView flutterSurfaceView;
@Nullable private FlutterTextureView flutterTextureView;
@Nullable private RenderSurface renderSurface;
private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners = new HashSet<>();
private boolean isFlutterUiDisplayed;
@ -136,75 +136,135 @@ public class FlutterView extends FrameLayout {
* <p>
*
* <ul>
* <li>{@link #renderMode} defaults to {@link RenderMode#surface}.
* <li>{@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.
* <li>A {@link FlutterSurfaceView} is used to render the Flutter UI.
* <li>{@code transparencyMode} defaults to {@link TransparencyMode#opaque}.
* </ul>
*
* {@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
*/
public FlutterView(@NonNull Context context) {
this(context, null, null, null);
this(context, null, new FlutterSurfaceView(context));
}
/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes, and allows
* selection of a {@link #renderMode}.
*
* <p>{@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.
*
* <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
* Deprecated - use {@link #FlutterView(Context, FlutterSurfaceView)} or {@link
* #FlutterView(Context, FlutterTextureView)} instead.
*/
@Deprecated
public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) {
this(context, null, renderMode, null);
super(context, null);
if (renderMode == RenderMode.surface) {
flutterSurfaceView = new FlutterSurfaceView(context);
renderSurface = flutterSurfaceView;
} else {
flutterTextureView = new FlutterTextureView(context);
renderSurface = flutterTextureView;
}
init();
}
/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes, assumes the use
* of {@link RenderMode#surface}, and allows selection of a {@link #transparencyMode}.
* Deprecated - use {@link #FlutterView(Context, FlutterSurfaceView)} or {@link
* #FlutterView(Context, FlutterTextureView)} instead, and configure the incoming {@code
* FlutterSurfaceView} or {@code FlutterTextureView} for transparency as desired.
*
* <p>Constructs a {@code FlutterView} programmatically, without any XML attributes, uses a {@link
* FlutterSurfaceView} to render the Flutter UI, and allows selection of a {@code
* transparencyMode}.
*
* <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
*/
@Deprecated
public FlutterView(@NonNull Context context, @NonNull TransparencyMode transparencyMode) {
this(context, null, RenderMode.surface, transparencyMode);
this(
context,
null,
new FlutterSurfaceView(context, transparencyMode == TransparencyMode.transparent));
}
/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes, and allows a
* selection of {@link #renderMode} and {@link #transparencyMode}.
* Constructs a {@code FlutterView} programmatically, without any XML attributes, uses the given
* {@link FlutterSurfaceView} to render the Flutter UI, and allows selection of a {@code
* transparencyMode}.
*
* <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
*/
public FlutterView(
@NonNull Context context,
@NonNull RenderMode renderMode,
@NonNull TransparencyMode transparencyMode) {
this(context, null, renderMode, transparencyMode);
public FlutterView(@NonNull Context context, @NonNull FlutterSurfaceView flutterSurfaceView) {
this(context, null, flutterSurfaceView);
}
/**
* Constructs a {@code FlutterSurfaceView} in an XML-inflation-compliant manner.
* Constructs a {@code FlutterView} programmatically, without any XML attributes, uses the given
* {@link FlutterTextureView} to render the Flutter UI, and allows selection of a {@code
* transparencyMode}.
*
* <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
*/
public FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutterTextureView) {
this(context, null, flutterTextureView);
}
/**
* Constructs a {@code FlutterView} in an XML-inflation-compliant manner.
*
* <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be
* compatible with {@link PlatformViewsController}.
*/
// TODO(mattcarroll): expose renderMode in XML when build system supports R.attr
public FlutterView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, null, null);
this(context, attrs, new FlutterSurfaceView(context));
}
/**
* Deprecated - use {@link #FlutterView(Context, FlutterSurfaceView)} or {@link
* #FlutterView(Context, FlutterTextureView)} instead, and configure the incoming {@code
* FlutterSurfaceView} or {@code FlutterTextureView} for transparency as desired.
*/
@Deprecated
public FlutterView(
@NonNull Context context,
@NonNull RenderMode renderMode,
@NonNull TransparencyMode transparencyMode) {
super(context, null);
if (renderMode == RenderMode.surface) {
flutterSurfaceView =
new FlutterSurfaceView(context, transparencyMode == TransparencyMode.transparent);
renderSurface = flutterSurfaceView;
} else {
flutterTextureView = new FlutterTextureView(context);
renderSurface = flutterTextureView;
}
init();
}
private FlutterView(
@NonNull Context context,
@Nullable AttributeSet attrs,
@Nullable RenderMode renderMode,
@Nullable TransparencyMode transparencyMode) {
@NonNull FlutterSurfaceView flutterSurfaceView) {
super(context, attrs);
this.renderMode = renderMode == null ? RenderMode.surface : renderMode;
this.transparencyMode = transparencyMode != null ? transparencyMode : TransparencyMode.opaque;
this.flutterSurfaceView = flutterSurfaceView;
this.renderSurface = flutterSurfaceView;
init();
}
private FlutterView(
@NonNull Context context,
@Nullable AttributeSet attrs,
@NonNull FlutterTextureView flutterTextureView) {
super(context, attrs);
this.flutterTextureView = flutterTextureView;
this.renderSurface = flutterSurfaceView;
init();
}
@ -212,20 +272,12 @@ public class FlutterView extends FrameLayout {
private void init() {
Log.v(TAG, "Initializing FlutterView");
switch (renderMode) {
case surface:
Log.v(TAG, "Internally using a FlutterSurfaceView.");
FlutterSurfaceView flutterSurfaceView =
new FlutterSurfaceView(getContext(), transparencyMode == TransparencyMode.transparent);
renderSurface = flutterSurfaceView;
addView(flutterSurfaceView);
break;
case texture:
Log.v(TAG, "Internally using a FlutterTextureView.");
FlutterTextureView flutterTextureView = new FlutterTextureView(getContext());
renderSurface = flutterTextureView;
addView(flutterTextureView);
break;
if (flutterSurfaceView != null) {
Log.v(TAG, "Internally using a FlutterSurfaceView.");
addView(flutterSurfaceView);
} else {
Log.v(TAG, "Internally using a FlutterTextureView.");
addView(flutterTextureView);
}
// FlutterView needs to be focusable so that the InputMethodManager can interact with it.
@ -846,7 +898,12 @@ public class FlutterView extends FrameLayout {
flutterEngine.getRenderer().setViewportMetrics(viewportMetrics);
}
/** Render modes for a {@link FlutterView}. */
/**
* Render modes for a {@link FlutterView}.
*
* <p>Deprecated - please use {@link io.flutter.embedding.android.RenderMode} instead.
*/
@Deprecated()
public enum RenderMode {
/**
* {@code RenderMode}, which paints a Flutter UI to a {@link android.view.SurfaceView}. This
@ -870,6 +927,8 @@ public class FlutterView extends FrameLayout {
/**
* Transparency mode for a {@code FlutterView}.
*
* <p>Deprecated - please use {@link io.flutter.embedding.android.TransparencyMode} instead.
*
* <p>{@code TransparencyMode} impacts the visual behavior and performance of a {@link
* FlutterSurfaceView}, which is displayed when a {@code FlutterView} uses {@link
* RenderMode#surface}.
@ -878,27 +937,29 @@ public class FlutterView extends FrameLayout {
* a {@code FlutterView} uses {@link RenderMode#texture}, because a {@link FlutterTextureView}
* automatically comes with transparency.
*/
@Deprecated
public enum TransparencyMode {
/**
* Renders a {@code FlutterView} without any transparency. This affects {@code FlutterView}s in
* {@link RenderMode#surface} by introducing a base color of black, and places the {@link
* FlutterSurfaceView}'s {@code Window} behind all other content.
* {@link io.flutter.embedding.android.RenderMode#surface} by introducing a base color of black,
* and places the {@link FlutterSurfaceView}'s {@code Window} behind all other content.
*
* <p>In {@link RenderMode#surface}, this mode is the most performant and is a good choice for
* fullscreen Flutter UIs that will not undergo {@code Fragment} transactions. If this mode is
* used within a {@code Fragment}, and that {@code Fragment} is replaced by another one, a brief
* black flicker may be visible during the switch.
* <p>In {@link io.flutter.embedding.android.RenderMode#surface}, this mode is the most
* performant and is a good choice for fullscreen Flutter UIs that will not undergo {@code
* Fragment} transactions. If this mode is used within a {@code Fragment}, and that {@code
* Fragment} is replaced by another one, a brief black flicker may be visible during the switch.
*/
opaque,
/**
* Renders a {@code FlutterView} with transparency. This affects {@code FlutterView}s in {@link
* RenderMode#surface} by allowing background transparency, and places the {@link
* FlutterSurfaceView}'s {@code Window} on top of all other content.
* io.flutter.embedding.android.RenderMode#surface} by allowing background transparency, and
* places the {@link FlutterSurfaceView}'s {@code Window} on top of all other content.
*
* <p>In {@link RenderMode#surface}, this mode is less performant than {@link #opaque}, but this
* mode avoids the black flicker problem that {@link #opaque} has when going through {@code
* Fragment} transactions. Consider using this {@code TransparencyMode} if you intend to switch
* {@code Fragment}s at runtime that contain a Flutter UI.
* <p>In {@link io.flutter.embedding.android.RenderMode#surface}, this mode is less performant
* than {@link #opaque}, but this mode avoids the black flicker problem that {@link #opaque} has
* when going through {@code Fragment} transactions. Consider using this {@code
* TransparencyMode} if you intend to switch {@code Fragment}s at runtime that contain a Flutter
* UI.
*/
transparent
}

View File

@ -0,0 +1,25 @@
// 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.android;
/** Render modes for a Flutter UI. */
public enum RenderMode {
/**
* {@code RenderMode}, which paints a Flutter UI to a {@link android.view.SurfaceView}. This mode
* has the best performance, but a Flutter UI in this mode cannot be positioned between 2 other
* Android {@code View}s in the z-index, nor can it be animated/transformed. Unless the special
* capabilities of a {@link android.graphics.SurfaceTexture} are required, developers should
* strongly prefer this render mode.
*/
surface,
/**
* {@code RenderMode}, which paints a Flutter UI to a {@link android.graphics.SurfaceTexture}.
* This mode is not as performant as {@link #surface}, but a Flutter UI in this mode can be
* animated and transformed, as well as positioned in the z-index between 2+ other Android {@code
* Views}. Unless the special capabilities of a {@link android.graphics.SurfaceTexture} are
* required, developers should strongly prefer the {@link #surface} render mode.
*/
texture
}

View File

@ -0,0 +1,40 @@
// 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.android;
/**
* Transparency mode for a Flutter UI.
*
* <p>{@code TransparencyMode} impacts the visual behavior and performance of a {@link
* FlutterSurfaceView}, which is displayed when a Flutter UI uses {@link RenderMode#surface}.
*
* <p>{@code TransparencyMode} does not impact {@link FlutterTextureView}, which is displayed when a
* Flutter UI uses {@link RenderMode#texture}, because a {@link FlutterTextureView} automatically
* comes with transparency.
*/
public enum TransparencyMode {
/**
* Renders a Flutter UI without any transparency. This affects Flutter UI's with {@link
* RenderMode#surface} by introducing a base color of black, and places the {@link
* FlutterSurfaceView}'s {@code Window} behind all other content.
*
* <p>In {@link RenderMode#surface}, this mode is the most performant and is a good choice for
* fullscreen Flutter UIs that will not undergo {@code Fragment} transactions. If this mode is
* used within a {@code Fragment}, and that {@code Fragment} is replaced by another one, a brief
* black flicker may be visible during the switch.
*/
opaque,
/**
* Renders a Flutter UI with transparency. This affects Flutter UI's in {@link RenderMode#surface}
* by allowing background transparency, and places the {@link FlutterSurfaceView}'s {@code Window}
* on top of all other content.
*
* <p>In {@link RenderMode#surface}, this mode is less performant than {@link #opaque}, but this
* mode avoids the black flicker problem that {@link #opaque} has when going through {@code
* Fragment} transactions. Consider using this {@code TransparencyMode} if you intend to switch
* {@code Fragment}s at runtime that contain a Flutter UI.
*/
transparent
}

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@ -16,6 +17,7 @@ import android.arch.lifecycle.Lifecycle;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.Host;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.FlutterShellArgs;
@ -58,8 +60,8 @@ public class FlutterActivityAndFragmentDelegateTest {
when(mockHost.getDartEntrypointFunctionName()).thenReturn("main");
when(mockHost.getAppBundlePath()).thenReturn("/fake/path");
when(mockHost.getInitialRoute()).thenReturn("/");
when(mockHost.getRenderMode()).thenReturn(FlutterView.RenderMode.surface);
when(mockHost.getTransparencyMode()).thenReturn(FlutterView.TransparencyMode.transparent);
when(mockHost.getRenderMode()).thenReturn(RenderMode.surface);
when(mockHost.getTransparencyMode()).thenReturn(TransparencyMode.transparent);
when(mockHost.provideFlutterEngine(any(Context.class))).thenReturn(mockFlutterEngine);
when(mockHost.shouldAttachEngineToActivity()).thenReturn(true);
when(mockHost.shouldDestroyEngineWithHost()).thenReturn(true);
@ -200,6 +202,38 @@ public class FlutterActivityAndFragmentDelegateTest {
verify(mockHost, times(1)).configureFlutterEngine(mockFlutterEngine);
}
@Test
public void itGivesHostAnOpportunityToConfigureFlutterSurfaceView() {
// ---- Test setup ----
// Create the real object that we're testing.
FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost);
// --- Execute the behavior under test ---
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
// Verify that the host was asked to configure a FlutterSurfaceView.
verify(mockHost, times(1)).onFlutterSurfaceViewCreated(notNull(FlutterSurfaceView.class));
}
@Test
public void itGivesHostAnOpportunityToConfigureFlutterTextureView() {
// ---- Test setup ----
Host customMockHost = mock(Host.class);
when(customMockHost.getRenderMode()).thenReturn(RenderMode.texture);
// Create the real object that we're testing.
FlutterActivityAndFragmentDelegate delegate =
new FlutterActivityAndFragmentDelegate(customMockHost);
// --- Execute the behavior under test ---
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
// Verify that the host was asked to configure a FlutterTextureView.
verify(customMockHost, times(1)).onFlutterTextureViewCreated(notNull(FlutterTextureView.class));
}
@Test
public void itGivesHostAnOpportunityToCleanUpFlutterEngine() {
// ---- Test setup ----

View File

@ -57,8 +57,8 @@ public class FlutterActivityTest {
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertEquals(BackgroundMode.opaque, flutterActivity.getBackgroundMode());
assertEquals(FlutterView.RenderMode.surface, flutterActivity.getRenderMode());
assertEquals(FlutterView.TransparencyMode.opaque, flutterActivity.getTransparencyMode());
assertEquals(RenderMode.surface, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.opaque, flutterActivity.getTransparencyMode());
}
@Test
@ -108,8 +108,8 @@ public class FlutterActivityTest {
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertEquals(BackgroundMode.transparent, flutterActivity.getBackgroundMode());
assertEquals(FlutterView.RenderMode.texture, flutterActivity.getRenderMode());
assertEquals(FlutterView.TransparencyMode.transparent, flutterActivity.getTransparencyMode());
assertEquals(RenderMode.texture, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.transparent, flutterActivity.getTransparencyMode());
}
@Test

View File

@ -232,14 +232,14 @@ public class FlutterAndroidComponentTest {
@NonNull
@Override
public FlutterView.RenderMode getRenderMode() {
return FlutterView.RenderMode.surface;
public RenderMode getRenderMode() {
return RenderMode.surface;
}
@NonNull
@Override
public FlutterView.TransparencyMode getTransparencyMode() {
return FlutterView.TransparencyMode.transparent;
public TransparencyMode getTransparencyMode() {
return TransparencyMode.transparent;
}
@Nullable
@ -272,6 +272,12 @@ public class FlutterAndroidComponentTest {
return true;
}
@Override
public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {}
@Override
public void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView) {}
@Override
public void onFlutterUiDisplayed() {}

View File

@ -25,8 +25,8 @@ public class FlutterFragmentTest {
assertTrue(fragment.shouldAttachEngineToActivity());
assertNull(fragment.getCachedEngineId());
assertTrue(fragment.shouldDestroyEngineWithHost());
assertEquals(FlutterView.RenderMode.surface, fragment.getRenderMode());
assertEquals(FlutterView.TransparencyMode.transparent, fragment.getTransparencyMode());
assertEquals(RenderMode.surface, fragment.getRenderMode());
assertEquals(TransparencyMode.transparent, fragment.getTransparencyMode());
}
@Test
@ -36,8 +36,8 @@ public class FlutterFragmentTest {
.dartEntrypoint("custom_entrypoint")
.initialRoute("/custom/route")
.shouldAttachEngineToActivity(false)
.renderMode(FlutterView.RenderMode.texture)
.transparencyMode(FlutterView.TransparencyMode.opaque)
.renderMode(RenderMode.texture)
.transparencyMode(TransparencyMode.opaque)
.build();
fragment.setDelegate(new FlutterActivityAndFragmentDelegate(fragment));
@ -47,8 +47,8 @@ public class FlutterFragmentTest {
assertFalse(fragment.shouldAttachEngineToActivity());
assertNull(fragment.getCachedEngineId());
assertTrue(fragment.shouldDestroyEngineWithHost());
assertEquals(FlutterView.RenderMode.texture, fragment.getRenderMode());
assertEquals(FlutterView.TransparencyMode.opaque, fragment.getTransparencyMode());
assertEquals(RenderMode.texture, fragment.getRenderMode());
assertEquals(TransparencyMode.opaque, fragment.getTransparencyMode());
}
@Test

View File

@ -8,8 +8,9 @@ import static org.junit.Assert.assertTrue;
import android.content.Intent;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.android.RenderMode;
import io.flutter.embedding.android.RobolectricFlutterActivity;
import io.flutter.embedding.android.TransparencyMode;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@ -32,7 +33,7 @@ public class FlutterLaunchTests {
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertEquals(
BackgroundMode.opaque, RobolectricFlutterActivity.getBackgroundMode(flutterActivity));
assertEquals(FlutterView.RenderMode.surface, flutterActivity.getRenderMode());
assertEquals(FlutterView.TransparencyMode.opaque, flutterActivity.getTransparencyMode());
assertEquals(RenderMode.surface, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.opaque, flutterActivity.getTransparencyMode());
}
}