Fixed
Status Update
Comments
ma...@google.com <ma...@google.com>
ad...@gmail.com <ad...@gmail.com> #2
Tests should be expanded for `Saver` to cover situations like this. It's inevitable that users would eventually switch away from the app they're using.
Good thing it's still alpha.
Good thing it's still alpha.
zi...@gmail.com <zi...@gmail.com> #3
I have this problem too, is there any good solution?
ki...@protonmail.com <ki...@protonmail.com> #4
Same problem here, the problem is that val GlobalMutatorMutex: MutatorMutex = MutatorMutex()
is trying to be saved to a bundle
save = {
listOf(
it.isVisible,
it.isPersistent,
it.mutatorMutex
)
},
restore = {
val (isVisible, isPersistent, mutatorMutex) = it as List<*>
TooltipStateImpl(
initialIsVisible = isVisible as Boolean,
isPersistent = isPersistent as Boolean,
mutatorMutex = mutatorMutex as MutatorMutex,
)
}
)
but the MutatorMutex class doesn't implement Parcelable nor Serializable
class MutatorMutex {}
The workaround is to modify the rememberTooltipState
and provide your own implementation until fix is there.
Here is a quick fix that I created, it means that it will use the singleton's BasicTooltipDefaults.GlobalMutatorMutex
instance.
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.BasicTooltipDefaults
import androidx.compose.foundation.BasicTooltipState
import androidx.compose.foundation.MutatePriority
import androidx.compose.foundation.MutatorMutex
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TooltipState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeout
//https://issuetracker.google.com/issues/299500338
@Composable
@ExperimentalMaterial3Api
fun rememberTooltipStateFix(
initialIsVisible: Boolean = false,
isPersistent: Boolean = false
): TooltipState {
return rememberSaveable(
isPersistent,
saver = TooltipStateImpl.Saver
) {
TooltipStateImpl(
initialIsVisible = initialIsVisible,
isPersistent = isPersistent,
mutatorMutex = BasicTooltipDefaults.GlobalMutatorMutex
)
}
}
@Stable
private class TooltipStateImpl(
initialIsVisible: Boolean,
override val isPersistent: Boolean,
private val mutatorMutex: MutatorMutex
) : TooltipState {
override val transition: MutableTransitionState<Boolean> =
MutableTransitionState(initialIsVisible)
override val isVisible: Boolean
get() = transition.currentState || transition.targetState
/**
* continuation used to clean up
*/
private var job: (CancellableContinuation<Unit>)? = null
/**
* Show the tooltip associated with the current [BasicTooltipState].
* When this method is called, all of the other tooltips associated
* with [mutatorMutex] will be dismissed.
*
* @param mutatePriority [MutatePriority] to be used with [mutatorMutex].
*/
override suspend fun show(
mutatePriority: MutatePriority
) {
val cancellableShow: suspend () -> Unit = {
suspendCancellableCoroutine { continuation ->
transition.targetState = true
job = continuation
}
}
// Show associated tooltip for [TooltipDuration] amount of time
// or until tooltip is explicitly dismissed depending on [isPersistent].
mutatorMutex.mutate(mutatePriority) {
try {
if (isPersistent) {
cancellableShow()
} else {
withTimeout(BasicTooltipDefaults.TooltipDuration) {
cancellableShow()
}
}
} finally {
// timeout or cancellation has occurred
// and we close out the current tooltip.
dismiss()
}
}
}
/**
* Dismiss the tooltip associated with
* this [TooltipState] if it's currently being shown.
*/
override fun dismiss() {
transition.targetState = false
}
/**
* Cleans up [mutatorMutex] when the tooltip associated
* with this state leaves Composition.
*/
override fun onDispose() {
job?.cancel()
}
companion object {
/**
* The default [Saver] implementation for [TooltipStateImpl].
*/
val Saver = Saver<TooltipStateImpl, Any>(
save = {
listOf(
it.isVisible,
it.isPersistent,
)
},
restore = {
val (isVisible, isPersistent) = it as List<*>
TooltipStateImpl(
initialIsVisible = isVisible as Boolean,
isPersistent = isPersistent as Boolean,
mutatorMutex = BasicTooltipDefaults.GlobalMutatorMutex,
)
}
)
}
}
ap...@google.com <ap...@google.com> #5
Project: platform/frameworks/support
Branch: androidx-main
commit 6bb2ebba14f7f98b3a82e7f7869e248b47d97953
Author: Kevin Truong <kevinctruong@google.com>
Date: Mon Sep 11 09:13:03 2023
[Tooltip] Removing savedInstanceState for tooltips
Removing the use of savedInstanceState for tooltips since the changes that need to be made to support this outweigh the benefit of supporting it.
We initially used a Saver for tooltip, so that a shown tooltip would remain showing even on device rotation. However, MutatorMutex is not a saveable type.
To make it work, we would need to make MutatorMutex saveable. For now, users will just need to reopen closed tooltips on device rotation or app closure.
Bug: 299500338
Test: N/A
Relnote: remove the use of rememberSaveable for tooltips.
Change-Id: Icc131c852cc3b3c722954aecb0a002711e13ca96
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicTooltip.kt
M compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
https://android-review.googlesource.com/2747573
Branch: androidx-main
commit 6bb2ebba14f7f98b3a82e7f7869e248b47d97953
Author: Kevin Truong <kevinctruong@google.com>
Date: Mon Sep 11 09:13:03 2023
[Tooltip] Removing savedInstanceState for tooltips
Removing the use of savedInstanceState for tooltips since the changes that need to be made to support this outweigh the benefit of supporting it.
We initially used a Saver for tooltip, so that a shown tooltip would remain showing even on device rotation. However, MutatorMutex is not a saveable type.
To make it work, we would need to make MutatorMutex saveable. For now, users will just need to reopen closed tooltips on device rotation or app closure.
Bug: 299500338
Test: N/A
Relnote: remove the use of rememberSaveable for tooltips.
Change-Id: Icc131c852cc3b3c722954aecb0a002711e13ca96
M compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/BasicTooltip.kt
M compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
ke...@google.com <ke...@google.com>
na...@google.com <na...@google.com> #6
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.foundation:foundation:1.6.0-alpha06
androidx.compose.foundation:foundation-android:1.6.0-alpha06
androidx.compose.material3:material3:1.2.0-alpha08
androidx.compose.material3:material3-android:1.2.0-alpha08
Description
After updating to compose
1.6.0-alpha05
, my app was crashing after pressing the home button to leave the app. After some testing, I think the app crashes whenTooltipBox
is used.I've attached a small app that I've been using to test the bug on different devices, but any app that uses
TooltipBox
should have the issue.Steps to reproduce:
The app should crash with a
RuntimeException
. If we hide the Icon + Tooltip before clicking Home, the app won't crash.I've tested the app on a device running SDK 30 and on three emulator images running 26, 29 and 33.
I hope this is not a problem with my to avoid mistakes.
TooltipBox
implementation. I've used the same composable fromTooltipSamples