Skip to content

Commit

Permalink
Updates AmbientAware to avoid recreating whole tree (#2050)
Browse files Browse the repository at this point in the history
  • Loading branch information
garanj authored Feb 20, 2024
1 parent 71688da commit 492231f
Showing 1 changed file with 31 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,56 +51,48 @@ fun AmbientAware(
isAlwaysOnScreen: Boolean = true,
block: @Composable (AmbientStateUpdate) -> Unit,
) {
var ambientUpdate by remember(isAlwaysOnScreen) {
mutableStateOf(if (isAlwaysOnScreen) null else AmbientStateUpdate(AmbientState.Interactive))
}

val activity = LocalContext.current.findActivityOrNull()
// Using AmbientAware correctly relies on there being an Activity context. If there isn't, then
// gracefully allow the composition of [block], but no ambient-mode functionality is enabled.
if (activity != null && isAlwaysOnScreen) {
AmbientAwareEnabled(activity, block)
} else {
AmbientAwareDisabled(block)
}
}
val lifecycle = LocalLifecycleOwner.current.lifecycle
val observer = remember {
val callback = object : AmbientLifecycleObserver.AmbientLifecycleCallback {
override fun onEnterAmbient(ambientDetails: AmbientLifecycleObserver.AmbientDetails) {
ambientUpdate = AmbientStateUpdate(AmbientState.Ambient(ambientDetails))
}

@Composable
private fun AmbientAwareEnabled(
activity: Activity,
block: @Composable (AmbientStateUpdate) -> Unit,
) {
val lifecycle = LocalLifecycleOwner.current.lifecycle
var ambientUpdate by remember { mutableStateOf<AmbientStateUpdate?>(null) }
override fun onExitAmbient() {
ambientUpdate = AmbientStateUpdate(AmbientState.Interactive)
}

val observer = remember {
val callback = object : AmbientLifecycleObserver.AmbientLifecycleCallback {
override fun onEnterAmbient(ambientDetails: AmbientLifecycleObserver.AmbientDetails) {
ambientUpdate = AmbientStateUpdate(AmbientState.Ambient(ambientDetails))
override fun onUpdateAmbient() {
val lastAmbientDetails =
(ambientUpdate?.ambientState as? AmbientState.Ambient)?.ambientDetails
ambientUpdate = AmbientStateUpdate(AmbientState.Ambient(lastAmbientDetails))
}
}

override fun onExitAmbient() {
ambientUpdate = AmbientStateUpdate(AmbientState.Interactive)
AmbientLifecycleObserver(activity, callback).also {
// Necessary to populate the initial value
val initialAmbientState = if (it.isAmbient) {
AmbientState.Ambient(null)
} else {
AmbientState.Interactive
}
ambientUpdate = AmbientStateUpdate(initialAmbientState)
}

override fun onUpdateAmbient() {
val lastAmbientDetails =
(ambientUpdate?.ambientState as? AmbientState.Ambient)?.ambientDetails
ambientUpdate = AmbientStateUpdate(AmbientState.Ambient(lastAmbientDetails))
}
}
AmbientLifecycleObserver(activity, callback).also {
// Necessary to populate the initial value
val initialAmbientState = if (it.isAmbient) {
AmbientState.Ambient(null)
} else {
AmbientState.Interactive
}
ambientUpdate = AmbientStateUpdate(initialAmbientState)
}
}

DisposableEffect(Unit) {
lifecycle.addObserver(observer)
DisposableEffect(Unit) {
lifecycle.addObserver(observer)

onDispose {
lifecycle.removeObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}

Expand All @@ -109,12 +101,6 @@ private fun AmbientAwareEnabled(
}
}

@Composable
private fun AmbientAwareDisabled(block: @Composable (AmbientStateUpdate) -> Unit) {
val staticAmbientState by remember { mutableStateOf(AmbientStateUpdate(AmbientState.Interactive)) }
block(staticAmbientState)
}

private fun Context.findActivityOrNull(): Activity? {
var context = this
while (context is ContextWrapper) {
Expand Down

0 comments on commit 492231f

Please sign in to comment.