Flutter Engine
The Flutter Engine
FlutterEngineConnectionRegistryTest.java
Go to the documentation of this file.
1package io.flutter.embedding.engine;
2
3import static org.junit.Assert.*;
4import static org.mockito.ArgumentMatchers.*;
5import static org.mockito.Mockito.*;
6
7import android.app.Activity;
8import android.content.Context;
9import android.content.Intent;
10import androidx.annotation.NonNull;
11import androidx.lifecycle.Lifecycle;
12import androidx.test.ext.junit.runners.AndroidJUnit4;
13import io.flutter.embedding.android.ExclusiveAppComponent;
14import io.flutter.embedding.engine.loader.FlutterLoader;
15import io.flutter.embedding.engine.plugins.FlutterPlugin;
16import io.flutter.embedding.engine.plugins.activity.ActivityAware;
17import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
18import io.flutter.plugin.common.PluginRegistry;
19import io.flutter.plugin.platform.PlatformViewsController;
20import java.util.concurrent.atomic.AtomicBoolean;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23import org.robolectric.annotation.Config;
24
25// Run with Robolectric so that Log calls don't crash.
26@Config(manifest = Config.NONE)
27@RunWith(AndroidJUnit4.class)
29 @Test
31 Context context = mock(Context.class);
32
33 FlutterEngine flutterEngine = mock(FlutterEngine.class);
34 PlatformViewsController platformViewsController = mock(PlatformViewsController.class);
35 when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController);
36
37 FlutterLoader flutterLoader = mock(FlutterLoader.class);
38
39 FakeFlutterPlugin fakePlugin1 = new FakeFlutterPlugin();
40 FakeFlutterPlugin fakePlugin2 = new FakeFlutterPlugin();
41
43 new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
44
45 // Verify that the registry doesn't think it contains our plugin yet.
46 assertFalse(registry.has(fakePlugin1.getClass()));
47
48 // Add our plugin to the registry.
49 registry.add(fakePlugin1);
50
51 // Verify that the registry now thinks it contains our plugin.
52 assertTrue(registry.has(fakePlugin1.getClass()));
53 assertEquals(1, fakePlugin1.attachmentCallCount);
54
55 // Add a different instance of the same plugin class.
56 registry.add(fakePlugin2);
57
58 // Verify that the registry did not detach the 1st plugin, and
59 // it did not attach the 2nd plugin.
60 assertEquals(1, fakePlugin1.attachmentCallCount);
61 assertEquals(0, fakePlugin1.detachmentCallCount);
62
63 assertEquals(0, fakePlugin2.attachmentCallCount);
64 assertEquals(0, fakePlugin2.detachmentCallCount);
65 }
66
67 @Test
69 Context context = mock(Context.class);
70
71 FlutterEngine flutterEngine = mock(FlutterEngine.class);
72 PlatformViewsController platformViewsController = mock(PlatformViewsController.class);
73 when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController);
74
75 FlutterLoader flutterLoader = mock(FlutterLoader.class);
76
77 ExclusiveAppComponent appComponent = mock(ExclusiveAppComponent.class);
78 Activity activity = mock(Activity.class);
79 when(appComponent.getAppComponent()).thenReturn(activity);
80
81 Intent intent = mock(Intent.class);
82 when(activity.getIntent()).thenReturn(intent);
83
84 Lifecycle lifecycle = mock(Lifecycle.class);
85 AtomicBoolean isFirstCall = new AtomicBoolean(true);
86
87 // Set up the environment to get the required internal data
89 new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
90 FakeActivityAwareFlutterPlugin fakePlugin = new FakeActivityAwareFlutterPlugin();
91 registry.add(fakePlugin);
92 registry.attachToActivity(appComponent, lifecycle);
93
94 // The binding is now available via `fakePlugin.binding`: Create and add the listeners
95 FakeActivityResultListener listener1 =
96 new FakeActivityResultListener(isFirstCall, fakePlugin.binding);
97 FakeActivityResultListener listener2 =
98 new FakeActivityResultListener(isFirstCall, fakePlugin.binding);
99
100 fakePlugin.binding.addActivityResultListener(listener1);
101 fakePlugin.binding.addActivityResultListener(listener2);
102
103 // fire the onActivityResult which should invoke both listeners
104 registry.onActivityResult(0, 0, intent);
105
106 assertEquals(1, listener1.callCount);
107 assertEquals(1, listener2.callCount);
108
109 // fire it again to check if the first called listener was removed
110 registry.onActivityResult(0, 0, intent);
111
112 // The order of the listeners in the HashSet is random: So just check the sum of calls
113 assertEquals(3, listener1.callCount + listener2.callCount);
114 }
115
116 @Test
117 public void softwareRendering() {
118 Context context = mock(Context.class);
119
120 FlutterEngine flutterEngine = mock(FlutterEngine.class);
121 PlatformViewsController platformViewsController = mock(PlatformViewsController.class);
122 when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController);
123
124 FlutterLoader flutterLoader = mock(FlutterLoader.class);
125
126 ExclusiveAppComponent appComponent = mock(ExclusiveAppComponent.class);
127 Activity activity = mock(Activity.class);
128 when(appComponent.getAppComponent()).thenReturn(activity);
129
130 // Test attachToActivity with an Activity that has no Intent.
132 new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
133 registry.attachToActivity(appComponent, mock(Lifecycle.class));
134 verify(platformViewsController).setSoftwareRendering(false);
135
136 Intent intent = mock(Intent.class);
137 when(intent.getBooleanExtra("enable-software-rendering", false)).thenReturn(false);
138 when(activity.getIntent()).thenReturn(intent);
139
140 registry.attachToActivity(appComponent, mock(Lifecycle.class));
141 verify(platformViewsController, times(2)).setSoftwareRendering(false);
142
143 when(intent.getBooleanExtra("enable-software-rendering", false)).thenReturn(true);
144
145 registry.attachToActivity(appComponent, mock(Lifecycle.class));
146 verify(platformViewsController).setSoftwareRendering(true);
147 }
148
149 private static class FakeFlutterPlugin implements FlutterPlugin {
150 public int attachmentCallCount = 0;
151 public int detachmentCallCount = 0;
152
153 @Override
154 public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
155 attachmentCallCount += 1;
156 }
157
158 @Override
159 public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
160 detachmentCallCount += 1;
161 }
162 }
163
164 private static class FakeActivityAwareFlutterPlugin implements FlutterPlugin, ActivityAware {
165 public ActivityPluginBinding binding;
166
167 @Override
168 public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {}
169
170 @Override
171 public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
172
173 @Override
174 public void onAttachedToActivity(final ActivityPluginBinding binding) {
175 this.binding = binding;
176 }
177
178 @Override
179 public void onDetachedFromActivityForConfigChanges() {}
180
181 @Override
182 public void onReattachedToActivityForConfigChanges(final ActivityPluginBinding binding) {}
183
184 @Override
185 public void onDetachedFromActivity() {}
186 }
187
188 private static class FakeActivityResultListener implements PluginRegistry.ActivityResultListener {
189 public int callCount = 0;
190 private final AtomicBoolean isFirstCall;
191 private final ActivityPluginBinding binding;
192
193 public FakeActivityResultListener(AtomicBoolean isFirstCall, ActivityPluginBinding binding) {
194 this.isFirstCall = isFirstCall;
195 this.binding = binding;
196 }
197
198 @Override
199 public boolean onActivityResult(
200 final int requestCode, final int resultCode, final Intent data) {
201 callCount++;
202 if (isFirstCall.get()) {
203 isFirstCall.set(false);
204 binding.removeActivityResultListener(this);
205 }
206 return false;
207 }
208 }
209}
static SkISize times(const SkISize &size, float factor)
void attachToActivity( @NonNull ExclusiveAppComponent< Activity > exclusiveActivity, @NonNull Lifecycle lifecycle)
boolean has(@NonNull Class<? extends FlutterPlugin > pluginClass)
boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
PlatformViewsController getPlatformViewsController()
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63