Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
PlatformViewWrapperTest.java
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package io.flutter.plugin.platform;
6
7import static android.view.View.OnFocusChangeListener;
8import static io.flutter.Build.API_LEVELS;
9import static org.junit.Assert.*;
10import static org.mockito.ArgumentMatchers.*;
11import static org.mockito.Mockito.*;
12import static org.mockito.Mockito.spy;
13
14import android.annotation.TargetApi;
15import android.content.Context;
16import android.graphics.Canvas;
17import android.graphics.Color;
18import android.view.View;
19import android.view.View.OnFocusChangeListener;
20import android.view.ViewGroup;
21import android.view.ViewTreeObserver;
22import android.view.accessibility.AccessibilityEvent;
23import android.widget.FrameLayout;
24import androidx.test.core.app.ApplicationProvider;
25import androidx.test.ext.junit.runners.AndroidJUnit4;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28import org.mockito.ArgumentCaptor;
29import org.robolectric.annotation.Config;
30import org.robolectric.annotation.Implementation;
31import org.robolectric.annotation.Implements;
32
33@TargetApi(API_LEVELS.API_31)
34@RunWith(AndroidJUnit4.class)
36 private final Context ctx = ApplicationProvider.getApplicationContext();
37
38 @Test
40 final PlatformViewWrapper wrapper = spy(new PlatformViewWrapper(ctx));
41
42 // Mock Android framework calls.
43 wrapper.invalidateChildInParent(null, null);
44
45 // Verify.
46 verify(wrapper, times(1)).invalidate();
47 }
48
49 @Test
50 public void draw_withoutSurface() {
51 final PlatformViewWrapper wrapper =
52 new PlatformViewWrapper(ctx) {
53 @Override
54 public void onDraw(Canvas canvas) {
55 canvas.drawColor(Color.RED);
56 }
57 };
58 // Test.
59 final Canvas canvas = mock(Canvas.class);
60 wrapper.draw(canvas);
61
62 // Verify.
63 verify(canvas, times(1)).drawColor(Color.RED);
64 }
65
66 @Test
68 final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
69 when(viewTreeObserver.isAlive()).thenReturn(true);
70
71 final PlatformViewWrapper view =
72 new PlatformViewWrapper(ctx) {
73 @Override
74 public ViewTreeObserver getViewTreeObserver() {
75 return viewTreeObserver;
76 }
77
78 @Override
79 public boolean hasFocus() {
80 return true;
81 }
82 };
83
84 final OnFocusChangeListener focusListener = mock(OnFocusChangeListener.class);
85 view.setOnDescendantFocusChangeListener(focusListener);
86
87 final ArgumentCaptor<ViewTreeObserver.OnGlobalFocusChangeListener> focusListenerCaptor =
88 ArgumentCaptor.forClass(ViewTreeObserver.OnGlobalFocusChangeListener.class);
89 verify(viewTreeObserver).addOnGlobalFocusChangeListener(focusListenerCaptor.capture());
90
91 focusListenerCaptor.getValue().onGlobalFocusChanged(null, null);
92 verify(focusListener).onFocusChange(view, true);
93 }
94
95 @Test
97 final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
98 when(viewTreeObserver.isAlive()).thenReturn(true);
99
100 final PlatformViewWrapper view =
101 new PlatformViewWrapper(ctx) {
102 @Override
103 public ViewTreeObserver getViewTreeObserver() {
104 return viewTreeObserver;
105 }
106
107 @Override
108 public boolean hasFocus() {
109 return false;
110 }
111 };
112
113 final OnFocusChangeListener focusListener = mock(OnFocusChangeListener.class);
114 view.setOnDescendantFocusChangeListener(focusListener);
115
116 final ArgumentCaptor<ViewTreeObserver.OnGlobalFocusChangeListener> focusListenerCaptor =
117 ArgumentCaptor.forClass(ViewTreeObserver.OnGlobalFocusChangeListener.class);
118 verify(viewTreeObserver).addOnGlobalFocusChangeListener(focusListenerCaptor.capture());
119
120 focusListenerCaptor.getValue().onGlobalFocusChanged(null, null);
121 verify(focusListener).onFocusChange(view, false);
122 }
123
124 @Test
126 final PlatformViewWrapper view =
127 new PlatformViewWrapper(ctx) {
128 @Override
129 public ViewTreeObserver getViewTreeObserver() {
130 final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
131 when(viewTreeObserver.isAlive()).thenReturn(false);
132 return viewTreeObserver;
133 }
134 };
135 view.setOnDescendantFocusChangeListener(mock(OnFocusChangeListener.class));
136 }
137
138 @Test
140 final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
141 when(viewTreeObserver.isAlive()).thenReturn(true);
142
143 final PlatformViewWrapper view =
144 new PlatformViewWrapper(ctx) {
145 @Override
146 public ViewTreeObserver getViewTreeObserver() {
147 return viewTreeObserver;
148 }
149 };
150
151 assertNull(view.getActiveFocusListener());
152
153 view.setOnDescendantFocusChangeListener(mock(OnFocusChangeListener.class));
154 assertNotNull(view.getActiveFocusListener());
155
156 final ViewTreeObserver.OnGlobalFocusChangeListener activeFocusListener =
158
159 view.setOnDescendantFocusChangeListener(mock(OnFocusChangeListener.class));
160 assertNotNull(view.getActiveFocusListener());
161
162 verify(viewTreeObserver, times(1)).removeOnGlobalFocusChangeListener(activeFocusListener);
163 }
164
165 @Test
167 final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
168 when(viewTreeObserver.isAlive()).thenReturn(true);
169
170 final PlatformViewWrapper view =
171 new PlatformViewWrapper(ctx) {
172 @Override
173 public ViewTreeObserver getViewTreeObserver() {
174 return viewTreeObserver;
175 }
176 };
177
178 assertNull(view.getActiveFocusListener());
179
180 view.setOnDescendantFocusChangeListener(mock(OnFocusChangeListener.class));
181 assertNotNull(view.getActiveFocusListener());
182
183 final ViewTreeObserver.OnGlobalFocusChangeListener activeFocusListener =
185
187 assertNull(view.getActiveFocusListener());
188
190 verify(viewTreeObserver, times(1)).removeOnGlobalFocusChangeListener(activeFocusListener);
191 }
192
193 @Test
194 @Config(
195 shadows = {
196 ShadowFrameLayout.class,
197 ShadowViewGroup.class,
198 })
200 final PlatformViewWrapper wrapperView = new PlatformViewWrapper(ctx);
201
202 final View embeddedView = mock(View.class);
203 wrapperView.addView(embeddedView);
204
205 when(embeddedView.getImportantForAccessibility())
206 .thenReturn(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
207 final boolean eventSent =
208 wrapperView.requestSendAccessibilityEvent(embeddedView, mock(AccessibilityEvent.class));
209 assertFalse(eventSent);
210 }
211
212 @Test
213 @Config(
214 shadows = {
215 ShadowFrameLayout.class,
216 ShadowViewGroup.class,
217 })
219 final PlatformViewWrapper wrapperView = new PlatformViewWrapper(ctx);
220
221 final View embeddedView = mock(View.class);
222 wrapperView.addView(embeddedView);
223
224 when(embeddedView.getImportantForAccessibility())
225 .thenReturn(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
226 boolean eventSent =
227 wrapperView.requestSendAccessibilityEvent(embeddedView, mock(AccessibilityEvent.class));
228 assertTrue(eventSent);
229
230 when(embeddedView.getImportantForAccessibility())
231 .thenReturn(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
232 eventSent =
233 wrapperView.requestSendAccessibilityEvent(embeddedView, mock(AccessibilityEvent.class));
234 assertTrue(eventSent);
235 }
236
237 @Implements(ViewGroup.class)
238 public static class ShadowViewGroup extends org.robolectric.shadows.ShadowViewGroup {
239 @Implementation
240 protected boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
241 return true;
242 }
243 }
244
245 @Implements(FrameLayout.class)
246 public static class ShadowFrameLayout
247 extends io.flutter.plugin.platform.PlatformViewWrapperTest.ShadowViewGroup {}
248}
static SkISize times(const SkISize &size, float factor)
boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event)
void setOnDescendantFocusChangeListener(@NonNull OnFocusChangeListener userFocusListener)
boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event)
ViewParent invalidateChildInParent(int[] location, Rect dirty)
ViewTreeObserver.OnGlobalFocusChangeListener getActiveFocusListener()
FlKeyEvent * event