Changes in captureToBitmap.
Fixes the captureToBitmap to work with ActionBar and cut outs. This also
replaces the way we were obtaining the screenshots. Instead of taking a
bitmap from a window we use UiAutomator which actually takes a real
screenshot. This enabled us to capture multiple windows and defend
against cases where popup could be on top of our view. Finally it also
removes the need to juggle with Activities (and casting them) and also
removes the O+ API restriction.
Finally I have also removed the method used to capture full screen. The
reason is that no one used it and it is tricky to define how it should
work. E.g. it does not have much value if we don't crop out the action
bar. With that and the fact that developers can use UiAutomator for
fullscreen screenshots it is not beneficial to keep that API around. We
can reintroduce it in the future once we need to.
Bug: 157657482
Test: Added
Change-Id: I5320d61c7a4ebc03472b0cb79c3da6c3870482f3
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/TextFieldTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/TextFieldTest.kt
index a8302e7..effbd0f 100644
--- a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/TextFieldTest.kt
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/TextFieldTest.kt
@@ -40,6 +40,7 @@
import androidx.ui.input.TextInputService
import androidx.ui.layout.Row
import androidx.ui.layout.fillMaxSize
+import androidx.ui.layout.padding
import androidx.ui.layout.preferredSize
import androidx.ui.layout.preferredWidth
import androidx.ui.savedinstancestate.savedInstanceState
@@ -479,16 +480,21 @@
val height = 20.dp
val latch = CountDownLatch(1)
composeTestRule.setContent {
- TextField(
- value = TextFieldValue(),
- >
- textStyle = TextStyle(color = Color.White, background = Color.White),
- modifier = Modifier.preferredSize(width, height).drawBackground(Color.White),
- cursorColor = Color.Red,
- focused ->
- if (focused) latch.countDown()
- }
- )
+ // The padding helps if the test is run accidentally in landscape. Landscape makes
+ // the cursor to be next to the navigation bar which affects the red color to be a bit
+ // different - possibly anti-aliasing.
+ Box(Modifier.padding(10.dp)) {
+ TextField(
+ value = TextFieldValue(),
+ >
+ textStyle = TextStyle(color = Color.White, background = Color.White),
+ modifier = Modifier.preferredSize(width, height).drawBackground(Color.White),
+ cursorColor = Color.Red,
+ focused ->
+ if (focused) latch.countDown()
+ }
+ )
+ }
}
find(hasInputMethodsSupport()).doClick()
@@ -506,6 +512,11 @@
// cursor invisible during next 500 ms
composeTestRule.clockTestRule.advanceClock(700)
+
+ // TODO: There seems to be an issue on Pixel that we capture the bitmap too early and
+ // perform the assert while the cursor is still there.
+ waitForIdle()
+
find(hasInputMethodsSupport())
.captureToBitmap()
.assertShape(
diff --git a/ui/ui-test/api/0.1.0-dev14.txt b/ui/ui-test/api/0.1.0-dev14.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/0.1.0-dev14.txt
+++ b/ui/ui-test/api/0.1.0-dev14.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/api/current.txt b/ui/ui-test/api/current.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/current.txt
+++ b/ui/ui-test/api/current.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/api/public_plus_experimental_0.1.0-dev14.txt b/ui/ui-test/api/public_plus_experimental_0.1.0-dev14.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/public_plus_experimental_0.1.0-dev14.txt
+++ b/ui/ui-test/api/public_plus_experimental_0.1.0-dev14.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/api/public_plus_experimental_current.txt b/ui/ui-test/api/public_plus_experimental_current.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/ui/ui-test/api/public_plus_experimental_current.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/api/restricted_0.1.0-dev14.txt b/ui/ui-test/api/restricted_0.1.0-dev14.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/restricted_0.1.0-dev14.txt
+++ b/ui/ui-test/api/restricted_0.1.0-dev14.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/api/restricted_current.txt b/ui/ui-test/api/restricted_current.txt
index 5a16901..3b20f975 100644
--- a/ui/ui-test/api/restricted_current.txt
+++ b/ui/ui-test/api/restricted_current.txt
@@ -55,8 +55,8 @@
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);
method public static void assertShape--mmofgM(android.graphics.Bitmap, androidx.ui.unit.Density density, float horizontalPadding, float verticalPadding, long backgroundColor, long shapeColor, androidx.ui.graphics.Shape shape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float shapeOverlapPixelCount = 1.0f);
method public static void assertShape-t2RoSCg(android.graphics.Bitmap, androidx.ui.unit.Density density, androidx.ui.graphics.Shape shape, long shapeColor, long backgroundColor, androidx.ui.graphics.Shape backgroundShape = androidx.ui.graphics.RectangleShapeKt.RectangleShape, float sizeX = width.toFloat(), float sizeY = height.toFloat(), float shapeSizeX = sizeX, float shapeSizeY = sizeY, float centerX = width / 2.0, float centerY = height / 2.0, float shapeOverlapPixelCount = 1.0f);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static android.graphics.Bitmap captureToBitmap(android.view.View);
+ method public static android.graphics.Bitmap captureToBitmap(androidx.ui.test.SemanticsNodeInteraction);
+ method public static android.graphics.Bitmap captureToBitmap(android.view.View);
method public static boolean contains-m3TnucA(androidx.ui.graphics.Path, long offset);
}
@@ -123,7 +123,6 @@
}
public interface ComposeTestRule extends org.junit.rules.TestRule {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.ui.test.AnimationClockTestRule getClockTestRule();
@@ -343,7 +342,6 @@
public final class AndroidComposeTestRule<T extends androidx.activity.ComponentActivity> implements androidx.ui.test.ComposeTestRule {
ctor public AndroidComposeTestRule(androidx.test.rule.ActivityTestRule<T> activityTestRule, androidx.compose.Recomposer? recomposer, boolean disableTransitions);
method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description? description);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public android.graphics.Bitmap captureScreenOnIdle();
method public androidx.ui.test.ComposeTestCaseSetup forGivenContent(kotlin.jvm.functions.Function0<kotlin.Unit> composable);
method public androidx.ui.test.ComposeTestCaseSetup forGivenTestCase(androidx.ui.test.ComposeTestCase testCase);
method public androidx.test.rule.ActivityTestRule<T> getActivityTestRule();
diff --git a/ui/ui-test/build.gradle b/ui/ui-test/build.gradle
index 4e581cb..a38c164 100644
--- a/ui/ui-test/build.gradle
+++ b/ui/ui-test/build.gradle
@@ -36,6 +36,7 @@
implementation(KOTLIN_STDLIB)
implementation(ANDROIDX_TEST_RULES)
implementation(ANDROIDX_TEST_RUNNER)
+ implementation(ANDROIDX_TEST_UIAUTOMATOR)
implementation(ESPRESSO_CORE)
implementation(JUNIT)
@@ -71,4 +72,4 @@
mavenGroup = LibraryGroups.UI
inceptionYear = "2019"
description = "AndroidX UI test framework."
-}
+}
\ No newline at end of file
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/BitmapCapturingTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/BitmapCapturingTest.kt
index 72b497c..75c4e0b5 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/BitmapCapturingTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/BitmapCapturingTest.kt
@@ -16,9 +16,9 @@
package androidx.ui.test
-import android.os.Build
+import androidx.activity.ComponentActivity
import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
+import androidx.test.rule.ActivityTestRule
import androidx.ui.core.Modifier
import androidx.ui.core.testTag
import androidx.ui.foundation.Box
@@ -27,7 +27,10 @@
import androidx.ui.layout.Column
import androidx.ui.layout.Row
import androidx.ui.layout.fillMaxSize
+import androidx.ui.layout.padding
import androidx.ui.layout.preferredSize
+import androidx.ui.test.android.AndroidComposeTestRule
+import androidx.ui.test.gesturescope.ActivityWithActionBar
import androidx.ui.unit.IntPxPosition
import androidx.ui.unit.IntPxSize
import androidx.ui.unit.ipx
@@ -35,15 +38,26 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import org.junit.runners.Parameterized
@MediumTest
-@RunWith(JUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-class BitmapCapturingTest {
+@RunWith(Parameterized::class)
+class BitmapCapturingTest(val config: TestConfig) {
+ data class TestConfig(
+ val activityClass: Class<out ComponentActivity>
+ )
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun createTestSet(): List<TestConfig> = listOf(
+ TestConfig(ComponentActivity::class.java),
+ TestConfig(ActivityWithActionBar::class.java)
+ )
+ }
@get:Rule
- val composeTestRule = createComposeRule()
+ val composeTestRule = AndroidComposeTestRule(ActivityTestRule(config.activityClass))
private val rootTag = "Root"
private val tag11 = "Rect11"
@@ -101,17 +115,6 @@
}
}
- @Test
- fun captureWholeWindow_checkSizeAndColors() {
- composeCheckerboard()
-
- composeTestRule
- .captureScreenOnIdle()
- .assertPixels() {
- expectedColorProvider(it)
- }
- }
-
@Test(expected = AssertionError::class)
fun assertWrongColor_expectException() {
composeCheckerboard()
@@ -155,30 +158,32 @@
with(composeTestRule.density) {
composeTestRule.setContent {
Box(Modifier.fillMaxSize(), backgroundColor = colorBg) {
- Column(Modifier.testTag(rootTag)) {
- Row {
- Box(Modifier
- .testTag(tag11)
- .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
- .drawBackground(color11)
- )
- Box(Modifier
- .testTag(tag12)
- .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
- .drawBackground(color12)
- )
- }
- Row {
- Box(Modifier
- .testTag(tag21)
- .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
- .drawBackground(color21)
- )
- Box(Modifier
- .testTag(tag22)
- .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
- .drawBackground(color22)
- )
+ Box(Modifier.padding(top = 20.ipx.toDp()), backgroundColor = colorBg) {
+ Column(Modifier.testTag(rootTag)) {
+ Row {
+ Box(Modifier
+ .testTag(tag11)
+ .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
+ .drawBackground(color11)
+ )
+ Box(Modifier
+ .testTag(tag12)
+ .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
+ .drawBackground(color12)
+ )
+ }
+ Row {
+ Box(Modifier
+ .testTag(tag21)
+ .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
+ .drawBackground(color21)
+ )
+ Box(Modifier
+ .testTag(tag22)
+ .preferredSize(100.ipx.toDp(), 50.ipx.toDp())
+ .drawBackground(color22)
+ )
+ }
}
}
}
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/BitmapHelpers.kt b/ui/ui-test/src/main/java/androidx/ui/test/BitmapHelpers.kt
index 02308fd..8d65ad2 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/BitmapHelpers.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/BitmapHelpers.kt
@@ -16,13 +16,8 @@
package androidx.ui.test
-import android.app.Activity
-import android.content.Context
-import android.content.ContextWrapper
import android.graphics.Bitmap
-import android.os.Build
import android.view.View
-import androidx.annotation.RequiresApi
import androidx.ui.geometry.Offset
import androidx.ui.geometry.Rect
import androidx.ui.geometry.Size
@@ -45,17 +40,15 @@
import kotlin.math.roundToInt
/**
- * Captures the underlying component's surface into bitmap.
+ * Captures the screen region occupied by this component into a bitmap.
*
- * This has currently several limitations. Currently we assume that the component is hosted in
- * Activity's window. Also if there is another window covering part of the component if won't occur
- * in the bitmap as this is taken from the component's window surface.
+ * In case there is anything else (for example a popup) on top of this component, it will be also
+ * captured as part of this operation.
*/
-@RequiresApi(Build.VERSION_CODES.O)
fun SemanticsNodeInteraction.captureToBitmap(): Bitmap {
val node = fetchSemanticsNode("Failed to capture a node to bitmap.")
// TODO(pavlis): Consider doing assertIsDisplayed here. Will need to move things around.
- return captureRegionToBitmap(node.globalBounds.toRect(), node.componentNode.owner!!)
+ return captureRegionToBitmap(node.globalBounds.toRect())
}
/**
@@ -65,24 +58,13 @@
* Activity's window. Also if there is another window covering part of the component if won't occur
* in the bitmap as this is taken from the component's window surface.
*/
-@RequiresApi(Build.VERSION_CODES.O)
fun View.captureToBitmap(): Bitmap {
val locationOnScreen = intArrayOf(0, 0)
getLocationOnScreen(locationOnScreen)
val x = locationOnScreen[0].toFloat()
val y = locationOnScreen[1].toFloat()
val bounds = Rect(x, y, x + width, y + height)
-
- // Recursively search for the Activity context through (possible) ContextWrappers
- fun Context.getActivity(): Activity? {
- return when (this) {
- is Activity -> this
- is ContextWrapper -> this.baseContext.getActivity()
- else -> null
- }
- }
-
- return captureRegionToBitmap(bounds, handler, context.getActivity()!!.window)
+ return captureRegionToBitmap(bounds)
}
/**
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt b/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
index b8c4f25..611728b 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/ComposeTestRule.kt
@@ -16,11 +16,8 @@
package androidx.ui.test
-import android.graphics.Bitmap
-import android.os.Build
import android.util.DisplayMetrics
import androidx.activity.ComponentActivity
-import androidx.annotation.RequiresApi
import androidx.compose.Composable
import androidx.compose.Recomposer
import androidx.ui.unit.Density
@@ -68,22 +65,6 @@
*/
fun forGivenTestCase(testCase: ComposeTestCase): ComposeTestCaseSetup
- /**
- * Takes screenshot of the Activity's window after Compose UI gets idle.
- *
- * This function blocks until complete.
- *
- * Note that this does not capture the full device screen as it has access only to the test
- * Activity's window surface. The test Activity is the one that hosts the initial composition
- * created via [setContent]. If there are windows on top of the Activity's window these won't
- * be included. It will also not include any other Activities started afterwards.
- *
- * You can also use [SemanticsNodeInteraction.captureToBitmap] to capture individual components.
- * That one does not require any specific Activity.
- */
- @RequiresApi(Build.VERSION_CODES.O)
- fun captureScreenOnIdle(): Bitmap
-
// TODO(pavlis): Provide better abstraction for host side reusability
val displayMetrics: DisplayMetrics get
}
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
index 7d65436..30fa720 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
@@ -16,21 +16,17 @@
package androidx.ui.test.android
-import android.graphics.Bitmap
-import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.DisplayMetrics
import android.util.SparseArray
import android.view.ViewGroup
import androidx.activity.ComponentActivity
-import androidx.annotation.RequiresApi
import androidx.compose.Composable
import androidx.compose.Recomposer
import androidx.test.rule.ActivityTestRule
import androidx.ui.animation.transitionsEnabled
import androidx.ui.core.setContent
-import androidx.ui.geometry.Rect
import androidx.ui.input.textInputServiceFactory
import androidx.ui.test.AnimationClockTestRule
import androidx.ui.test.ComposeTestCase
@@ -143,20 +139,6 @@
)
}
- @RequiresApi(Build.VERSION_CODES.O)
- override fun captureScreenOnIdle(): Bitmap {
- waitForIdle()
- val contentView = activityTestRule.activity.findViewById<ViewGroup>(android.R.id.content)
-
- val screenRect = Rect.fromLTWH(
- 0f,
- 0f,
- contentView.width.toFloat(),
- contentView.height.toFloat()
- )
- return captureRegionToBitmap(screenRect, handler, activityTestRule.activity.window)
- }
-
inner class AndroidComposeStatement(
private val base: Statement
) : Statement() {
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/android/WindowCapture.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/WindowCapture.kt
index 525636e..836cad5 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/android/WindowCapture.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/WindowCapture.kt
@@ -16,90 +16,15 @@
package androidx.ui.test.android
-import android.app.Activity
-import android.content.Context
-import android.content.ContextWrapper
import android.graphics.Bitmap
-import android.os.Build
-import android.os.Handler
-import android.os.Looper
-import android.view.PixelCopy
-import android.view.ViewTreeObserver
-import android.view.Window
-import androidx.annotation.RequiresApi
-import androidx.ui.core.AndroidOwner
-import androidx.ui.core.Owner
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
import androidx.ui.geometry.Rect
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
-@RequiresApi(Build.VERSION_CODES.O)
internal fun captureRegionToBitmap(
- captureRect: Rect,
- owner: Owner
+ captureRect: Rect
): Bitmap {
-
- fun Context.getActivity(): Activity? {
- return when (this) {
- is Activity -> this
- is ContextWrapper -> this.baseContext.getActivity()
- else -> null
- }
- }
-
- // TODO(pavlis): Make sure that the Activity actually hosts the view. As in case of popup
- // it wouldn't. This will require us rewriting the structure how we collect the nodes.
-
- // TODO(pavlis): Add support for popups. So if we find composable hosted in popup we can
- // grab its reference to its window (need to add a hook to popup).
-
- val window = (owner as AndroidOwner).view.context.getActivity()!!.window
- val handler = Handler(Looper.getMainLooper())
- return captureRegionToBitmap(captureRect, handler, window)
-}
-
-@RequiresApi(Build.VERSION_CODES.O)
-internal fun captureRegionToBitmap(
- captureRect: Rect,
- handler: Handler,
- window: Window
-): Bitmap {
- // first we wait for the drawing to happen
- val drawLatch = CountDownLatch(1)
- val decorView = window.decorView
- handler.post {
- if (Build.VERSION.SDK_INT >= 29) {
- decorView.viewTreeObserver.registerFrameCommitCallback {
- drawLatch.countDown()
- }
- } else {
- decorView.viewTreeObserver.addOnDrawListener(object : ViewTreeObserver.OnDrawListener {
- var handled = false
- override fun onDraw() {
- if (!handled) {
- handled = true
- handler.post {
- drawLatch.countDown()
- decorView.viewTreeObserver.removeOnDrawListener(this)
- }
- }
- }
- })
- }
- decorView.invalidate()
- }
- if (!drawLatch.await(1, TimeUnit.SECONDS)) {
- throw AssertionError("Failed waiting for DecorView redraw!")
- }
-
- // and then request the pixel copy of the drawn buffer
- val destBitmap = Bitmap.createBitmap(
- captureRect.width.roundToInt(),
- captureRect.height.roundToInt(),
- Bitmap.Config.ARGB_8888
- )
-
// TODO: This could go to some Android specific extensions.
val srcRect = android.graphics.Rect(
captureRect.left.roundToInt(),
@@ -108,22 +33,12 @@
captureRect.bottom.roundToInt()
)
- val latch = CountDownLatch(1)
- var copyResult = 0
- val : PixelCopy.OnPixelCopyFinishedListener {
- override fun onPixelCopyFinished(result: Int) {
- copyResult = result
- latch.countDown()
- }
- }
+ val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ device.waitForIdle()
- PixelCopy.request(window, srcRect, destBitmap, onCopyFinished, handler)
+ val automation = InstrumentationRegistry.getInstrumentation().uiAutomation
+ val srcBitmap = automation.takeScreenshot()
- if (!latch.await(1, TimeUnit.SECONDS)) {
- throw AssertionError("Failed waiting for PixelCopy!")
- }
- if (copyResult != PixelCopy.SUCCESS) {
- throw AssertionError("PixelCopy failed!")
- }
- return destBitmap
-}
+ return Bitmap.createBitmap(srcBitmap, captureRect.left.roundToInt(),
+ captureRect.top.roundToInt(), srcRect.width(), srcRect.height())
+}
\ No newline at end of file