未验证 提交 438a29cb 编写于 作者: E Emmanuel Garcia 提交者: GitHub

Set Flutter View ID to the view ID instead of of the splash screen (#27262)

上级 b68786a4
......@@ -47,6 +47,7 @@ import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface;
import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.util.ViewUtils;
/**
* {@code Activity} which displays a fullscreen Flutter UI.
......@@ -215,7 +216,7 @@ public class FlutterActivity extends Activity
* <p>This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more,
* see {@link android.view.View#findViewById}.
*/
public static final int FLUTTER_VIEW_ID = 0xF1F2;
public static final int FLUTTER_VIEW_ID = ViewUtils.generateViewId(0xF1F2);
/**
* Creates an {@link Intent} that launches a {@code FlutterActivity}, which creates a {@link
......@@ -433,9 +434,7 @@ public class FlutterActivity extends Activity
configureWindowForTransparency();
View flutterView = createFlutterView();
flutterView.setId(FLUTTER_VIEW_ID);
setContentView(flutterView);
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}
......@@ -540,7 +539,10 @@ public class FlutterActivity extends Activity
@NonNull
private View createFlutterView() {
return delegate.onCreateView(
null /* inflater */, null /* container */, null /* savedInstanceState */);
/* inflater=*/ null,
/* container=*/ null,
/* savedInstanceState=*/ null,
/*flutterViewId=*/ FLUTTER_VIEW_ID);
}
private void configureStatusBarForFullscreenFlutterExperience() {
......
......@@ -11,7 +11,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
......@@ -28,6 +27,7 @@ import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.util.ViewUtils;
import java.util.Arrays;
/**
......@@ -266,7 +266,10 @@ import java.util.Arrays;
*/
@NonNull
View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState,
int flutterViewId) {
Log.v(TAG, "Creating FlutterView.");
ensureAlive();
......@@ -296,18 +299,12 @@ import java.util.Arrays;
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
flutterSplashView = new FlutterSplashView(host.getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
flutterSplashView.setId(View.generateViewId());
} else {
// TODO(mattcarroll): Find a better solution to this ID. This is a random, static ID.
// It might conflict with other Views, and it means that only a single FlutterSplashView
// can exist in a View hierarchy at one time.
flutterSplashView.setId(486947586);
}
flutterSplashView.setId(ViewUtils.generateViewId(486947586));
flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
Log.v(TAG, "Attaching FlutterEngine to FlutterView.");
flutterView.attachToFlutterEngine(flutterEngine);
flutterView.setId(flutterViewId);
return flutterSplashView;
}
......
......@@ -24,6 +24,7 @@ import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.util.ViewUtils;
/**
* {@code Fragment} which displays a Flutter UI that takes up all available {@code Fragment} space.
......@@ -88,11 +89,20 @@ import io.flutter.plugin.platform.PlatformPlugin;
* }</pre>
*
* <p>If Flutter is needed in a location that can only use a {@code View}, consider using a {@link
* FlutterView}. Using a {@link FlutterView} requires forwarding some calls from an {@code
* io.flutter.embedding.android.FlutterView}. Using a {@link
* io.flutter.embedding.android.FlutterView} requires forwarding some calls from an {@code
* Activity}, as well as forwarding lifecycle calls from an {@code Activity} or a {@code Fragment}.
*/
public class FlutterFragment extends Fragment
implements FlutterActivityAndFragmentDelegate.Host, ComponentCallbacks2 {
/**
* The ID of the {@code FlutterView} created by this activity.
*
* <p>This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more,
* see {@link android.view.View#findViewById}.
*/
public static final int FLUTTER_VIEW_ID = ViewUtils.generateViewId(0xF1F2);
private static final String TAG = "FlutterFragment";
/** The Dart entrypoint method name that is executed upon initialization. */
......@@ -105,10 +115,14 @@ public class FlutterFragment extends Fragment
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 RenderMode} to be used for the {@link FlutterView} in this {@code FlutterFragment} */
/**
* {@link RenderMode} to be used for the {@link io.flutter.embedding.android.FlutterView} in this
* {@code FlutterFragment}
*/
protected static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode";
/**
* {@link TransparencyMode} to be used for the {@link FlutterView} in this {@code FlutterFragment}
* {@link TransparencyMode} to be used for the {@link io.flutter.embedding.android.FlutterView} in
* this {@code FlutterFragment}
*/
protected static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode";
/** See {@link #shouldAttachEngineToActivity()}. */
......@@ -290,8 +304,9 @@ public class FlutterFragment extends Fragment
}
/**
* Support a {@link TransparencyMode#transparent} background within {@link FlutterView}, or
* force an {@link TransparencyMode#opaque} background.
* Support a {@link TransparencyMode#transparent} background within {@link
* io.flutter.embedding.android.FlutterView}, or force an {@link TransparencyMode#opaque}
* background.
*
* <p>See {@link TransparencyMode} for implications of this selection.
*/
......@@ -517,8 +532,9 @@ public class FlutterFragment extends Fragment
}
/**
* Support a {@link TransparencyMode#transparent} background within {@link FlutterView}, or
* force an {@link TransparencyMode#opaque} background.
* Support a {@link TransparencyMode#transparent} background within {@link
* io.flutter.embedding.android.FlutterView}, or force an {@link TransparencyMode#opaque}
* background.
*
* <p>See {@link TransparencyMode} for implications of this selection.
*/
......@@ -710,7 +726,8 @@ public class FlutterFragment extends Fragment
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return delegate.onCreateView(inflater, container, savedInstanceState);
return delegate.onCreateView(
inflater, container, savedInstanceState, /*flutterViewId=*/ FLUTTER_VIEW_ID);
}
@Override
......@@ -1002,8 +1019,8 @@ public class FlutterFragment extends Fragment
}
/**
* Returns the desired {@link RenderMode} for the {@link FlutterView} displayed in this {@code
* FlutterFragment}.
* Returns the desired {@link RenderMode} for the {@link io.flutter.embedding.android.FlutterView}
* displayed in this {@code FlutterFragment}.
*
* <p>Defaults to {@link RenderMode#surface}.
*
......@@ -1018,8 +1035,8 @@ public class FlutterFragment extends Fragment
}
/**
* Returns the desired {@link TransparencyMode} for the {@link FlutterView} displayed in this
* {@code FlutterFragment}.
* Returns the desired {@link TransparencyMode} for the {@link
* io.flutter.embedding.android.FlutterView} displayed in this {@code FlutterFragment}.
*
* <p>Defaults to {@link TransparencyMode#transparent}.
*
......@@ -1176,8 +1193,8 @@ public class FlutterFragment extends Fragment
}
/**
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} starts rendering
* pixels to the screen.
* Invoked after the {@link io.flutter.embedding.android.FlutterView} within this {@code
* FlutterFragment} starts rendering pixels to the screen.
*
* <p>This method forwards {@code onFlutterUiDisplayed()} to its attached {@code Activity}, if the
* attached {@code Activity} implements {@link FlutterUiDisplayListener}.
......@@ -1195,8 +1212,8 @@ public class FlutterFragment extends Fragment
}
/**
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} stops rendering
* pixels to the screen.
* Invoked after the {@link io.flutter.embedding.android.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}.
......
......@@ -7,6 +7,8 @@ package io.flutter.util;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
import android.view.View;
public final class ViewUtils {
/**
......@@ -28,4 +30,19 @@ public final class ViewUtils {
}
return null;
}
/**
* Generates a view id.
*
* <p>In API level 17 and above, this ID is unique. Below 17, the fallback id is used instead.
*
* @param fallbackId the fallback id.
* @return the view id.
*/
public static int generateViewId(int fallbackId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return View.generateViewId();
}
return fallbackId;
}
}
......@@ -86,7 +86,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// We're testing lifecycle behaviors, which require/expect that certain methods have already
// been executed by the time they run. Therefore, we run those expected methods first.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
// --- Execute the behavior under test ---
// By the time an Activity/Fragment is started, we don't expect any lifecycle messages
......@@ -164,7 +164,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// The FlutterEngine is obtained in onAttach().
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
......@@ -220,7 +220,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
// Verify that the host was asked to configure a FlutterSurfaceView.
verify(mockHost, times(1)).onFlutterSurfaceViewCreated(notNull(FlutterSurfaceView.class));
......@@ -249,7 +249,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
// Verify that the host was asked to configure a FlutterTextureView.
verify(customMockHost, times(1)).onFlutterTextureViewCreated(notNull(FlutterTextureView.class));
......@@ -282,7 +282,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// The initial route is sent in onStart().
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
// Verify that the navigation channel was given our initial route.
......@@ -306,7 +306,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Dart is executed in onStart().
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
// Verify that the host's Dart entrypoint was used.
......@@ -335,7 +335,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Dart is executed in onStart().
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
// Verify that the host's Dart entrypoint was used.
......@@ -647,7 +647,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Push the delegate through all lifecycle methods all the way to destruction.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......@@ -671,7 +671,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Push the delegate through all lifecycle methods all the way to destruction.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......@@ -702,7 +702,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Push the delegate through all lifecycle methods all the way to destruction.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......@@ -734,7 +734,7 @@ public class FlutterActivityAndFragmentDelegateTest {
// --- Execute the behavior under test ---
// Push the delegate through all lifecycle methods all the way to destruction.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......
......@@ -77,6 +77,7 @@ public class FlutterActivityTest {
activity.onCreate(null);
assertNotNull(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID));
assertTrue(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID) instanceof FlutterView);
}
@Test
......
......@@ -82,7 +82,7 @@ public class FlutterAndroidComponentTest {
assertNotNull(binding.getPlatformViewRegistry());
delegate.onRestoreInstanceState(null);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......@@ -156,7 +156,7 @@ public class FlutterAndroidComponentTest {
// Verify that after Activity creation, the plugin was allowed to restore state.
verify(mockSaveStateListener, times(1)).onRestoreInstanceState(any(Bundle.class));
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......@@ -195,7 +195,7 @@ public class FlutterAndroidComponentTest {
// Push the delegate through all lifecycle methods all the way to destruction.
delegate.onAttach(RuntimeEnvironment.application);
delegate.onRestoreInstanceState(null);
delegate.onCreateView(null, null, null);
delegate.onCreateView(null, null, null, 0);
delegate.onStart();
delegate.onResume();
delegate.onPause();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册