Add partial gesture injection API
This allows developers to inject gestures that can be interspersed
with assertions, and it allows them to inject custom gestures. A new
receiver scope is introduced next to GestureScope, PartialGestureScope,
which contains the following methods:
* sendDown
* sendMoveTo
* sendMoveBy
* sendUp
* sendCancel
Use the action `doPartialGesture` to execute your partial gestures.
Bug: 152477560
Test: Added new tests for PartialGestureScope methods.
Relnote: "Adds `doPartialGesture` action with PartialGestureScope
receiver that has the methods `sendDown`, `sendMoveTo`, `sendMoveBy`,
`sendUp` and `sendCancel`."
Change-Id: I6b05886b2a2e49ae79a131ac9b6dbb7bdb0fb907
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/LayerTouchTransformTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/LayerTouchTransformTest.kt
index 99b9336..0ba012a 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/LayerTouchTransformTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/LayerTouchTransformTest.kt
@@ -39,9 +39,9 @@
import androidx.ui.layout.preferredSize
import androidx.ui.test.captureToBitmap
import androidx.ui.test.createComposeRule
-import androidx.ui.test.doGesture
+import androidx.ui.test.doPartialGesture
import androidx.ui.test.findByTag
-import androidx.ui.test.sendTouchDown
+import androidx.ui.test.sendDown
import androidx.ui.unit.Px
import androidx.ui.unit.PxPosition
import androidx.ui.unit.dp
@@ -142,7 +142,7 @@
// its bounds
val mappedPosition = PxPosition(Px(342.0f), Px(168.0f))
- val node = findByTag(testTag).doGesture { sendTouchDown(mappedPosition) }
+ val node = findByTag(testTag).doPartialGesture { sendDown(mappedPosition) }
latch = CountDownLatch(1).apply {
await(5, TimeUnit.SECONDS)
diff --git a/ui/ui-test/api/0.1.0-dev11.txt b/ui/ui-test/api/0.1.0-dev11.txt
index 32f50f9..5023596 100644
--- a/ui/ui-test/api/0.1.0-dev11.txt
+++ b/ui/ui-test/api/0.1.0-dev11.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,26 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -212,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/api/current.txt b/ui/ui-test/api/current.txt
index 32f50f9..5023596 100644
--- a/ui/ui-test/api/current.txt
+++ b/ui/ui-test/api/current.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,26 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -212,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/api/public_plus_experimental_0.1.0-dev11.txt b/ui/ui-test/api/public_plus_experimental_0.1.0-dev11.txt
index 32f50f9..5023596 100644
--- a/ui/ui-test/api/public_plus_experimental_0.1.0-dev11.txt
+++ b/ui/ui-test/api/public_plus_experimental_0.1.0-dev11.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,26 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -212,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/api/public_plus_experimental_current.txt b/ui/ui-test/api/public_plus_experimental_current.txt
index 32f50f9..5023596 100644
--- a/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/ui/ui-test/api/public_plus_experimental_current.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,26 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -212,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/api/restricted_0.1.0-dev11.txt b/ui/ui-test/api/restricted_0.1.0-dev11.txt
index f4f19db..5023596 100644
--- a/ui/ui-test/api/restricted_0.1.0-dev11.txt
+++ b/ui/ui-test/api/restricted_0.1.0-dev11.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,27 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void sendTouchDown(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -213,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/api/restricted_current.txt b/ui/ui-test/api/restricted_current.txt
index f4f19db..5023596 100644
--- a/ui/ui-test/api/restricted_current.txt
+++ b/ui/ui-test/api/restricted_current.txt
@@ -6,6 +6,7 @@
method public static void callSemanticsAction(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.semantics.SemanticsPropertyKey<androidx.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<kotlin.Unit>>> key);
method public static androidx.ui.test.SemanticsNodeInteraction doClick(androidx.ui.test.SemanticsNodeInteraction);
method public static androidx.ui.test.SemanticsNodeInteraction doGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.GestureScope,kotlin.Unit> block);
+ method public static androidx.ui.test.SemanticsNodeInteraction doPartialGesture(androidx.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.ui.test.PartialGestureScope,kotlin.Unit> block);
method public static androidx.ui.test.SemanticsNodeInteraction doScrollTo(androidx.ui.test.SemanticsNodeInteraction);
}
@@ -43,6 +44,9 @@
method public static androidx.ui.test.SemanticsNodeInteraction assertValueEquals(androidx.ui.test.SemanticsNodeInteraction, String value);
}
+ public abstract sealed class BaseGestureScope {
+ }
+
public final class BitmapHelpersKt {
method public static void assertPixelColor-9bBi3KA(android.graphics.Bitmap, long expected, int x, int y, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.Color,java.lang.String> error = { color -> "Pixel(" + x + ", " + y + ") expected to be " + expected + ", but was " + color });
method public static void assertPixels(android.graphics.Bitmap, androidx.ui.unit.IntPxSize? expectedSize = null, kotlin.jvm.functions.Function1<? super androidx.ui.unit.IntPxPosition,androidx.ui.graphics.Color> expectedColorProvider);
@@ -182,27 +186,31 @@
method public static androidx.ui.test.SemanticsNodeInteraction findByText(String text, boolean ignoreCase = false);
}
- public final class GestureScope {
+ public final class GestureScope extends androidx.ui.test.BaseGestureScope {
}
public final class GestureScopeKt {
- method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.GestureScope);
- method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static androidx.ui.unit.PxPosition getCenter(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxBounds getGlobalBounds(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.IntPxSize getSize(androidx.ui.test.BaseGestureScope);
+ method public static androidx.ui.unit.PxPosition localToGlobal(androidx.ui.test.BaseGestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendCancel(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
method public static void sendClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendClick(androidx.ui.test.GestureScope);
method public static void sendDoubleClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendDoubleClick(androidx.ui.test.GestureScope);
+ method public static androidx.ui.test.GestureToken sendDown(androidx.ui.test.PartialGestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
method public static void sendLongClick(androidx.ui.test.GestureScope);
+ method public static void sendMoveBy(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition delta);
+ method public static void sendMoveTo(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition position);
method public static void sendSwipe(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, androidx.ui.unit.Duration duration = 200.milliseconds);
method public static void sendSwipeDown(androidx.ui.test.GestureScope);
method public static void sendSwipeLeft(androidx.ui.test.GestureScope);
method public static void sendSwipeRight(androidx.ui.test.GestureScope);
method public static void sendSwipeUp(androidx.ui.test.GestureScope);
method public static void sendSwipeWithVelocity(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition start, androidx.ui.unit.PxPosition end, @FloatRange(from=0.0) float endVelocity, androidx.ui.unit.Duration duration = 200.milliseconds);
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void sendTouchDown(androidx.ui.test.GestureScope, androidx.ui.unit.PxPosition position);
+ method public static void sendUp(androidx.ui.test.PartialGestureScope, androidx.ui.test.GestureToken token, androidx.ui.unit.PxPosition? position = null);
}
public final class GestureToken {
@@ -213,6 +221,9 @@
method public static String dumpToString(androidx.ui.test.SemanticsNodeInteractionCollection);
}
+ public final class PartialGestureScope extends androidx.ui.test.BaseGestureScope {
+ }
+
public final class SelectionResult {
ctor public SelectionResult(java.util.List<androidx.ui.core.semantics.SemanticsNode> selectedNodes, String? customErrorOnNoMatch);
method public String? getCustomErrorOnNoMatch();
diff --git a/ui/ui-test/src/androidTest/AndroidManifest.xml b/ui/ui-test/src/androidTest/AndroidManifest.xml
index 86cb9d3..7ac2dec 100644
--- a/ui/ui-test/src/androidTest/AndroidManifest.xml
+++ b/ui/ui-test/src/androidTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:theme="@style/TestTheme"/>
<activity android:name="androidx.ui.test.CustomActivity"
android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen"/>
- <activity android:name="androidx.ui.test.ActivityWithActionBar" />
+ <activity android:name="androidx.ui.test.gesturescope.ActivityWithActionBar" />
<activity android:name="androidx.ui.test.MultipleActivitiesFindTest$Activity1" />
<activity android:name="androidx.ui.test.MultipleActivitiesFindTest$Activity2" />
<activity android:name="androidx.ui.test.MultipleActivitiesClickTest$Activity1" />
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendClickTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendClickTest.kt
similarity index 97%
rename from ui/ui-test/src/androidTest/java/androidx/ui/test/SendClickTest.kt
rename to ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendClickTest.kt
index 143c07b..98b3c66 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendClickTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendClickTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.ui.test
+package androidx.ui.test.gesturescope
import android.os.Bundle
import android.view.Gravity
@@ -38,6 +38,11 @@
import androidx.ui.layout.preferredSize
import androidx.ui.semantics.Semantics
import androidx.ui.test.android.AndroidComposeTestRule
+import androidx.ui.test.doGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.runOnUiThread
+import androidx.ui.test.sendClick
import androidx.ui.unit.IntPxSize
import androidx.ui.unit.PxPosition
import androidx.ui.unit.px
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendDoubleClickTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendDoubleClickTest.kt
similarity index 96%
rename from ui/ui-test/src/androidTest/java/androidx/ui/test/SendDoubleClickTest.kt
rename to ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendDoubleClickTest.kt
index b356638..401abcd 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendDoubleClickTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendDoubleClickTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.ui.test
+package androidx.ui.test.gesturescope
import androidx.compose.Composable
import androidx.test.filters.MediumTest
@@ -29,6 +29,11 @@
import androidx.ui.layout.preferredSize
import androidx.ui.semantics.Semantics
import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnUiThread
+import androidx.ui.test.sendDoubleClick
import androidx.ui.test.util.PointerInputRecorder
import androidx.ui.test.util.assertTimestampsAreIncreasing
import androidx.ui.unit.Px
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendLongClickTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendLongClickTest.kt
similarity index 93%
rename from ui/ui-test/src/androidTest/java/androidx/ui/test/SendLongClickTest.kt
rename to ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendLongClickTest.kt
index e7b21a7..8366cc4 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendLongClickTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendLongClickTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.ui.test
+package androidx.ui.test.gesturescope
import androidx.compose.Composable
import androidx.test.filters.MediumTest
@@ -22,8 +22,8 @@
import androidx.ui.core.DensityAmbient
import androidx.ui.core.Modifier
import androidx.ui.core.TestTag
-import androidx.ui.core.gesture.longPressGestureFilter
import androidx.ui.core.gesture.LongPressTimeout
+import androidx.ui.core.gesture.longPressGestureFilter
import androidx.ui.foundation.Box
import androidx.ui.graphics.Color
import androidx.ui.layout.Stack
@@ -31,6 +31,11 @@
import androidx.ui.layout.preferredSize
import androidx.ui.layout.wrapContentSize
import androidx.ui.semantics.Semantics
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnUiThread
+import androidx.ui.test.sendLongClick
import androidx.ui.test.util.PointerInputRecorder
import androidx.ui.test.util.areAlmostEqualTo
import androidx.ui.test.util.assertOnlyLastEventIsUp
@@ -70,7 +75,7 @@
}
/**
- * Tests [GestureScope.sendLongClick] without arguments. Verifies that the click is in the middle
+ * Tests [sendLongClick] without arguments. Verifies that the click is in the middle
* of the component, that the gesture has a duration of 600 milliseconds and that all input
* events were on the same location.
*/
@@ -113,7 +118,7 @@
}
/**
- * Tests [GestureScope.sendLongClick] with arguments. Verifies that the click is in the middle
+ * Tests [sendLongClick] with arguments. Verifies that the click is in the middle
* of the component, that the gesture has a duration of 600 milliseconds and that all input
* events were on the same location.
*/
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeTest.kt
similarity index 94%
rename from ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeTest.kt
rename to ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeTest.kt
index 8bdb5e9..f966857 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.ui.test
+package androidx.ui.test.gesturescope
import androidx.compose.Composable
import androidx.test.filters.MediumTest
@@ -28,6 +28,14 @@
import androidx.ui.layout.wrapContentSize
import androidx.ui.semantics.Semantics
import androidx.ui.semantics.testTag
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnUiThread
+import androidx.ui.test.sendSwipeDown
+import androidx.ui.test.sendSwipeLeft
+import androidx.ui.test.sendSwipeRight
+import androidx.ui.test.sendSwipeUp
import androidx.ui.test.util.PointerInputRecorder
import androidx.ui.test.util.assertOnlyLastEventIsUp
import androidx.ui.test.util.assertTimestampsAreIncreasing
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeVelocityTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeVelocityTest.kt
similarity index 96%
rename from ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeVelocityTest.kt
rename to ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeVelocityTest.kt
index 7836d19..252823d 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/SendSwipeVelocityTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/gesturescope/SendSwipeVelocityTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.ui.test
+package androidx.ui.test.gesturescope
import androidx.compose.Composable
import androidx.compose.remember
@@ -33,6 +33,11 @@
import androidx.ui.semantics.Semantics
import androidx.ui.semantics.testTag
import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnUiThread
+import androidx.ui.test.sendSwipeWithVelocity
import androidx.ui.test.util.PointerInputRecorder
import androidx.ui.test.util.assertOnlyLastEventIsUp
import androidx.ui.test.util.assertTimestampsAreIncreasing
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendCancelTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendCancelTest.kt
new file mode 100644
index 0000000..b6c4ee7
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendCancelTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.partialgesturescope
+
+import androidx.test.filters.MediumTest
+import androidx.ui.graphics.Color
+import androidx.ui.test.GestureToken
+import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doPartialGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.sendCancel
+import androidx.ui.test.sendDown
+import androidx.ui.test.util.ClickableTestBox
+import androidx.ui.test.util.PointerInputRecorder
+import androidx.ui.test.util.assertTimestampsAreIncreasing
+import androidx.ui.test.util.inMilliseconds
+import androidx.ui.unit.PxPosition
+import androidx.ui.unit.px
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private val width = 200.px
+private val height = 200.px
+
+private const val tag = "widget"
+
+@MediumTest
+@RunWith(Parameterized::class)
+class SendCancelTest(private val config: TestConfig) {
+ data class TestConfig(val cancelPosition: PxPosition?) {
+ val downPosition = PxPosition(1.px, 1.px)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> {
+ return mutableListOf<TestConfig>().apply {
+ for (x in listOf(2.px, 99.px)) {
+ for (y in listOf(3.px, 53.px)) {
+ add(TestConfig(PxPosition(x, y)))
+ }
+ }
+ add(TestConfig(null))
+ }
+ }
+ }
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val dispatcherRule = AndroidInputDispatcher.TestRule(disableDispatchInRealTime = true)
+ @get:Rule
+ val inputDispatcherRule: TestRule = dispatcherRule
+
+ private lateinit var recorder: PointerInputRecorder
+ private val expectedCancelPosition = config.cancelPosition ?: config.downPosition
+
+ @Test
+ fun testSendCancel() {
+ // Given some content
+ recorder = PointerInputRecorder()
+ composeTestRule.setContent {
+ ClickableTestBox(width, height, Color.Yellow, tag, recorder)
+ }
+
+ // When we inject a down event followed by a cancel event
+ lateinit var token: GestureToken
+ findByTag(tag).doPartialGesture { token = sendDown(config.downPosition) }
+ findByTag(tag).doPartialGesture { sendCancel(token, config.cancelPosition) }
+
+ runOnIdleCompose {
+ recorder.run {
+ // Then we have only recorded 1 down event
+ assertTimestampsAreIncreasing()
+ assertThat(events).hasSize(1)
+
+ // But the information in the token matches the cancel event
+ assertThat(token.downTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.eventTime)
+ .isEqualTo(events[0].timestamp.inMilliseconds() + dispatcherRule.eventPeriod)
+ assertThat(token.lastPosition).isEqualTo(expectedCancelPosition)
+ }
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendDownTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendDownTest.kt
new file mode 100644
index 0000000..c56472e
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendDownTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.partialgesturescope
+
+import androidx.test.filters.MediumTest
+import androidx.ui.graphics.Color
+import androidx.ui.test.GestureToken
+import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doPartialGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.sendDown
+import androidx.ui.test.util.ClickableTestBox
+import androidx.ui.test.util.PointerInputRecorder
+import androidx.ui.test.util.assertTimestampsAreIncreasing
+import androidx.ui.test.util.inMilliseconds
+import androidx.ui.unit.PxPosition
+import androidx.ui.unit.px
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private val width = 200.px
+private val height = 200.px
+
+private const val tag = "widget"
+
+@MediumTest
+@RunWith(Parameterized::class)
+class SendDownTest(private val config: TestConfig) {
+ data class TestConfig(val position: PxPosition)
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> {
+ return mutableListOf<TestConfig>().apply {
+ for (x in listOf(1.px, 99.px)) {
+ for (y in listOf(2.px, 53.px)) {
+ add(TestConfig(PxPosition(x, y)))
+ }
+ }
+ }
+ }
+ }
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @get:Rule
+ val inputDispatcherRule: TestRule = AndroidInputDispatcher.TestRule(
+ disableDispatchInRealTime = true
+ )
+
+ private lateinit var recorder: PointerInputRecorder
+ private val expectedPosition = config.position
+
+ @Test
+ fun testSendDown() {
+ // Given some content
+ recorder = PointerInputRecorder()
+ composeTestRule.setContent {
+ ClickableTestBox(width, height, Color.Yellow, tag, recorder)
+ }
+
+ // When we inject a down event
+ lateinit var token: GestureToken
+ findByTag(tag).doPartialGesture { token = sendDown(config.position) }
+
+ runOnIdleCompose {
+ recorder.run {
+ // Then we have recorded 1 down event
+ assertTimestampsAreIncreasing()
+ assertThat(events).hasSize(1)
+ assertThat(events[0].down).isTrue()
+ assertThat(events[0].position).isEqualTo(expectedPosition)
+
+ // That matches the information in the token
+ assertThat(token.downTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.eventTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.lastPosition).isEqualTo(expectedPosition)
+ }
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveByTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveByTest.kt
new file mode 100644
index 0000000..acc538a
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveByTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.partialgesturescope
+
+import androidx.test.filters.MediumTest
+import androidx.ui.graphics.Color
+import androidx.ui.test.GestureToken
+import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doPartialGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.sendDown
+import androidx.ui.test.sendMoveBy
+import androidx.ui.test.util.ClickableTestBox
+import androidx.ui.test.util.PointerInputRecorder
+import androidx.ui.test.util.assertTimestampsAreIncreasing
+import androidx.ui.test.util.inMilliseconds
+import androidx.ui.unit.PxPosition
+import androidx.ui.unit.inMilliseconds
+import androidx.ui.unit.px
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private val width = 200.px
+private val height = 200.px
+
+private const val tag = "widget"
+
+@MediumTest
+@RunWith(Parameterized::class)
+class SendMoveByTest(private val config: TestConfig) {
+ data class TestConfig(val moveByDelta: PxPosition) {
+ val downPosition = PxPosition(1.px, 1.px)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> {
+ return mutableListOf<TestConfig>().apply {
+ for (x in listOf(2.px, (-100).px)) {
+ for (y in listOf(3.px, (-530).px)) {
+ add(TestConfig(PxPosition(x, y)))
+ }
+ }
+ }
+ }
+ }
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val dispatcherRule = AndroidInputDispatcher.TestRule(disableDispatchInRealTime = true)
+ @get:Rule
+ val inputDispatcherRule: TestRule = dispatcherRule
+
+ private lateinit var recorder: PointerInputRecorder
+ private val expectedEndPosition = config.downPosition + config.moveByDelta
+
+ @Test
+ fun testSendMoveBy() {
+ // Given some content
+ recorder = PointerInputRecorder()
+ composeTestRule.setContent {
+ ClickableTestBox(width, height, Color.Yellow, tag, recorder)
+ }
+
+ // When we inject a down event followed by a move event
+ lateinit var token: GestureToken
+ findByTag(tag).doPartialGesture { token = sendDown(config.downPosition) }
+ findByTag(tag).doPartialGesture { sendMoveBy(token, config.moveByDelta) }
+
+ runOnIdleCompose {
+ recorder.run {
+ // Then we have recorded 1 down event and 1 move event
+ assertTimestampsAreIncreasing()
+ assertThat(events).hasSize(2)
+ assertThat(events[1].down).isTrue()
+ assertThat(events[1].position).isEqualTo(expectedEndPosition)
+ assertThat((events[1].timestamp - events[0].timestamp).inMilliseconds())
+ .isEqualTo(dispatcherRule.eventPeriod)
+
+ // And the information in the token matches the last move event
+ assertThat(token.downTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.eventTime).isEqualTo(events[1].timestamp.inMilliseconds())
+ assertThat(token.lastPosition).isEqualTo(expectedEndPosition)
+ }
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveToTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveToTest.kt
new file mode 100644
index 0000000..86092f5
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendMoveToTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.partialgesturescope
+
+import androidx.test.filters.MediumTest
+import androidx.ui.graphics.Color
+import androidx.ui.test.GestureToken
+import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doPartialGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.sendDown
+import androidx.ui.test.sendMoveTo
+import androidx.ui.test.util.ClickableTestBox
+import androidx.ui.test.util.PointerInputRecorder
+import androidx.ui.test.util.assertTimestampsAreIncreasing
+import androidx.ui.test.util.inMilliseconds
+import androidx.ui.unit.PxPosition
+import androidx.ui.unit.inMilliseconds
+import androidx.ui.unit.px
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private val width = 200.px
+private val height = 200.px
+
+private const val tag = "widget"
+
+@MediumTest
+@RunWith(Parameterized::class)
+class SendMoveToTest(private val config: TestConfig) {
+ data class TestConfig(val moveToPosition: PxPosition) {
+ val downPosition = PxPosition(1.px, 1.px)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> {
+ return mutableListOf<TestConfig>().apply {
+ for (x in listOf(2.px, 99.px)) {
+ for (y in listOf(3.px, 53.px)) {
+ add(TestConfig(PxPosition(x, y)))
+ }
+ }
+ }
+ }
+ }
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val dispatcherRule = AndroidInputDispatcher.TestRule(disableDispatchInRealTime = true)
+ @get:Rule
+ val inputDispatcherRule: TestRule = dispatcherRule
+
+ private lateinit var recorder: PointerInputRecorder
+ private val expectedEndPosition = config.moveToPosition
+
+ @Test
+ fun testSendMoveTo() {
+ // Given some content
+ recorder = PointerInputRecorder()
+ composeTestRule.setContent {
+ ClickableTestBox(width, height, Color.Yellow, tag, recorder)
+ }
+
+ // When we inject a down event followed by a move event
+ lateinit var token: GestureToken
+ findByTag(tag).doPartialGesture { token = sendDown(config.downPosition) }
+ findByTag(tag).doPartialGesture { sendMoveTo(token, config.moveToPosition) }
+
+ runOnIdleCompose {
+ recorder.run {
+ // Then we have recorded 1 down event and 1 move event
+ assertTimestampsAreIncreasing()
+ assertThat(events).hasSize(2)
+ assertThat(events[1].down).isTrue()
+ assertThat(events[1].position).isEqualTo(expectedEndPosition)
+ assertThat((events[1].timestamp - events[0].timestamp).inMilliseconds())
+ .isEqualTo(dispatcherRule.eventPeriod)
+
+ // And the information in the token matches the last move event
+ assertThat(token.downTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.eventTime).isEqualTo(events[1].timestamp.inMilliseconds())
+ assertThat(token.lastPosition).isEqualTo(expectedEndPosition)
+ }
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendUpTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendUpTest.kt
new file mode 100644
index 0000000..6bc448b
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/partialgesturescope/SendUpTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.partialgesturescope
+
+import androidx.test.filters.MediumTest
+import androidx.ui.graphics.Color
+import androidx.ui.test.GestureToken
+import androidx.ui.test.android.AndroidInputDispatcher
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.doPartialGesture
+import androidx.ui.test.findByTag
+import androidx.ui.test.runOnIdleCompose
+import androidx.ui.test.sendDown
+import androidx.ui.test.sendUp
+import androidx.ui.test.util.ClickableTestBox
+import androidx.ui.test.util.PointerInputRecorder
+import androidx.ui.test.util.assertTimestampsAreIncreasing
+import androidx.ui.test.util.inMilliseconds
+import androidx.ui.unit.PxPosition
+import androidx.ui.unit.inMilliseconds
+import androidx.ui.unit.px
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private val width = 200.px
+private val height = 200.px
+
+private const val tag = "widget"
+
+@MediumTest
+@RunWith(Parameterized::class)
+class SendUpTest(private val config: TestConfig) {
+ data class TestConfig(val upPosition: PxPosition?) {
+ val downPosition: PxPosition = PxPosition(1.px, 1.px)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> {
+ return mutableListOf<TestConfig>().apply {
+ for (x in listOf(2.px, 99.px)) {
+ for (y in listOf(3.px, 53.px)) {
+ add(TestConfig(PxPosition(x, y)))
+ }
+ }
+ add(TestConfig(null))
+ }
+ }
+ }
+
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private val dispatcherRule = AndroidInputDispatcher.TestRule(disableDispatchInRealTime = true)
+ @get:Rule
+ val inputDispatcherRule: TestRule = dispatcherRule
+
+ private lateinit var recorder: PointerInputRecorder
+ private val expectedEndPosition = config.upPosition ?: config.downPosition
+
+ @Test
+ fun testSendUp() {
+ // Given some content
+ recorder = PointerInputRecorder()
+ composeTestRule.setContent {
+ ClickableTestBox(width, height, Color.Yellow, tag, recorder)
+ }
+
+ // When we inject a down event followed by an up event
+ lateinit var token: GestureToken
+ findByTag(tag).doPartialGesture { token = sendDown(config.downPosition) }
+ findByTag(tag).doPartialGesture { sendUp(token, config.upPosition) }
+
+ runOnIdleCompose {
+ recorder.run {
+ // Then we have recorded 1 down event and 1 move event
+ assertTimestampsAreIncreasing()
+ assertThat(events).hasSize(2)
+ assertThat(events[1].down).isFalse()
+ assertThat(events[1].position).isEqualTo(expectedEndPosition)
+ assertThat((events[1].timestamp - events[0].timestamp).inMilliseconds())
+ .isEqualTo(dispatcherRule.eventPeriod)
+
+ // And the information in the token matches the last move event
+ assertThat(token.downTime).isEqualTo(events[0].timestamp.inMilliseconds())
+ assertThat(token.eventTime).isEqualTo(events[1].timestamp.inMilliseconds())
+ assertThat(token.lastPosition).isEqualTo(expectedEndPosition)
+ }
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/util/ClickableTestBox.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/util/ClickableTestBox.kt
new file mode 100644
index 0000000..ec46184
--- /dev/null
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/util/ClickableTestBox.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.test.util
+
+import androidx.compose.Composable
+import androidx.ui.core.DensityAmbient
+import androidx.ui.core.pointerinput.PointerInputModifier
+import androidx.ui.foundation.Box
+import androidx.ui.graphics.Color
+import androidx.ui.layout.size
+import androidx.ui.semantics.Semantics
+import androidx.ui.semantics.testTag
+import androidx.ui.unit.Px
+
+@Composable
+fun ClickableTestBox(
+ width: Px,
+ height: Px,
+ color: Color,
+ tag: String,
+ pointerInputModifier: PointerInputModifier
+) {
+ Semantics(container = true, properties = { testTag = tag }) {
+ with(DensityAmbient.current) {
+ Box(
+ modifier = pointerInputModifier.size(width.toDp(), height.toDp()),
+ backgroundColor = color
+ )
+ }
+ }
+}
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/util/PointerInputs.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/util/PointerInputs.kt
index 3c25ab5..2321adc 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/util/PointerInputs.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/util/PointerInputs.kt
@@ -27,6 +27,7 @@
import androidx.ui.unit.Duration
import androidx.ui.unit.IntPxSize
import androidx.ui.unit.PxPosition
+import androidx.ui.unit.Uptime
import com.google.common.truth.Truth.assertThat
class PointerInputRecorder : PointerInputModifier {
@@ -67,6 +68,8 @@
}
}
+fun Uptime.inMilliseconds(): Long = nanoseconds / 1_000_000
+
val PointerInputRecorder.downEvents get() = events.filter { it.down }
val PointerInputRecorder.recordedDuration: Duration
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/Actions.kt b/ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
index 9a5e8ab..e71f275 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
@@ -84,10 +84,12 @@
* Executes the gestures specified in the given block.
*
* Example usage:
+ * ```
* findByTag("myWidget")
* .doGesture {
* sendSwipeUp()
* }
+ * ```
*/
fun SemanticsNodeInteraction.doGesture(
block: GestureScope.() -> Unit
@@ -98,6 +100,35 @@
}
/**
+ * Executes the (partial) gesture specified in the given block. The gesture doesn't need to be
+ * complete and can be resumed later. It is the responsibility of the caller to make sure partial
+ * gestures don't leave the test in an inconsistent state.
+ *
+ * When [sending the down event][sendDown], a token is returned which needs to be used in all
+ * subsequent events of this gesture.
+ *
+ * Example usage:
+ * ```
+ * lateinit var token: GestureToken
+ * findByTag("myWidget")
+ * .doPartialGesture {
+ * token = sendDown()
+ * }
+ * .assertHasClickAction()
+ * .doPartialGesture {
+ * sendUp(token)
+ * }
+ * ```
+ */
+fun SemanticsNodeInteraction.doPartialGesture(
+ block: PartialGestureScope.() -> Unit
+): SemanticsNodeInteraction {
+ val scope = PartialGestureScope(this)
+ scope.block()
+ return this
+}
+
+/**
* Provides support to call custom semantics actions on this node.
*
* This method is supposed to be used for actions with parameters.
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/GestureScope.kt b/ui/ui-test/src/main/java/androidx/ui/test/GestureScope.kt
index a8cf4ac..0a4675b 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/GestureScope.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/GestureScope.kt
@@ -17,7 +17,6 @@
package androidx.ui.test
import androidx.annotation.FloatRange
-import androidx.annotation.RestrictTo
import androidx.ui.core.gesture.LongPressTimeout
import androidx.ui.unit.Duration
import androidx.ui.unit.IntPxSize
@@ -34,26 +33,6 @@
import kotlin.math.sin
/**
- * An object that has an associated component in which one can inject gestures. The gestures can
- * be injected by calling methods defined on [GestureScope], such as [sendSwipeUp]. The associated
- * component is the [SemanticsNodeInteraction] found by one of the finder methods such as [findByTag].
- *
- * Example usage:
- * findByTag("myWidget")
- * .doGesture {
- * sendSwipeUp()
- * }
- */
-class GestureScope internal constructor(
- internal val semanticsNodeInteraction: SemanticsNodeInteraction
-) {
- // TODO(b/133217292): Better error: explain which gesture couldn't be performed
- // TODO: Avoid calling this multiple times as it involves synchronization.
- internal inline val semanticsNode
- get() = semanticsNodeInteraction.fetchSemanticsNode("Failed to perform a gesture.")
-}
-
-/**
* The distance of a swipe's start position from the node's edge, in terms of the node's length.
* We do not start the swipe exactly on the node's edge, but somewhat more inward, since swiping
* from the exact edge may behave in an unexpected way (e.g. may open a navigation drawer).
@@ -66,17 +45,26 @@
*/
private val doubleClickDelay = 145.milliseconds
+sealed class BaseGestureScope(
+ internal val semanticsNodeInteraction: SemanticsNodeInteraction
+) {
+ // TODO(b/133217292): Better error: explain which gesture couldn't be performed
+ // TODO: Avoid calling this multiple times as it involves synchronization.
+ internal inline val semanticsNode
+ get() = semanticsNodeInteraction.fetchSemanticsNode("Failed to perform a gesture.")
+}
+
/**
* Returns the size of the component we're interacting with
*/
-val GestureScope.size: IntPxSize
+val BaseGestureScope.size: IntPxSize
get() = semanticsNode.size
/**
* Returns the center of the component we're interacting with, in the component's local
* coordinate system, where (0.px, 0.px) is the top left corner of the component.
*/
-val GestureScope.center: PxPosition
+val BaseGestureScope.center: PxPosition
get() {
return PxPosition(size.width / 2, size.height / 2)
}
@@ -84,7 +72,7 @@
/**
* Returns the global bounds of the component we're interacting with
*/
-val GestureScope.globalBounds: PxBounds
+val BaseGestureScope.globalBounds: PxBounds
get() = semanticsNode.globalBounds
/**
@@ -92,13 +80,31 @@
*
* @param position A position in local coordinates
*/
-fun GestureScope.localToGlobal(position: PxPosition): PxPosition {
+fun BaseGestureScope.localToGlobal(position: PxPosition): PxPosition {
val bounds = globalBounds
return position + PxPosition(bounds.left, bounds.top)
}
/**
- * Performs a click gesture on the given [position] on the associated component. The [position]
+ * The receiver scope for injecting gestures on the node identified by the
+ * [semanticsNodeInteraction]. Gestures can be injected by calling methods defined on
+ * [GestureScope], such as [sendSwipeUp]. The [semanticsNodeInteraction] can be found by one of
+ * the finder methods such as [findByTag].
+ *
+ * Example usage:
+ * ```
+ * findByTag("myWidget")
+ * .doGesture {
+ * sendSwipeUp()
+ * }
+ * ```
+ */
+class GestureScope internal constructor(
+ semanticsNodeInteraction: SemanticsNodeInteraction
+) : BaseGestureScope(semanticsNodeInteraction)
+
+/**
+ * Performs a click gesture at the given [position] on the associated component. The [position]
* is in the component's local coordinate system, where (0.px, 0.px) is the top left corner of
* the component.
*
@@ -113,24 +119,6 @@
}
/**
- * Dispatches a down event on the given [position] on the associated component. The [position]
- * is in the component's local coordinate system, where (0.px, 0.px) is the top left corner of
- * the component.
- *
- * Throws [AssertionError] when the component doesn't have a bounding rectangle set
- *
- * @param position The position of the down event, in the component's local coordinate system
- *
- * @suppress
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-fun GestureScope.sendTouchDown(position: PxPosition) {
- semanticsNodeInteraction.sendInput {
- it.sendDown(localToGlobal(position))
- }
-}
-
-/**
* Performs a click gesture on the associated component. The click is done in the middle of the
* component's bounds.
*
@@ -141,7 +129,7 @@
}
/**
- * Performs a long click gesture on the given [position] on the associated component. There will
+ * Performs a long click gesture at the given [position] on the associated component. There will
* be [LongPressTimeout] + 100 milliseconds time between the down and the up event. The
* [position] is in the component's local coordinate system, where (0.px, 0.px) is the top left
* corner of the component.
@@ -156,7 +144,7 @@
}
/**
- * Performs a long click gesture on the middle of the associated component. There will
+ * Performs a long click gesture at the middle of the associated component. There will
* be [LongPressTimeout] + 100 milliseconds time between the down and the up event.
*
* Throws [AssertionError] when the component doesn't have a bounding rectangle set
@@ -166,7 +154,7 @@
}
/**
- * Performs a double click gesture on the given [position] on the associated component. The
+ * Performs a double click gesture at the given [position] on the associated component. The
* [position] is in the component's local coordinate system, where (0.px, 0.px) is the top left
* corner of the component.
*
@@ -401,7 +389,29 @@
}
/**
- * A token to be shared between individual motion events that form a single gesture.
+ * The receiver scope for injecting partial gestures on the node identified by the
+ * [semanticsNodeInteraction]. Gestures can be injected by calling methods defined on
+ * [PartialGestureScope], such as [sendDown]. The [semanticsNodeInteraction] can be found by one
+ * of the finder methods such as [findByTag].
+ *
+ * Example usage:
+ * ```
+ * val position = PxPosition(10.px, 10.px)
+ * lateinit var token: GestureToken
+ * findByTag("myWidget")
+ * .doPartialGesture { token = sendDown(position) }
+ * .assertIsDisplayed()
+ * .doPartialGesture { sendUp(token, position) }
+ * ```
+ */
+class PartialGestureScope internal constructor(
+ semanticsNodeInteraction: SemanticsNodeInteraction
+) : BaseGestureScope(semanticsNodeInteraction)
+
+/**
+ * A token to be shared between individual motion events that form a single gesture. It is
+ * generated by the [sendDown] partial gesture, and must be passed to all subsequent events of
+ * the gesture, such as [sendMoveTo] and [sendUp].
*/
class GestureToken internal constructor(
internal val downTime: Long,
@@ -410,3 +420,86 @@
internal var eventTime: Long = downTime
internal var finished: Boolean = false
}
+
+/**
+ * Sends a down event at the given [position] on the associated component. The [position] is in
+ * the component's local coordinate system, where (0.px, 0.px) is the top left corner of the
+ * component. The returned token needs to be used in all subsequent events of this gesture.
+ *
+ * @param position The position of the down event, in the component's local coordinate system
+ * @return A token that identifies this gesture and must be passed to all subsequent events that
+ * are part of this gesture.
+ */
+fun PartialGestureScope.sendDown(position: PxPosition): GestureToken {
+ val globalPosition = localToGlobal(position)
+ lateinit var token: GestureToken
+ semanticsNodeInteraction.sendInput {
+ token = it.sendDown(globalPosition)
+ }
+ return token
+}
+
+/**
+ * Sends a move event at the given [position] on the associated component. The [position] is in
+ * the component's local coordinate system, where (0.px, 0.px) is the top left corner of the
+ * component.
+ *
+ * @param token The token returned from the corresponding [down event][sendDown] that started
+ * this gesture.
+ * @param position The position of the move event, in the component's local coordinate system
+ */
+fun PartialGestureScope.sendMoveTo(token: GestureToken, position: PxPosition) {
+ val globalPosition = localToGlobal(position)
+ semanticsNodeInteraction.sendInput {
+ it.sendMove(token, globalPosition)
+ }
+}
+
+/**
+ * Sends a move event on the associated component, using the last used coordinate and moving it
+ * by the given [delta].
+ *
+ * @param token The token returned from the corresponding [down event][sendDown] that started
+ * this gesture.
+ * @param delta The position for this move event, relative to the last sent event. For example,
+ * `delta = PxPosition(10.px, -10.px) will add 10.px to the last event's x-position, and subtract
+ * 10.px from the last event's y-position.
+ */
+fun PartialGestureScope.sendMoveBy(token: GestureToken, delta: PxPosition) {
+ val globalPosition = token.lastPosition + delta
+ semanticsNodeInteraction.sendInput {
+ it.sendMove(token, globalPosition)
+ }
+}
+
+/**
+ * Sends an up event at the given [position] on the associated component. If [position] is
+ * omitted, the position of the previous event is used. The [position] is in the component's
+ * local coordinate system, where (0.px, 0.px) is the top left corner of the component.
+ *
+ * @param token The token returned from the corresponding [down event][sendDown] that started
+ * this gesture.
+ * @param position The position of the up event, in the component's local coordinate system
+ */
+fun PartialGestureScope.sendUp(token: GestureToken, position: PxPosition? = null) {
+ val globalPosition = position?.let { localToGlobal(it) } ?: token.lastPosition
+ semanticsNodeInteraction.sendInput {
+ it.sendUp(token, globalPosition)
+ }
+}
+
+/**
+ * Sends a cancel event at the given [position] on the associated component. If [position] is
+ * omitted, the position of the previous event is used. The [position] is in the component's
+ * local coordinate system, where (0.px, 0.px) is the top left corner of the component.
+ *
+ * @param token The token returned from the corresponding [down event][sendDown] that started
+ * this gesture.
+ * @param position The position of the cancel event, in the component's local coordinate system
+ */
+fun PartialGestureScope.sendCancel(token: GestureToken, position: PxPosition? = null) {
+ val globalPosition = position?.let { localToGlobal(it) } ?: token.lastPosition
+ semanticsNodeInteraction.sendInput {
+ it.sendCancel(token, globalPosition)
+ }
+}
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidInputDispatcher.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidInputDispatcher.kt
index 4c81ec9..bb03972 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidInputDispatcher.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidInputDispatcher.kt
@@ -268,13 +268,17 @@
* immediately without blocking. See also [dispatchInRealTime].
* @param eventPeriodOverride If set, specifies a different period in milliseconds between
* two consecutive injected motion events injected by this [AndroidInputDispatcher]. If not
- * set, the event period of 10 milliseconds is unchanged. See also [eventPeriod].
+ * set, the event period of 10 milliseconds is unchanged.
+ *
+ * @see AndroidInputDispatcher.eventPeriod
*/
internal class TestRule(
private val disableDispatchInRealTime: Boolean = false,
private val eventPeriodOverride: Long? = null
) : org.junit.rules.TestRule {
+ val eventPeriod get() = AndroidInputDispatcher.eventPeriod
+
override fun apply(base: Statement, description: Description?): Statement {
return ModifyingStatement(base)
}
@@ -285,7 +289,7 @@
dispatchInRealTime = false
}
if (eventPeriodOverride != null) {
- eventPeriod = eventPeriodOverride
+ AndroidInputDispatcher.eventPeriod = eventPeriodOverride
}
try {
base.evaluate()
@@ -294,7 +298,7 @@
dispatchInRealTime = true
}
if (eventPeriodOverride != null) {
- eventPeriod = 10L
+ AndroidInputDispatcher.eventPeriod = 10L
}
}
}