Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
}
2 changes: 2 additions & 0 deletions shell/platform/android/test/io/flutter/FlutterTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -60,6 +61,7 @@
FlutterJNITest.class,
FlutterLaunchTests.class,
FlutterLoaderTest.class,
FlutterMutatorViewTest.class,
FlutterShellArgsTest.class,
FlutterRendererTest.class,
FlutterShellArgsTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Matrix> 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<Matrix> 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<Matrix> 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<Matrix> 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));
}
}
}