Status Update
Comments
nj...@google.com <nj...@google.com>
ch...@google.com <ch...@google.com> #2
You can provide your own regex to By.text()
.
For example, By.text(Pattern.compile("All albums.*", Pattern.DOTALL))
should be equivalent to a multi-line startsWith.
yu...@gmail.com <yu...@gmail.com> #3
I'm probably dumb but why would it be the default and wanted behavior if not documented properly?
Every known startWith / contains function in Java/Kotlin are multiline, the javadoc says: A UI element will be considered a match if its text value starts with the substring parameter
Many people will fall into this non standard default behavior and loose tons of time trying to figure out why.
If you still consider this default is the correct one, then please document it.
yu...@gmail.com <yu...@gmail.com> #4
Branch: androidx-main
commit 1625e615b9aed44323029da2726a57390956e4ab
Author: Daniel Peykov <peykov@google.com>
Date: Wed Nov 02 21:46:28 2022
Support multiline text and description matching
* Fixes inconsistency between UiSelector (partial support) and
BySelector, and clarifies the case sensitivity of related methods.
* Also, reorganizes byselector_test_activity to decrease its height
which was right up to the limit on some device types.
Bug: 255787130
Test: ./gradlew :test:uiautomator:integration-tests:t:cAT
Change-Id: Ied9eff43ce4ce6f2ace2889a55b0382e71604b61
M test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTest.java
M test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_test_activity.xml
M test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/BySelector.java
M test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiSelector.java
M test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/Until.java
yu...@gmail.com <yu...@gmail.com> #5
Will be fixed in version 2.3.0-alpha02.
To clarify
However, looking at this again, it was inconsistent between UiSelector and BySelector, and users are unlikely to be relying on single line matching.
yu...@gmail.com <yu...@gmail.com> #6
Thanks a lot for the change.
I understand legacy and everything, it was just the close without discussion about proper solution (including doc that would have worked too) that was strange.
Seeing the $ in the regexp took me time, and it's good to avoid this to other users when improvement is possible.
ch...@google.com <ch...@google.com> #7
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.test.uiautomator:uiautomator:2.3.0-alpha02
ch...@google.com <ch...@google.com> #8
ch...@google.com <ch...@google.com> #9
I tried cutting down the example myself and was not able to reproduce this.
The primary dependency chagnes I made were:
compose-material3 = { module = "androidx.compose.material3:material3", version = "1.3.0-SNAPSHOT" }
compose-foundation = { module = "androidx.compose.foundation:foundation-android", version = "1.7.0-SNAPSHOT" }
I only included the part of the Dialog.kt that was needed by the above,
class DialogState {
var content: (@Composable () -> Unit)? by mutableStateOf(null)
@Composable
fun Intercept() = content?.invoke()
fun dismiss() {
content = null
}
suspend inline fun <R> dialog(crossinline block: @Composable (CancellableContinuation<R>) -> Unit) = suspendCancellableCoroutine<R> { cont ->
cont.invokeOnCancellation { dismiss() }
val realContinuation = object : CancellableContinuation<R> by cont {
override fun resumeWith(result: Result<R>) {
dismiss()
cont.resumeWith(result)
}
}
content = { block(realContinuation) }
}
suspend inline fun showSelectActions(
title: String? = null,
builder: ActionScope.() -> Unit,
) {
val (items, actions) = buildList { builder(ActionScope { action, that -> add(action to that) }) }.unzip()
val selected = showSelectItem(items, title)
actions[selected].invoke()
}
suspend fun showSelectItem(
items: List<String>,
title: String?,
respectDefaultWidth: Boolean = true,
): Int = showNoButton(respectDefaultWidth) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
if (title != null) {
Text(
text = title,
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
style = MaterialTheme.typography.headlineSmall,
)
}
LazyColumn {
itemsIndexed(items) { index, text ->
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.tertiary) {
Text(
text = text,
modifier = Modifier.clickable { dismissWith(index) }.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp),
style = MaterialTheme.typography.titleMedium,
)
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
suspend fun <R> showNoButton(respectDefaultWidth: Boolean = true, block: @Composable DismissDialogScope<R>.() -> Unit): R {
return dialog { cont ->
val impl = remember(cont) {
DismissDialogScope<R> {
cont.resume(it)
}
}
BasicAlertDialog(
onDismissRequest = { cont.cancel() },
properties = DialogProperties(usePlatformDefaultWidth = respectDefaultWidth),
content = {
Surface(
modifier = with(Modifier) { if (!respectDefaultWidth) defaultMinSize(280.dp) else width(280.dp) },
shape = AlertDialogDefaults.shape,
color = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
content = { block(impl) },
)
},
)
}
}
}
fun interface ActionScope {
fun onSelect(action: String, that: suspend () -> Unit)
}
fun interface DismissDialogScope<R> {
fun dismissWith(value: R)
}
This shows the "Please wait" and then selection between "a" and "b" as I expected.
yu...@gmail.com <yu...@gmail.com> #10
This requires compose compiler 1.5.11-dev-k2.0.0-Beta4-21f5e479a96
I will upload a sample project soon
yu...@gmail.com <yu...@gmail.com> #11
yu...@gmail.com <yu...@gmail.com> #12
ch...@google.com <ch...@google.com> #13
Sorry! I didn't see you updated this. I must have missed the notification. Trying now.
ch...@google.com <ch...@google.com> #14
I have the exception reproducing locally, investigating.
ch...@google.com <ch...@google.com> #15
The issue is in the call to dialog
when it inlines the crossinline
lambda. This lambda instances are getting the same key at both call sights and, when the second dialog shows, it believes it is recomposing the first and then throws as it didn't create the state in this slot table.
The simple work-around now is to change dialog
's parameter to noinline
instead of crossinline
. This ensures that the keys produced for the lambdas are different.
I am investigating what change caused this.
ch...@google.com <ch...@google.com> #16
The code generation for crossinline
lambda seems to have always been wrong but the extra groups the compiler create that the change removes prevented crashes in most cases. By removing otherwise unnecessary groups, the missing group around a crossinline
lambda now causes a crash.
The work-around above, changing the lambda to noinline
, is valid because it avoids crossinline
and, therefore, avoids the crash.
The key symptom is that currentComposer.inserting
is never true
for the crossinline
lambda passed into the second dialog which indicates it is recomposing over state it didn't produce.
A group is required because a crossinline
lambda can be inlined into a lambda instance. The instance created gets the same key but its content has effectively changed as the crossinline
lambda acts as a branch point. The runtime assumes that when a different branch of code is executed, it executes in a block with a different key than the previous branch taken. As there is no branch group, the code is recomposed over state it didn't create, which is never valid. Recomposing over state it didn't create will not always create an exception and this was the case for the code generated prior to enabling the optimization to remove otherwise unnecessary groups.
ap...@google.com <ap...@google.com> #17
Branch: androidx-main
commit 7862dc2cf51ebc69f6760b0c6cf8a2133f11cd94
Author: Chuck Jazdzewski <chuckj@google.com>
Date: Mon Feb 26 15:02:15 2024
Fix code generation for composable crossinline lambda
If a crossinline lambda was called in a lambda instance then
it was possible for the composition to get out of sync potentially
causing crashes. This is hard to reproduce without
"nonSkippingGroupOptimization" enabled as the group around
remember causes most exceptions avoided, however the code was
incorrect as and subtle crashes were still possible.
Fixes: 325502738
Test: ./gradlew :compose:c:c-h:i-t:tDUT :compose:c:c-h:r-t:jvmTest
Change-Id: Icb2fd2f5a946144cc105737c4a4051f02a901b78
M compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testEarlyReturnFromCrossInlinedLambda[useFir = false].txt
M compose/compiler/compiler-hosted/integration-tests/src/test/resources/golden/androidx.compose.compiler.plugins.kotlin.ControlFlowTransformTests/testEarlyReturnFromCrossInlinedLambda[useFir = true].txt
M compose/compiler/compiler-hosted/runtime-tests/build.gradle
M compose/compiler/compiler-hosted/runtime-tests/src/commonTest/kotlin/androidx/compose/compiler/test/CompositionTests.kt
M compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
M compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrInlineReferenceLocator.kt
pr...@google.com <pr...@google.com> #18
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.compiler:compiler-hosted:1.5.11
Description
Sorry that I cannot find a minimal sample code yet
Got following crash
Seems that we get a wrong object in SlotTable during recompose
Reproduce with
Navigate to a random gallery, and navigate back, then we will crash.