Status Update
Comments
ma...@google.com <ma...@google.com>
je...@google.com <je...@google.com> #2
First of all thanks for this detailed issue.
This issue had been investigated thoroughly when it was first reported internally. The surprising detail in this report is that the issue is not reproducible before 1.7
. I will look into this.
The main problem with POBox is the fact that it is deprecated. Since 2021 Sony has been shipping new Xperia devices with Gboard pre-installed. Although we are aware that there is still a considerable amount of users still using POBox, the described behavior is caused by POBox's noncompliant behavior with InputConnection
and InputMethodManager
documentation. However, this is understandable since TextView
implementation was also not respecting the behavior that is expected from Editors.
Ultimately we have decided to enforce the documented behavior with specifically regards to when editors should call InputMethodManager.updateSelection
. Also, although unconfirmed, there were traces of possible custom code being included in Sony OEM images that changed how InputMethodManager was notified from TextView. If POBox also depended on something like this, it would be impossible for Compose code to replicate the same unknown behavior.
je...@google.com <je...@google.com> #3
Or is that option not available?
Even if the root cause is POBox, from the perspective of the app's customers, it looks like an app bug, so this issue is a blocker against updating Jetpack Compose.
me...@thomaskeller.biz <me...@thomaskeller.biz> #4
Just to be sure, it is dangerous to replace Compose TextField with Android View EditText as a workaround for this issue.
Compose 1.7 has a bug that causes ANR when the focus is on EditText.
Another View-related bug in Compose 1.7 is that an Android View is focused by calling FocusManager.clearFocus().
Perhaps there is a lack of testing of Compose 1.7 in combination with Android View. There is also a possibility that there are other fatal bugs related to View.
In other words, the only options for apps targeting the Japanese market that require POBox support are to continue using Compose 1.6 or to use EditText in combination with various workarounds.
je...@google.com <je...@google.com> #5
Project: platform/frameworks/support
Branch: androidx-main
Author: Halil Ozercan <
Link:
Fix POBox keyboard issue
Expand for full commit details
Fix POBox keyboard issue
Fix: 373743376
Fix: 329209241
Test: NullableInputConnectionWrapperTest
Change-Id: I94e0e598274fb88b255f977f9fbd50dfbbb1ecb1
Files:
- M
compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/input/NullableInputConnectionWrapperTest.kt
- M
compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/NullableInputConnectionWrapper.android.kt
Hash: 57f58c4b80d5d8470b2aca325dfdcd55f235231e
Date: Thu Oct 24 01:25:20 2024
me...@thomaskeller.biz <me...@thomaskeller.biz> #6
Many thanks again for this report. Especially for giving us a huge clue in terms of what could be going wrong. The fix is now merged and I will ask for a cherry-pick into a stable release.
me...@thomaskeller.biz <me...@thomaskeller.biz> #7
Do you have any concrete plan to cherry-pick the fix into current stable version (1.7.x)? We are currently waiting it.
je...@google.com <je...@google.com> #8
Yes, this fix is planned to be included in a future 1.7.x
release.
me...@thomaskeller.biz <me...@thomaskeller.biz> #9
Thanks for the fix. Sorry to follow up on this. is it possible for you to share specific release version/date for the stable version? We are waiting on this to decide on our direction.
je...@google.com <je...@google.com> #10
Ah, I think I see the misunderstanding now.
You don't need to call AndroidComposeTestRule.setContent
if your Activity or Fragment already sets the content. If you look closely to the return type of createEmptyComposeRule()
, you'll find that it doesn't even have a setContent
method.
The test rule takes care of wiring everything together. If you're interested to see how, take a look at
@get:Rule(order = 0)
val activityScenarioRule = ActivityScenarioRule<CustomActivity>()
@get:Rule(order = 1)
val composeTestRule = createEmptyComposeRule()
Please take a look at
ap...@google.com <ap...@google.com> #11
Branch: androidx-main
commit ff4469e78695de2436bdbe8822722f7c5e22de29
Author: Jelle Fresen <jellefresen@google.com>
Date: Tue Feb 15 14:22:51 2022
Test Compose when content set by a Fragment
This shows we can test Compose content if it is set by a Fragment
Fix: 199631334
Test: ./gradlew compose:ui:ui-test-junit4:cC
Change-Id: I9c79a1e240734be481c54d24c14111750c916f45
M compose/ui/ui-test-junit4/build.gradle
A compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeInFragmentTest.kt
je...@google.com <je...@google.com>
me...@thomaskeller.biz <me...@thomaskeller.biz> #12
Many thanks for the example, will try that out!
me...@thomaskeller.biz <me...@thomaskeller.biz> #13
A small addition - when my Fragment is in Lifecycle.State.STARTED
, compose will tell me this:
java.lang.IllegalStateException: No compose views found in the app. Is your Activity resumed?
at androidx.compose.ui.test.TestContext.getAllSemanticsNodes$ui_test_release(TestOwner.kt:96)
at androidx.compose.ui.test.SemanticsNodeInteraction.fetchSemanticsNodes$ui_test_release(SemanticsNodeInteraction.kt:82)
at androidx.compose.ui.test.SemanticsNodeInteraction.fetchOneOrDie(SemanticsNodeInteraction.kt:155)
at androidx.compose.ui.test.SemanticsNodeInteraction.fetchSemanticsNode(SemanticsNodeInteraction.kt:106)
at androidx.compose.ui.test.AndroidAssertions_androidKt.checkIsDisplayed(AndroidAssertions.android.kt:29)
at androidx.compose.ui.test.AssertionsKt.assertIsDisplayed(Assertions.kt:33)
If I move my Fragment to Lifecycle.State.RESUMED
, this error is gone, which is fine for me; I don't need to test things before onResume
.
I do call setContent
on the ComposeView
in onViewCreated
, as per your example.
je...@google.com <je...@google.com> #14
when my Fragment is in Lifecycle.State.STARTED, compose will tell me this
That is by design. If you open multiple activities we only want to find Compose elements in the RESUMED activity as that is the one the user is looking at.
If there is a good reason why the test harness should look in STARTED activities (/fragments) as well, then please open a new bug and I'll take a look.
me...@thomaskeller.biz <me...@thomaskeller.biz> #15
What I also figured is that each test that does anything with composeRule
runs quite slow, i.e. each test method needs about two extra seconds to run. I looked at the profile, but cannot say for sure whats causing this. What I can see however is that a test with the Activity-based rule takes about 150 to 250ms to execute with Robolectric, when I use the empty test rule the test takes about 2100 to 2300ms. Unfortunately I couldn't reproduce it yet with a smaller example. Will further have to look into this.
me...@thomaskeller.biz <me...@thomaskeller.biz> #16
That is by design. If you open multiple activities we only want to find Compose elements in the RESUMED activity as that is the one the user is looking at.
No, this is totally fine. The error message could only a tad bit better by saying "Is your Activity or Fragment resumed?", other than that this is fine.
me...@thomaskeller.biz <me...@thomaskeller.biz> #17
I created a follow-up DialogFragment
-related crash.
ap...@google.com <ap...@google.com> #18
Branch: androidx-main
commit 0fa0145d802d8effe0e833f0fe996dbeec3ab23e
Author: Jelle Fresen <jellefresen@google.com>
Date: Thu Feb 24 14:40:50 2022
Disallow overwriting content with test content
This adds a check in AndroidComposeTest.setContent that makes sure that
the Activity on which the content is set doesn't have content yet. If
there is content already, it is a signal that the tester is probably
unintentionally doing something wrong, so help them by throwing.
Bug: 199631334
Test: ./gradlew bOS
Relnote: "`ComposeContentTestRule.setContent` will now throw an
IllegalStateException if you try to set content when there already is
content."
Change-Id: I888a5054c27d7884110415a812d0ac748be3f869
M compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRemoveTest.kt
M compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/BitmapCapturingTest.kt
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
M compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/CustomActivityTest.kt
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/accessibility/CollectionInfoTest.kt
M compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ClickTestRuleTest.kt
M compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/IsDisplayedTest.kt
M compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/ActivityWithActionBar.kt
M compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/ComposeTest.android.kt
Description
Previously with plain XML UIs, one was able to test ViewModel and UI (Fragment/Activity + XML) in combination. With Compose and the
AndroidComposeTestRule
this is no longer possible:AndroidComposeTestRule
needs a test rule that provides anActivity
to the underlying compose infrastructure, while one can give it aFragmentScenarioRule
the fragment part of this cannot actually be re-used and the content of the whole Activity is replaced by the Compose UI.ComposeView.setContent()
of theFragment
(orActivity
, for that matter) isn't run when theAndroidComposeTestRule
'ssetContent
is used instead. Even worse, depending on the lifecycle state in which anActivity
is in (in which state it is started), a previous rendering could or could not have happened, leading to possible side effects with an actualViewModel
interfacing implementation.ComposeView
is not the root view of the controller component.I understand that a special
Recomposer
setup and a lot of other custom tooling is needed to make Jetpack Compose testable in an Robolectric / Android Instrumentation test, however I wish the test architecture would first and foremost provide an API to hook in / replace the existing functionality, e.g. by making it easy to inject a custom test composer in a running fragment / activity instance or by at least making this composer and possibly other utilities available for certain testing purposes.