Status Update
Comments
se...@google.com <se...@google.com> #2
Hello, thanks for reporting.
I can reproduce this issue by targeting SDK 35 and running the test on an emulator running Android 35.
I couldn't reproduce in a test that detects that content is occluded though. Both isDisplayed()
and !isNotDisplayed()
still return true, which seems to be caused by a bug in View.getGlobalVisibleRect
, which doesn't take the action bar into account either and which we rely on to get the clipped bounds of the AbstractComposeView.
I also couldn't reproduce with a View only test using Espresso and the following assertion: Espresso.onView(withText("Hello World")).check(matches(isCompletelyDisplayed()))
. Espresso also seems to rely on View.getGlobalVisibleRect
(
po...@gmail.com <po...@gmail.com> #3
Thank you for addressing this issue. I believe verifying the visibility and clickability of UI components is crucial for both UI and AI agent tests. Therefore, I think it's worth filing an issue to address this. Currently, I can achieve this through touch events, but it's not an ideal solution.
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun useAppContext() {
composeTestRule.setContent {
Column {
var isClicked by remember { mutableStateOf(false) }
// You can click the Button with this text
// Text("Hello\n\n\n\n\n\n\n\n\n\n World, $isClicked")
Button(onClick = { isClicked = true }) {
Text("Click me $isClicked")
}
}
}
val rect = composeTestRule.onNode(hasText("Click me false")).getBoundsInRoot()
val activity = (composeTestRule as AndroidComposeTestRule<*, *>).activity
val metrics = activity.windowManager.currentWindowMetrics
val density = metrics.density
println("density: $density $rect")
val x = (rect.left.value + rect.width.value / 2F) * density
val y = (rect.top.value + rect.height.value / 2F) * density
println("x: $x, y: $y")
activity.runOnUiThread {
activity.window.decorView.dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, y, 0))
activity.window.decorView.dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, x, y, 0))
}
composeTestRule.onNode(hasText("Click me true")).assertIsDisplayed()
}
}
se...@google.com <se...@google.com> #4
Clicks sent with the input injection methods (performClick
, performTouchInput
, etc) are not affected by the occlusion because we're essentially doing the same as in your workaround; we send the MotionEvents directly to the View that's hosting the compose content. You should be able to replace your custom injection logic with composeTestRule.onNode(hasText("Click me false")).performClick()
. If that doesn't pass, can you try the following test?
@Test
fun clickUnderActionBar() {
var clicked = false
composeTestRule.setContent {
Button(onClick = { clicked = true }) { Text("Click me") }
}
composeTestRule.onNodeWithText("Click me").performClick()
composeTestRule.runOnIdle { assert(clicked) { "Box was not clicked" } }
}
se...@google.com <se...@google.com> #5
Thank you for your continued work on this issue and the information about performClick()
.
I confirmed that both composeTestRule.onNode(hasText("Click me false")).performClick()
and the clickUnderActionBar()
test work as expected.
My aim was to provide a reproducing test case that demonstrates user clicks are unable to reach components as expected when they are overlaid by the ActionBar.
I'm very positive about the current direction of applying the appropriate theme, and I believe this approach will effectively resolve the underlying issue.
Thank you again for your efforts.
se...@google.com <se...@google.com> #6
Project: platform/frameworks/support
Branch: androidx-main
Author: Jelle Fresen <
Link:
Use NoActionBar theme for default test activity
Expand for full commit details
Use NoActionBar theme for default test activity
When targeting SDK 35, an activity is edge-to-edge by default. The
default theme has an ActionBar, which is now overlapping with the UI.
Fix this by setting a NoActionBar theme to remove the ActionBar. This
should not be a problem for existing tests, as the intended usecase for
using the ComponentActivity as a compose host is to test composables in
isolation.
Also changes the inappropriately named ActivityWithActionBar we use for
internal testing with the more appropriate name
CustomComposeHostActivity, as it had nothing to do with having an action
bar or not.
Bug: 383368165
Test: Added regression test in ComponentActivityLaunchesTest
Relnote: "The activity that is used as the host for the composable under
test when using `ComposeContentTestRule.setContent` now uses the theme
`Theme.Material.Light.NoActionBar`, to avoid the ActionBar from
overlapping with test content when targeting SDK 35. To opt out of this
behavior, you can remove the dependency on `ui-test-manifest` and add an
activity entry in your test app's AndroidManifest.xml for
ComponentActivity with the theme of your choice."
Change-Id: I7ae1bd28f5e341dafc07442b35ee4249793d257d
Files:
- M
compose/material/material-navigation/build.gradle
- M
compose/ui/ui-test-manifest/integration-tests/testapp/build.gradle
- M
compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt
- M
compose/ui/ui-test-manifest/src/main/AndroidManifest.xml
- M
compose/ui/ui-test/src/androidInstrumentedTest/AndroidManifest.xml
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/BitmapCapturingTest.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/CustomComposeHostActivity.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/IsDisplayedTest.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/gesturescope/SendClickTest.kt
- M
constraintlayout/constraintlayout-compose/build.gradle
Hash: 18d7693b4eba2ec6b1d1162b2154e914ba6ef25d
Date: Mon Dec 16 20:31:21 2024
se...@google.com <se...@google.com> #7
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.material:material-navigation:1.8.0-alpha08
androidx.compose.ui:ui-test:1.8.0-alpha08
androidx.compose.ui:ui-test-android:1.8.0-alpha08
androidx.compose.ui:ui-test-jvmstubs:1.8.0-alpha08
androidx.compose.ui:ui-test-linuxx64stubs:1.8.0-alpha08
androidx.compose.ui:ui-test-manifest:1.8.0-alpha08
po...@gmail.com <po...@gmail.com> #8
Amazing! That was super quick)
se...@google.com <se...@google.com> #9
Excellent bug report and I had some idle cycles this week :)
Description
Jetpack Compose version: 1.7.6
Jetpack Compose component used:
Android Studio Build: Ladybug Feature Drop 2024.2.2
Kotlin version: 2.1.0
Devices/Android versions reproduced on: Phone Emulator (API 34)
Keyboard (i.e. Gboard, Samsung, etc): AOSP Keyboard
If you have Material text
inside the layout with
Modifier.imePadding()
applied to it, and trigger the appearance of the soft keyboard, then text starts to move to the right of the screen.This bug is very similar to this one and is probably related to this code (it was introduced here ).
Screenshots and video attached.