Skip to content

Commit db99912

Browse files
author
Emmanuel Garcia
authored
Support dragging native platform views (flutter#21396)
1 parent 08cf725 commit db99912

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed

shell/platform/android/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ action("robolectric_tests") {
439439
"test/io/flutter/embedding/engine/dart/DartExecutorTest.java",
440440
"test/io/flutter/embedding/engine/loader/ApplicationInfoLoaderTest.java",
441441
"test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java",
442+
"test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java",
442443
"test/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistryTest.java",
443444
"test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java",
444445
"test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java",

shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public class FlutterMutatorView extends FrameLayout {
1919
private float screenDensity;
2020
private int left;
2121
private int top;
22+
private int prevLeft;
23+
private int prevTop;
2224

2325
private final AndroidTouchProcessor androidTouchProcessor;
2426

@@ -122,11 +124,26 @@ public boolean onTouchEvent(MotionEvent event) {
122124
return super.onTouchEvent(event);
123125
}
124126

125-
// Mutator view itself doesn't rotate, scale, skew, etc.
126-
// we only need to account for translation.
127-
Matrix screenMatrix = new Matrix();
128-
screenMatrix.postTranslate(left, top);
129-
127+
final Matrix screenMatrix = new Matrix();
128+
129+
switch (event.getAction()) {
130+
case MotionEvent.ACTION_DOWN:
131+
prevLeft = left;
132+
prevTop = top;
133+
screenMatrix.postTranslate(left, top);
134+
break;
135+
case MotionEvent.ACTION_MOVE:
136+
// While the view is dragged, use the left and top positions as
137+
// they were at the moment the touch event fired.
138+
screenMatrix.postTranslate(prevLeft, prevTop);
139+
prevLeft = left;
140+
prevTop = top;
141+
break;
142+
case MotionEvent.ACTION_UP:
143+
default:
144+
screenMatrix.postTranslate(left, top);
145+
break;
146+
}
130147
return androidTouchProcessor.onTouchEvent(event, screenMatrix);
131148
}
132149
}

shell/platform/android/test/io/flutter/FlutterTestSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.flutter.embedding.engine.RenderingComponentTest;
1919
import io.flutter.embedding.engine.loader.ApplicationInfoLoaderTest;
2020
import io.flutter.embedding.engine.loader.FlutterLoaderTest;
21+
import io.flutter.embedding.engine.mutatorsstack.FlutterMutatorViewTest;
2122
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistryTest;
2223
import io.flutter.embedding.engine.renderer.FlutterRendererTest;
2324
import io.flutter.embedding.engine.systemchannels.KeyEventChannelTest;
@@ -60,6 +61,7 @@
6061
FlutterJNITest.class,
6162
FlutterLaunchTests.class,
6263
FlutterLoaderTest.class,
64+
FlutterMutatorViewTest.class,
6365
FlutterShellArgsTest.class,
6466
FlutterRendererTest.class,
6567
FlutterShellArgsTest.class,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.flutter.embedding.engine.mutatorsstack;
2+
3+
import static junit.framework.TestCase.*;
4+
import static org.mockito.Mockito.*;
5+
6+
import android.graphics.Matrix;
7+
import android.view.MotionEvent;
8+
import io.flutter.embedding.android.AndroidTouchProcessor;
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
import org.mockito.ArgumentCaptor;
12+
import org.robolectric.RobolectricTestRunner;
13+
import org.robolectric.RuntimeEnvironment;
14+
import org.robolectric.annotation.Config;
15+
16+
@Config(manifest = Config.NONE)
17+
@RunWith(RobolectricTestRunner.class)
18+
public class FlutterMutatorViewTest {
19+
20+
@Test
21+
public void canDragViews() {
22+
final AndroidTouchProcessor touchProcessor = mock(AndroidTouchProcessor.class);
23+
final FlutterMutatorView view =
24+
new FlutterMutatorView(RuntimeEnvironment.systemContext, 1.0f, touchProcessor);
25+
final FlutterMutatorsStack mutatorStack = mock(FlutterMutatorsStack.class);
26+
27+
assertTrue(view.onInterceptTouchEvent(mock(MotionEvent.class)));
28+
29+
{
30+
view.readyToDisplay(mutatorStack, /*left=*/ 1, /*top=*/ 2, /*width=*/ 0, /*height=*/ 0);
31+
view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0));
32+
final ArgumentCaptor<Matrix> matrixCaptor = ArgumentCaptor.forClass(Matrix.class);
33+
verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture());
34+
35+
final Matrix screenMatrix = new Matrix();
36+
screenMatrix.postTranslate(1, 2);
37+
assertTrue(matrixCaptor.getValue().equals(screenMatrix));
38+
}
39+
40+
reset(touchProcessor);
41+
42+
{
43+
view.readyToDisplay(mutatorStack, /*left=*/ 3, /*top=*/ 4, /*width=*/ 0, /*height=*/ 0);
44+
view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0.0f, 0.0f, 0));
45+
final ArgumentCaptor<Matrix> matrixCaptor = ArgumentCaptor.forClass(Matrix.class);
46+
verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture());
47+
48+
final Matrix screenMatrix = new Matrix();
49+
screenMatrix.postTranslate(1, 2);
50+
assertTrue(matrixCaptor.getValue().equals(screenMatrix));
51+
}
52+
53+
reset(touchProcessor);
54+
55+
{
56+
view.readyToDisplay(mutatorStack, /*left=*/ 5, /*top=*/ 6, /*width=*/ 0, /*height=*/ 0);
57+
view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0.0f, 0.0f, 0));
58+
final ArgumentCaptor<Matrix> matrixCaptor = ArgumentCaptor.forClass(Matrix.class);
59+
verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture());
60+
61+
final Matrix screenMatrix = new Matrix();
62+
screenMatrix.postTranslate(3, 4);
63+
assertTrue(matrixCaptor.getValue().equals(screenMatrix));
64+
}
65+
66+
reset(touchProcessor);
67+
68+
{
69+
view.readyToDisplay(mutatorStack, /*left=*/ 7, /*top=*/ 8, /*width=*/ 0, /*height=*/ 0);
70+
view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0));
71+
final ArgumentCaptor<Matrix> matrixCaptor = ArgumentCaptor.forClass(Matrix.class);
72+
verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture());
73+
74+
final Matrix screenMatrix = new Matrix();
75+
screenMatrix.postTranslate(7, 8);
76+
assertTrue(matrixCaptor.getValue().equals(screenMatrix));
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)