From 13bd607393f8fd6398159d12f8da5261044e3bee Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 24 Sep 2020 18:45:57 -0700 Subject: [PATCH 1/3] Account for views being dragged --- .../mutatorsstack/FlutterMutatorView.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java index d910ab82f2eb0..f1af7534ba869 100644 --- a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java +++ b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java @@ -19,6 +19,8 @@ public class FlutterMutatorView extends FrameLayout { private float screenDensity; private int left; private int top; + private int prevLeft; + private int prevTop; private final AndroidTouchProcessor androidTouchProcessor; @@ -122,11 +124,25 @@ public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } - // Mutator view itself doesn't rotate, scale, skew, etc. - // we only need to account for translation. - Matrix screenMatrix = new Matrix(); - screenMatrix.postTranslate(left, top); - + final Matrix screenMatrix = new Matrix(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + prevLeft = left; + prevTop = top; + screenMatrix.postTranslate(left, top); + break; + case MotionEvent.ACTION_MOVE: + // While the view is dragged, use the left and top positions as + // they were at the moment the touch event fired. + screenMatrix.postTranslate(prevLeft, prevTop); + prevLeft = left; + prevTop = top; + break; + case MotionEvent.ACTION_UP: + screenMatrix.postTranslate(left, top); + break; + } return androidTouchProcessor.onTouchEvent(event, screenMatrix); } } From a467a61100e656f4a8f2ab1487665d08f6c40fd5 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 24 Sep 2020 19:36:25 -0700 Subject: [PATCH 2/3] Test --- shell/platform/android/BUILD.gn | 1 + .../test/io/flutter/FlutterTestSuite.java | 2 + .../mutatorsstack/FlutterMutatorViewTest.java | 79 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 shell/platform/android/test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 52373e3c74ffa..f5714f1fd0fa6 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -439,6 +439,7 @@ action("robolectric_tests") { "test/io/flutter/embedding/engine/dart/DartExecutorTest.java", "test/io/flutter/embedding/engine/loader/ApplicationInfoLoaderTest.java", "test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java", + "test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java", "test/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistryTest.java", "test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java", "test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java", diff --git a/shell/platform/android/test/io/flutter/FlutterTestSuite.java b/shell/platform/android/test/io/flutter/FlutterTestSuite.java index bdc130ef87e9a..c96f8d5dd5770 100644 --- a/shell/platform/android/test/io/flutter/FlutterTestSuite.java +++ b/shell/platform/android/test/io/flutter/FlutterTestSuite.java @@ -18,6 +18,7 @@ import io.flutter.embedding.engine.RenderingComponentTest; import io.flutter.embedding.engine.loader.ApplicationInfoLoaderTest; import io.flutter.embedding.engine.loader.FlutterLoaderTest; +import io.flutter.embedding.engine.mutatorsstack.FlutterMutatorViewTest; import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistryTest; import io.flutter.embedding.engine.renderer.FlutterRendererTest; import io.flutter.embedding.engine.systemchannels.KeyEventChannelTest; @@ -60,6 +61,7 @@ FlutterJNITest.class, FlutterLaunchTests.class, FlutterLoaderTest.class, + FlutterMutatorViewTest.class, FlutterShellArgsTest.class, FlutterRendererTest.class, FlutterShellArgsTest.class, diff --git a/shell/platform/android/test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java b/shell/platform/android/test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java new file mode 100644 index 0000000000000..35f412058be61 --- /dev/null +++ b/shell/platform/android/test/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorViewTest.java @@ -0,0 +1,79 @@ +package io.flutter.embedding.engine.mutatorsstack; + +import static junit.framework.TestCase.*; +import static org.mockito.Mockito.*; + +import android.graphics.Matrix; +import android.view.MotionEvent; +import io.flutter.embedding.android.AndroidTouchProcessor; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@Config(manifest = Config.NONE) +@RunWith(RobolectricTestRunner.class) +public class FlutterMutatorViewTest { + + @Test + public void canDragViews() { + final AndroidTouchProcessor touchProcessor = mock(AndroidTouchProcessor.class); + final FlutterMutatorView view = + new FlutterMutatorView(RuntimeEnvironment.systemContext, 1.0f, touchProcessor); + final FlutterMutatorsStack mutatorStack = mock(FlutterMutatorsStack.class); + + assertTrue(view.onInterceptTouchEvent(mock(MotionEvent.class))); + + { + view.readyToDisplay(mutatorStack, /*left=*/ 1, /*top=*/ 2, /*width=*/ 0, /*height=*/ 0); + view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0)); + final ArgumentCaptor matrixCaptor = ArgumentCaptor.forClass(Matrix.class); + verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture()); + + final Matrix screenMatrix = new Matrix(); + screenMatrix.postTranslate(1, 2); + assertTrue(matrixCaptor.getValue().equals(screenMatrix)); + } + + reset(touchProcessor); + + { + view.readyToDisplay(mutatorStack, /*left=*/ 3, /*top=*/ 4, /*width=*/ 0, /*height=*/ 0); + view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0.0f, 0.0f, 0)); + final ArgumentCaptor matrixCaptor = ArgumentCaptor.forClass(Matrix.class); + verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture()); + + final Matrix screenMatrix = new Matrix(); + screenMatrix.postTranslate(1, 2); + assertTrue(matrixCaptor.getValue().equals(screenMatrix)); + } + + reset(touchProcessor); + + { + view.readyToDisplay(mutatorStack, /*left=*/ 5, /*top=*/ 6, /*width=*/ 0, /*height=*/ 0); + view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0.0f, 0.0f, 0)); + final ArgumentCaptor matrixCaptor = ArgumentCaptor.forClass(Matrix.class); + verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture()); + + final Matrix screenMatrix = new Matrix(); + screenMatrix.postTranslate(3, 4); + assertTrue(matrixCaptor.getValue().equals(screenMatrix)); + } + + reset(touchProcessor); + + { + view.readyToDisplay(mutatorStack, /*left=*/ 7, /*top=*/ 8, /*width=*/ 0, /*height=*/ 0); + view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0)); + final ArgumentCaptor matrixCaptor = ArgumentCaptor.forClass(Matrix.class); + verify(touchProcessor).onTouchEvent(any(), matrixCaptor.capture()); + + final Matrix screenMatrix = new Matrix(); + screenMatrix.postTranslate(7, 8); + assertTrue(matrixCaptor.getValue().equals(screenMatrix)); + } + } +} From 78bac30d3afbc57b041cfe970c016b0c326d2c69 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 25 Sep 2020 08:51:51 -0700 Subject: [PATCH 3/3] Default case --- .../embedding/engine/mutatorsstack/FlutterMutatorView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java index f1af7534ba869..25089bbc4d781 100644 --- a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java +++ b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java @@ -140,6 +140,7 @@ public boolean onTouchEvent(MotionEvent event) { prevTop = top; break; case MotionEvent.ACTION_UP: + default: screenMatrix.postTranslate(left, top); break; }