1package io.flutter.embedding.android;
3import static org.junit.Assert.assertArrayEquals;
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6import static org.junit.Assert.assertNotNull;
7import static org.junit.Assert.assertNull;
8import static org.junit.Assert.assertTrue;
9import static org.mockito.ArgumentMatchers.any;
10import static org.mockito.Mockito.doAnswer;
11import static org.mockito.Mockito.mock;
12import static org.mockito.Mockito.never;
13import static org.mockito.Mockito.spy;
14import static org.mockito.Mockito.times;
15import static org.mockito.Mockito.verify;
16import static org.mockito.Mockito.when;
19import androidx.activity.OnBackPressedCallback;
20import androidx.fragment.app.FragmentActivity;
21import androidx.test.core.app.ApplicationProvider;
22import androidx.test.ext.junit.runners.AndroidJUnit4;
23import io.flutter.embedding.engine.FlutterEngine;
24import io.flutter.embedding.engine.FlutterEngineCache;
25import io.flutter.embedding.engine.FlutterJNI;
26import io.flutter.embedding.engine.loader.FlutterLoader;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.concurrent.atomic.AtomicBoolean;
31import org.junit.runner.RunWith;
32import org.robolectric.Robolectric;
33import org.robolectric.annotation.Config;
36@RunWith(AndroidJUnit4.class)
38 private final Context ctx = ApplicationProvider.getApplicationContext();
45 this.delegate = delegate;
79 .dartEntrypoint(
"custom_entrypoint")
80 .dartLibraryUri(
"package:foo/bar.dart")
81 .dartEntrypointArgs(
new ArrayList<String>(Arrays.asList(
"foo",
"bar")))
82 .initialRoute(
"/custom/route")
83 .shouldAttachEngineToActivity(
false)
84 .handleDeeplinking(
true)
109 .dartEntrypoint(
"custom_entrypoint")
110 .initialRoute(
"/custom/route")
111 .shouldAttachEngineToActivity(
false)
112 .handleDeeplinking(
true)
156 .destroyEngineWithFragment(
true)
168 .shouldDelayFirstAndroidViewDraw(
true)
181 .destroyEngineWithFragment(
true)
184 isDelegateAttached =
true;
185 when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
186 doAnswer(invocation -> isDelegateAttached =
false).when(mockDelegate).onDetach();
193 verify(mockDelegate,
times(1)).onStart();
194 verify(mockDelegate,
times(1)).onResume();
195 verify(mockDelegate,
times(1)).onPostResume();
199 verify(mockDelegate,
times(1)).onPause();
200 verify(mockDelegate,
times(1)).onDestroyView();
201 verify(mockDelegate,
times(1)).onDetach();
204 verify(mockDelegate, never()).onStop();
210 verify(mockDelegate,
times(1)).onStart();
211 verify(mockDelegate,
times(1)).onResume();
212 verify(mockDelegate,
times(1)).onPostResume();
214 fragment.onDestroy();
217 verify(mockDelegate,
times(1)).onDetach();
224 isDelegateAttached =
true;
225 when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
226 doAnswer(invocation -> isDelegateAttached =
false).when(mockDelegate).onDetach();
231 .destroyEngineWithFragment(
true)
240 assertTrue(mockDelegate.isAttached());
242 verify(mockDelegate,
times(1)).onDetach();
243 verify(mockDelegate, never()).release();
244 assertFalse(mockDelegate.isAttached());
251 isDelegateAttached =
true;
252 when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
253 doAnswer(invocation -> isDelegateAttached =
false).when(mockDelegate).onDetach();
259 .destroyEngineWithFragment(
true)
261 when(fragment.
getContext()).thenReturn(mock(Context.class));
269 assertTrue(mockDelegate.isAttached());
271 verify(mockDelegate,
times(1)).onDetach();
272 verify(mockDelegate,
times(1)).release();
273 assertFalse(mockDelegate.isAttached());
286 @SuppressWarnings(
"deprecation")
287 private FragmentActivity getMockFragmentActivity() {
289 return Robolectric.setupActivity(FragmentActivity.class);
296 when(flutterJNI.
isAttached()).thenReturn(
true);
306 .shouldAutomaticallyHandleOnBackPressed(
true)
308 FragmentActivity activity = getMockFragmentActivity();
310 .getSupportFragmentManager()
312 .add(
android.R.id.content, fragment)
317 isDelegateAttached =
true;
318 when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
319 doAnswer(invocation -> isDelegateAttached =
false).when(mockDelegate).onDetach();
325 activity.onBackPressed();
326 verify(mockDelegate,
times(0)).onBackPressed();
331 activity.getOnBackPressedDispatcher().onBackPressed();
332 verify(mockDelegate,
times(1)).onBackPressed();
335 @SuppressWarnings(
"deprecation")
342 when(flutterJNI.
isAttached()).thenReturn(
true);
350 .shouldAutomaticallyHandleOnBackPressed(
true)
352 FragmentActivity activity = getMockFragmentActivity();
354 .getSupportFragmentManager()
356 .add(
android.R.id.content, fragment)
358 final AtomicBoolean onBackPressedCalled =
new AtomicBoolean(
false);
360 new OnBackPressedCallback(
true) {
362 public void handleOnBackPressed() {
363 onBackPressedCalled.set(
true);
366 activity.getOnBackPressedDispatcher().addCallback(
callback);
377 verify(mockDelegate, never()).onBackPressed();
378 assertTrue(onBackPressedCalled.get());
385 verify(mockDelegate, never()).onBackPressed();
393 isDelegateAttached =
true;
394 when(mockDelegate.isAttached()).thenAnswer(invocation -> isDelegateAttached);
395 doAnswer(invocation -> isDelegateAttached =
false).when(mockDelegate).onDetach();
398 Context spyCtx = spy(ctx);
401 when(flutterJNI.
isAttached()).thenReturn(
true);
408 when(fragment.
getContext()).thenReturn(spyCtx);
412 verify(spyCtx,
times(1)).registerComponentCallbacks(
any());
413 verify(spyCtx, never()).unregisterComponentCallbacks(
any());
416 verify(spyCtx,
times(1)).registerComponentCallbacks(
any());
417 verify(spyCtx,
times(1)).unregisterComponentCallbacks(
any());
static SkISize times(const SkISize &size, float factor)
TestDelegateFactory(FlutterActivityAndFragmentDelegate delegate)
FlutterActivityAndFragmentDelegate delegate
FlutterActivityAndFragmentDelegate createDelegate(FlutterActivityAndFragmentDelegate.Host host)
void itCreatesNewEngineFragmentThatDelaysFirstDrawWhenRequested()
void itReleaseEngineWhenOnDetach()
void itDelegatesOnBackPressedWithSetFrameworkHandlesBack()
void itReturnsExclusiveAppComponent()
void itHandlesPopSystemNavigationAutomaticallyWhenEnabled()
void itCreatesCachedEngineFragmentThatDestroysTheEngine()
void itCreatesCachedEngineFragmentThatDelaysFirstDrawWhenRequested()
void itCanBeDetachedFromTheEngineAndStopSendingFurtherEvents()
void itDoesNotReleaseEnginewhenDetachFromFlutterEngine()
void itCreatesNewEngineInGroupFragmentWithRequestedSettings()
boolean isDelegateAttached
void itCreatesNewEngineFragmentWithRequestedSettings()
void itCreatesCachedEngineFragmentWithExpectedDefaults()
void itCreatesDefaultFragmentWithExpectedDefaults()
void itRegistersComponentCallbacks()
public< T extends FlutterFragment > T build()
String getCachedEngineGroupId()
void setFrameworkHandlesBack(boolean frameworkHandlesBack)
List< String > getDartEntrypointArgs()
FlutterShellArgs getFlutterShellArgs()
boolean popSystemNavigator()
static NewEngineFragmentBuilder withNewEngine()
boolean shouldHandleDeeplinking()
static FlutterFragment createDefault()
String getDartEntrypointFunctionName()
boolean shouldDelayFirstAndroidViewDraw()
static NewEngineInGroupFragmentBuilder withNewEngineInGroup( @NonNull String engineGroupId)
void detachFromFlutterEngine()
boolean shouldAttachEngineToActivity()
static CachedEngineFragmentBuilder withCachedEngine(@NonNull String engineId)
String getDartEntrypointLibraryUri()
TransparencyMode getTransparencyMode()
RenderMode getRenderMode()
ExclusiveAppComponent< Activity > getExclusiveAppComponent()
boolean shouldDestroyEngineWithHost()
String getCachedEngineId()
void setDelegateFactory( @NonNull FlutterActivityAndFragmentDelegate.DelegateFactory delegateFactory)
void onAttach(@NonNull Context context)
static FlutterEngineCache getInstance()
void put(@NonNull String engineId, @Nullable FlutterEngine engine)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service host
SIT bool any(const Vec< 1, T > &x)