blob: 30dd648beac6e0f235cdf734d821b50852c9711a [file] [log] [blame]
package io.flutter.embedding.android;
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.HANDLE_DEEPLINKING_META_DATA_KEY;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.FlutterInjector;
import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding.OnSaveInstanceStateListener;
import io.flutter.plugins.GeneratedPluginRegistrant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
@Config(manifest = Config.NONE)
@RunWith(AndroidJUnit4.class)
public class FlutterActivityTest {
private final Context ctx = ApplicationProvider.getApplicationContext();
boolean isDelegateAttached;
@Before
public void setUp() {
FlutterInjector.reset();
GeneratedPluginRegistrant.clearRegisteredEngines();
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
when(mockFlutterJNI.isAttached()).thenReturn(true);
FlutterJNI.Factory mockFlutterJNIFactory = mock(FlutterJNI.Factory.class);
when(mockFlutterJNIFactory.provideFlutterJNI()).thenReturn(mockFlutterJNI);
FlutterInjector.setInstance(
new FlutterInjector.Builder().setFlutterJNIFactory(mockFlutterJNIFactory).build());
}
@After
public void tearDown() {
GeneratedPluginRegistrant.clearRegisteredEngines();
FlutterInjector.reset();
}
@Test
public void flutterViewHasId() {
Intent intent = FlutterActivity.createDefaultIntent(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity activity = activityController.get();
activity.onCreate(null);
assertNotNull(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID));
assertTrue(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID) instanceof FlutterView);
}
// TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric
// test that directly exercises the OnBackInvoked APIs when API 33 is supported.
@Test
@TargetApi(33)
public void itRegistersOnBackInvokedCallbackOnChangingFrameworkHandlesBack() {
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
FlutterActivityWithReportFullyDrawn activity = spy(activityController.get());
activity.onCreate(null);
verify(activity, times(0)).registerOnBackInvokedCallback();
activity.setFrameworkHandlesBack(false);
verify(activity, times(0)).registerOnBackInvokedCallback();
activity.setFrameworkHandlesBack(true);
verify(activity, times(1)).registerOnBackInvokedCallback();
}
// TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric
// test that directly exercises the OnBackInvoked APIs when API 33 is supported.
@Test
@TargetApi(33)
public void itUnregistersOnBackInvokedCallbackOnRelease() {
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
FlutterActivityWithReportFullyDrawn activity = spy(activityController.get());
activity.release();
verify(activity, times(1)).unregisterOnBackInvokedCallback();
}
@Test
public void itCreatesDefaultIntentWithExpectedDefaults() {
Intent intent = FlutterActivity.createDefaultIntent(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(new FlutterActivityAndFragmentDelegate(flutterActivity));
assertEquals("main", flutterActivity.getDartEntrypointFunctionName());
assertNull(flutterActivity.getDartEntrypointLibraryUri());
assertNull(flutterActivity.getDartEntrypointArgs());
assertEquals("/", flutterActivity.getInitialRoute());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertEquals(BackgroundMode.opaque, flutterActivity.getBackgroundMode());
assertEquals(RenderMode.surface, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.opaque, flutterActivity.getTransparencyMode());
}
@Test
public void itDestroysNewEngineWhenIntentIsMissingParameter() {
// All clients should use the static members of FlutterActivity to construct an
// Intent. Missing extras is an error. However, Flutter has number of tests that
// don't seem to use the static members of FlutterActivity to construct the
// launching Intent, so this test explicitly verifies that even illegal Intents
// result in the automatic destruction of a non-cached FlutterEngine, which prevents
// the breakage of memory usage benchmark tests.
Intent intent = new Intent(ctx, FlutterActivity.class);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(new FlutterActivityAndFragmentDelegate(flutterActivity));
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
}
@Test
public void itDoesNotDestroyFlutterEngineWhenProvidedByHost() {
Intent intent = new Intent(ctx, FlutterActivityWithProvidedEngine.class);
ActivityController<FlutterActivityWithProvidedEngine> activityController =
Robolectric.buildActivity(FlutterActivityWithProvidedEngine.class, intent);
activityController.create();
FlutterActivityWithProvidedEngine flutterActivity = activityController.get();
assertFalse(flutterActivity.shouldDestroyEngineWithHost());
}
@Test
public void itCreatesNewEngineIntentWithRequestedSettings() {
Intent intent =
FlutterActivity.withNewEngine()
.initialRoute("/custom/route")
.dartEntrypointArgs(new ArrayList<String>(Arrays.asList("foo", "bar")))
.backgroundMode(BackgroundMode.transparent)
.build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(new FlutterActivityAndFragmentDelegate(flutterActivity));
assertEquals("/custom/route", flutterActivity.getInitialRoute());
assertArrayEquals(
new String[] {"foo", "bar"}, flutterActivity.getDartEntrypointArgs().toArray());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertEquals(BackgroundMode.transparent, flutterActivity.getBackgroundMode());
assertEquals(RenderMode.texture, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.transparent, flutterActivity.getTransparencyMode());
}
@Test
public void itCreatesNewEngineInGroupIntentWithRequestedSettings() {
Intent intent =
FlutterActivity.withNewEngineInGroup("my_cached_engine_group")
.dartEntrypoint("custom_entrypoint")
.initialRoute("/custom/route")
.backgroundMode(BackgroundMode.transparent)
.build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(new FlutterActivityAndFragmentDelegate(flutterActivity));
assertEquals("my_cached_engine_group", flutterActivity.getCachedEngineGroupId());
assertEquals("custom_entrypoint", flutterActivity.getDartEntrypointFunctionName());
assertEquals("/custom/route", flutterActivity.getInitialRoute());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertNull(flutterActivity.getCachedEngineId());
assertEquals(BackgroundMode.transparent, flutterActivity.getBackgroundMode());
assertEquals(RenderMode.texture, flutterActivity.getRenderMode());
assertEquals(TransparencyMode.transparent, flutterActivity.getTransparencyMode());
}
@Test
public void itReturnsValueFromMetaDataWhenCallsShouldHandleDeepLinkingCase1()
throws PackageManager.NameNotFoundException {
Intent intent =
FlutterActivity.withNewEngine().backgroundMode(BackgroundMode.transparent).build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
Bundle bundle = new Bundle();
bundle.putBoolean(HANDLE_DEEPLINKING_META_DATA_KEY, true);
FlutterActivity spyFlutterActivity = spy(flutterActivity);
when(spyFlutterActivity.getMetaData()).thenReturn(bundle);
assertTrue(spyFlutterActivity.shouldHandleDeeplinking());
}
@Test
public void itReturnsValueFromMetaDataWhenCallsShouldHandleDeepLinkingCase2()
throws PackageManager.NameNotFoundException {
Intent intent =
FlutterActivity.withNewEngine().backgroundMode(BackgroundMode.transparent).build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
Bundle bundle = new Bundle();
bundle.putBoolean(HANDLE_DEEPLINKING_META_DATA_KEY, false);
FlutterActivity spyFlutterActivity = spy(flutterActivity);
when(spyFlutterActivity.getMetaData()).thenReturn(bundle);
assertFalse(spyFlutterActivity.shouldHandleDeeplinking());
}
@Test
public void itReturnsValueFromMetaDataWhenCallsShouldHandleDeepLinkingCase3()
throws PackageManager.NameNotFoundException {
Intent intent =
FlutterActivity.withNewEngine().backgroundMode(BackgroundMode.transparent).build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
// Creates an empty bundle.
Bundle bundle = new Bundle();
FlutterActivity spyFlutterActivity = spy(flutterActivity);
when(spyFlutterActivity.getMetaData()).thenReturn(bundle);
// Empty bundle should return false.
assertFalse(spyFlutterActivity.shouldHandleDeeplinking());
}
@Test
public void itCreatesCachedEngineIntentThatDoesNotDestroyTheEngine() {
Intent intent =
FlutterActivity.withCachedEngine("my_cached_engine")
.destroyEngineWithActivity(false)
.build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertEquals("my_cached_engine", flutterActivity.getCachedEngineId());
assertFalse(flutterActivity.shouldDestroyEngineWithHost());
}
@Test
public void itCreatesCachedEngineIntentThatDestroysTheEngine() {
Intent intent =
FlutterActivity.withCachedEngine("my_cached_engine")
.destroyEngineWithActivity(true)
.build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertEquals("my_cached_engine", flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
}
@Test
public void itRegistersPluginsAtConfigurationTime() {
Intent intent = FlutterActivity.createDefaultIntent(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity activity = activityController.get();
// This calls onAttach on FlutterActivityAndFragmentDelegate and subsequently
// configureFlutterEngine which registers the plugins.
activity.onCreate(null);
List<FlutterEngine> registeredEngines = GeneratedPluginRegistrant.getRegisteredEngines();
assertEquals(1, registeredEngines.size());
assertEquals(activity.getFlutterEngine(), registeredEngines.get(0));
}
@Test
public void itCanBeDetachedFromTheEngineAndStopSendingFurtherEvents() {
FlutterActivityAndFragmentDelegate mockDelegate =
mock(FlutterActivityAndFragmentDelegate.class);
FlutterEngine mockEngine = mock(FlutterEngine.class);
FlutterEngineCache.getInstance().put("my_cached_engine", mockEngine);
Intent intent = FlutterActivity.withCachedEngine("my_cached_engine").build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
isDelegateAttached = true;
when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
doAnswer(invocation -> isDelegateAttached = false).when(mockDelegate).onDetach();
flutterActivity.setDelegate(mockDelegate);
flutterActivity.onStart();
flutterActivity.onResume();
verify(mockDelegate, times(1)).onStart();
verify(mockDelegate, times(1)).onResume();
flutterActivity.onPause();
flutterActivity.detachFromFlutterEngine();
verify(mockDelegate, times(1)).onPause();
verify(mockDelegate, times(1)).onDestroyView();
verify(mockDelegate, times(1)).onDetach();
flutterActivity.onStop();
verify(mockDelegate, never()).onStop();
// Simulate the disconnected activity resuming again.
flutterActivity.onStart();
flutterActivity.onResume();
// Shouldn't send more events to the delegates as before and shouldn't crash.
verify(mockDelegate, times(1)).onStart();
verify(mockDelegate, times(1)).onResume();
flutterActivity.onDestroy();
// 1 time same as before.
verify(mockDelegate, times(1)).onDestroyView();
verify(mockDelegate, times(1)).onDetach();
verify(mockDelegate, times(1)).release();
}
@Test
public void itReturnsExclusiveAppComponent() {
Intent intent = FlutterActivity.createDefaultIntent(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
FlutterActivityAndFragmentDelegate delegate =
new FlutterActivityAndFragmentDelegate(flutterActivity);
flutterActivity.setDelegate(delegate);
assertEquals(flutterActivity.getExclusiveAppComponent(), delegate);
}
@Test
public void itDelaysDrawing() {
Intent intent = FlutterActivity.createDefaultIntent(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.onCreate(null);
assertNotNull(flutterActivity.delegate.activePreDrawListener);
}
@Test
public void itDoesNotDelayDrawingwhenUsingTextureRendering() {
Intent intent = FlutterActivityWithTextureRendering.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithTextureRendering> activityController =
Robolectric.buildActivity(FlutterActivityWithTextureRendering.class, intent);
FlutterActivityWithTextureRendering flutterActivity = activityController.get();
flutterActivity.onCreate(null);
assertNull(flutterActivity.delegate.activePreDrawListener);
}
@Test
public void itRestoresPluginStateBeforePluginOnCreate() {
FlutterLoader mockFlutterLoader = mock(FlutterLoader.class);
FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
when(mockFlutterJni.isAttached()).thenReturn(true);
FlutterEngine cachedEngine = new FlutterEngine(ctx, mockFlutterLoader, mockFlutterJni);
FakeFlutterPlugin fakeFlutterPlugin = new FakeFlutterPlugin();
cachedEngine.getPlugins().add(fakeFlutterPlugin);
FlutterEngineCache.getInstance().put("my_cached_engine", cachedEngine);
Intent intent = FlutterActivity.withCachedEngine("my_cached_engine").build(ctx);
Robolectric.buildActivity(FlutterActivity.class, intent).setup();
assertTrue(
"Expected FakeFlutterPlugin onCreateCalled to be true", fakeFlutterPlugin.onCreateCalled);
}
@Test
public void itDoesNotRegisterPluginsTwiceWhenUsingACachedEngine() {
Intent intent = new Intent(ctx, FlutterActivityWithProvidedEngine.class);
ActivityController<FlutterActivityWithProvidedEngine> activityController =
Robolectric.buildActivity(FlutterActivityWithProvidedEngine.class, intent);
activityController.create();
FlutterActivityWithProvidedEngine flutterActivity = activityController.get();
flutterActivity.configureFlutterEngine(flutterActivity.getFlutterEngine());
List<FlutterEngine> registeredEngines = GeneratedPluginRegistrant.getRegisteredEngines();
// This might cause the plugins to be registered twice, once by the FlutterEngine constructor,
// and once by the default FlutterActivity.configureFlutterEngine implementation.
// Test that it doesn't happen.
assertEquals(1, registeredEngines.size());
}
@Test
public void itDoesNotReleaseEnginewhenDetachFromFlutterEngine() {
FlutterActivityAndFragmentDelegate mockDelegate =
mock(FlutterActivityAndFragmentDelegate.class);
isDelegateAttached = true;
when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
doAnswer(invocation -> isDelegateAttached = false).when(mockDelegate).onDetach();
FlutterEngine mockEngine = mock(FlutterEngine.class);
FlutterEngineCache.getInstance().put("my_cached_engine", mockEngine);
Intent intent = FlutterActivity.withCachedEngine("my_cached_engine").build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(mockDelegate);
flutterActivity.onStart();
flutterActivity.onResume();
flutterActivity.onPause();
assertTrue(mockDelegate.isAttached());
flutterActivity.detachFromFlutterEngine();
verify(mockDelegate, times(1)).onDetach();
verify(mockDelegate, never()).release();
assertFalse(mockDelegate.isAttached());
}
@Test
public void itReleaseEngineWhenOnDestroy() {
FlutterActivityAndFragmentDelegate mockDelegate =
mock(FlutterActivityAndFragmentDelegate.class);
isDelegateAttached = true;
when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
doAnswer(invocation -> isDelegateAttached = false).when(mockDelegate).onDetach();
FlutterEngine mockEngine = mock(FlutterEngine.class);
FlutterEngineCache.getInstance().put("my_cached_engine", mockEngine);
Intent intent = FlutterActivity.withCachedEngine("my_cached_engine").build(ctx);
ActivityController<FlutterActivity> activityController =
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
flutterActivity.setDelegate(mockDelegate);
flutterActivity.onStart();
flutterActivity.onResume();
flutterActivity.onPause();
assertTrue(mockDelegate.isAttached());
flutterActivity.onDestroy();
verify(mockDelegate, times(1)).onDetach();
verify(mockDelegate, times(1)).release();
assertFalse(mockDelegate.isAttached());
}
@Test
@Config(minSdk = Build.VERSION_CODES.KITKAT, maxSdk = Build.VERSION_CODES.P)
public void fullyDrawn_beforeAndroidQ() {
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
FlutterActivityWithReportFullyDrawn flutterActivity = activityController.get();
// See https://github.com/flutter/flutter/issues/46172, and
// https://github.com/flutter/flutter/issues/88767.
flutterActivity.onFlutterUiDisplayed();
assertFalse("reportFullyDrawn isn't used", flutterActivity.isFullyDrawn());
}
@Test
@Config(minSdk = Build.VERSION_CODES.Q)
public void fullyDrawn_fromAndroidQ() {
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
FlutterActivityWithReportFullyDrawn flutterActivity = activityController.get();
flutterActivity.onFlutterUiDisplayed();
assertTrue("reportFullyDrawn is used", flutterActivity.isFullyDrawn());
flutterActivity.resetFullyDrawn();
}
static class FlutterActivityWithProvidedEngine extends FlutterActivity {
@Override
@SuppressLint("MissingSuperCall")
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.delegate = new FlutterActivityAndFragmentDelegate(this);
super.delegate.setUpFlutterEngine();
}
@Nullable
@Override
public FlutterEngine provideFlutterEngine(@NonNull Context context) {
FlutterJNI flutterJNI = mock(FlutterJNI.class);
FlutterLoader flutterLoader = mock(FlutterLoader.class);
when(flutterJNI.isAttached()).thenReturn(true);
when(flutterLoader.automaticallyRegisterPlugins()).thenReturn(true);
return new FlutterEngine(context, flutterLoader, flutterJNI, new String[] {}, true);
}
}
// This is just a compile time check to ensure that it's possible for FlutterActivity subclasses
// to provide their own intent builders which builds their own runtime types.
static class FlutterActivityWithIntentBuilders extends FlutterActivity {
public static NewEngineIntentBuilder withNewEngine() {
return new NewEngineIntentBuilder(FlutterActivityWithIntentBuilders.class);
}
public static CachedEngineIntentBuilder withCachedEngine(@NonNull String cachedEngineId) {
return new CachedEngineIntentBuilder(FlutterActivityWithIntentBuilders.class, cachedEngineId);
}
}
private static class FlutterActivityWithTextureRendering extends FlutterActivity {
@Override
public RenderMode getRenderMode() {
return RenderMode.texture;
}
}
private static class FlutterActivityWithReportFullyDrawn extends FlutterActivity {
private boolean fullyDrawn = false;
@Override
public void reportFullyDrawn() {
fullyDrawn = true;
}
public boolean isFullyDrawn() {
return fullyDrawn;
}
public void resetFullyDrawn() {
fullyDrawn = false;
}
}
private class FlutterActivityWithMockBackInvokedHandling extends FlutterActivity {
@Override
public void registerOnBackInvokedCallback() {}
@Override
public void unregisterOnBackInvokedCallback() {}
}
private static final class FakeFlutterPlugin
implements FlutterPlugin,
ActivityAware,
OnSaveInstanceStateListener,
DefaultLifecycleObserver {
private ActivityPluginBinding activityPluginBinding;
private boolean stateRestored = false;
private boolean onCreateCalled = false;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
activityPluginBinding = binding;
binding.addOnSaveStateListener(this);
((FlutterActivity) binding.getActivity()).getLifecycle().addObserver(this);
}
@Override
public void onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity();
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
onAttachedToActivity(binding);
}
@Override
public void onDetachedFromActivity() {
((FlutterActivity) activityPluginBinding.getActivity()).getLifecycle().removeObserver(this);
activityPluginBinding.removeOnSaveStateListener(this);
activityPluginBinding = null;
}
@Override
public void onSaveInstanceState(@NonNull Bundle bundle) {}
@Override
public void onRestoreInstanceState(@Nullable Bundle bundle) {
stateRestored = true;
}
@Override
public void onCreate(@NonNull LifecycleOwner lifecycleOwner) {
assertTrue("State was restored before onCreate", stateRestored);
onCreateCalled = true;
}
}
}