How to dismiss soft keyboard in jetpack compose test? - android-jetpack-compose

I'm writing tests for a jetpack compose screen that has a text field on it. In my test I want to enter some text into the field, then dismiss the soft keyboard, then click a button that was hidden beneath the soft keyboard. I cannot find a way to dismiss a soft keyboard in jetpack compose tests though. I tried "performImeAction" but that is not dismissing the keyboard, even though if you press the IME key on the soft keyboard when actually interacting with this text field it does dismiss the keyboard.
I want to be able to do this, but in a compose test:
onView(withId(R.id.text_field)).perform(typeText("100"), closeSoftKeyboard())
My current compose code, enters "100" in field then throws error:
composeTestRule
.onNodeWithTag(TEXT_FIELD_TAG)
.performTextInput("100")
composeTestRule
.onNodeWithTag(TEXT_FIELD_TAG)
.performImeAction() <------------- This fails
Error reported:
java.lang.AssertionError: Failed to perform IME action as current node does not specify any.
Semantics of the node:
Node #48 at (l=0.0, t=748.0, r=788.0, b=1141.0)px, Tag: 'TEXT_FIELD_TAG'
ImeAction = 'Default'
EditableText = '100'
TextSelectionRange = 'TextRange(3, 3)'
Focused = 'true'
Actions = [GetTextLayoutResult, SetText, SetSelection, OnClick, OnLongClick, PasteText]
MergeDescendants = 'true'
Has 7 siblings

Related

Unable use a TextField at the bottom of the screen in a LazyColumn

I have this code
setContent {
val items = mutableListOf<Int>().apply {
(1..100).forEach { add(it) }
}
LazyColumn {
items(items) { item ->
TextField("$item", {})
}
}
}
With android:windowSoftInputMode="adjustResize" in my AndroidManifest.xml.
If I click on a TextField at the top of the list, I can enter text fine.
If I click on a TextField near the bottom of the screen, the keyboard appears momentarily, then disappears quickly after, and prevents me from entering text.
How can I enter text when the TextField is at the bottom of the screen? Thanks!
Your keyboard disappears after having appeared for a brief, shiny moment. Here's the reason:
You tap the TextField, it calls it's built-in focus requestor, and requests the focus from the OS by calling appropriate (or inappropriate, who's to say) internal methods, as a result of which, the keyboard pops out (again, built-in mechanism.) and you can type all the more you want... AS LONG AS THE FIELD IS VISIBLE; or in Compose terms, long as the Composable holding the requestor, is in composition.
It should be clear, that once the Composable that owns the focus requestor goes off the screen, it is destroyed (well not every time, there are only certain specific cases when it is destroyed..., but yours is one of them), and when the Composable is destroyed, the focus requestor is destroyed. No focus requestor, no focus owner - the keyboard vanishes.
Now this is really important because you are using a LazyColumn, a lazy Composable, infamous for its merciless slaughtering of the Composables that are no longer visible to the user. HENCE, as long as it is the top (or other "visible") textfield that is in concern, it stays and works as expected. However, the bottom textfield, as the keyboard pops up, goes so much out of the visible bounds, that it gets slaughtered (recycled is the technical term, but what fun is that?), taking away the purpose of the keyboard.
Now, the lazy column, like any criminal, left a clue behind, and didn't notice it, which lead us to catch him red-handed. It is quite interesting, really, to see the column in action.
Now, workarounds include using a column, instead of a lazy column; creating your own lazy column using a custom lazy Composable, and manually handling the heap size for the Composable so the final field doesn't go out of composition.
That's it, you're cured.
Just leaving another answer, since OP didn't verify other purpose of him specifying adjustResize,if whether removing or changing it will be fine, but another solution aside from the mentioned comment about different API version is specifying adjustPan, which worked in my case, either
via AndroidManifest
android:windowSoftInputMode="adjustPan"
or programmatically
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
Same code base but with adjustPan
This issue is fixed in the current alpha version 1.4.0-alpha05
https://issuetracker.google.com/issues/179203700

iOS: How to ask voice over to read a particular label when a button is clicked

I have a UILabel that changes text when a button is clicked at the bottom of the screen and certain conditions are met. I want my voice-over to read that updated text when a button is clicked and the conditions are met. How do I do that
You can post a notification to the accessibility system to get the behavior you're looking for. The following command specifically will shift focus to that label, effectively the same as if the user had tapped the label after activating the button. Read up on the other notification types if you want different behavior.
UIAccessibility.post(notification: .layoutChanged, argument: labelThatChanged)

How to show keyboard programmatically in Firefox OS?

I am working on a ToDo list app wherein I keep the focus on the textbox input after the user adds a ToDo item.
Now, the problem is, when the user adds some text input and hits the add button, the focus on the textbox is lost so the keyboard disappears and then the focus gets back to the textbox. So, the keyboard disappears and appears again in a short interval. As you can imagine, this is bad UX.
How do I set the keyboard to be shown explicitly when the focus is on the input button?
I fixed it by setting the focus onto the textbox first when I click the add button then do the actual adding stuff.

Voiceover not focusing on next form field

I have a long HTML form that I am trying to make accessible to Voiceover. When I click into a field, interact with it, and then click Done on the keyboard, after a short delay Voiceover is focusing on what appears to be the field most centered on the screen rather than the next element. I tried adding explicit tabindex to all the fields and this did not help. It is not always reproducable, it sometimes works as expected.
Is this expected behavior for Voiceover? Would a user not expect "Done" to take them to the next field (seems like maybe a dumb question since there is also a "Next" button, which works fine)? But as a sighted user I know the "Done" button when I am interacting with a field just means I am done with that field and want to go on to the next action, field whatever.
"Done" dismisses editing mode on VoiceOver. A VoiceOver user would not expect that tapping "done" moves the VO cursor.

combobox steal keyboard from main window in pyqt

I'm writing a small pyqt program. I want the main window to to react to arrow movement. I added an event to my MainGui class, keyPressEvent, that handle this. The event work fine as long as I don't press certain buttons such as Key_Up or Key_Down are directed to my (currently only) QComboBox and not to my mainGui. I tried to give the focus to mainGui after each paintEvent but then I need to double click on buttons/comboBox.
Then I tried to use the MousePressEvent to check if a certain element is under the mouse. This work fine with the comboBox, but not with the button.
So, how can I direct key events to the mainGui or give the focus to QButtons?
I used eventFilter to identify when the mouse enter the QPushButton and give it focus:
def eventFilter(self,source,event):
if event.type() == QtCore.QEvent.HoverMove:
if self.execButton.underMouse():
self.execButton.setFocus()
self.keepFocus=False
else :
self.keepFocus=True
keepFocus is a flag I initialized in the __init__ function of the class. I added this part at the paintEvent function
if self.keepFocus:
self.setFocus()
else:
self.keepFocus = True
Now, I keep the focus at the MainGui and I only give it to the button when the mouse hove over it. If I do another action (like pressing a mouse button or a keyboard key) the focus is given back to the MainGui. This will create some buggy filling (For example, I need to press twice a keyboard key before the first response) but this is workable.

Resources