summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chandru S <chandruis@google.com> 2024-09-04 16:10:22 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-09-04 16:10:22 +0000
commit5f5abbfe0a0caa52fa21faf9e9ca521246b49cd0 (patch)
tree09ccfd946f0260fe524e192edd27d9d33685242a
parent9f11bb825b3e7e628a24fe15e344431baba4a943 (diff)
parent29e6bfef478935993e6e12db6cd161e61afd34c8 (diff)
Merge "Change the compose bouncer wire-up to follow recommended architecture guidelines" into main
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt84
3 files changed, 119 insertions, 77 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
index cc8dce7938aa..49dadcefb276 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
@@ -2,13 +2,11 @@ package com.android.systemui.bouncer.ui.binder
import android.view.ViewGroup
import com.android.keyguard.KeyguardMessageAreaController
-import com.android.keyguard.ViewMediatorCallback
import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.bouncer.ui.BouncerDialogFactory
+import com.android.systemui.bouncer.ui.viewmodel.BouncerContainerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.dagger.SysUISingleton
@@ -39,12 +37,9 @@ constructor(
data class ComposeBouncerDependencies
@Inject
constructor(
- val legacyInteractor: PrimaryBouncerInteractor,
val viewModelFactory: BouncerSceneContentViewModel.Factory,
val dialogFactory: BouncerDialogFactory,
- val authenticationInteractor: AuthenticationInteractor,
- val viewMediatorCallback: ViewMediatorCallback?,
- val selectedUserInteractor: SelectedUserInteractor,
+ val bouncerContainerViewModelFactory: BouncerContainerViewModel.Factory,
)
/**
@@ -63,12 +58,9 @@ constructor(
val deps = composeBouncerDependencies.get()
ComposeBouncerViewBinder.bind(
view,
- deps.legacyInteractor,
deps.viewModelFactory,
deps.dialogFactory,
- deps.authenticationInteractor,
- deps.selectedUserInteractor,
- deps.viewMediatorCallback,
+ deps.bouncerContainerViewModelFactory,
)
} else {
val deps = legacyBouncerDependencies.get()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
index c4bbd9cf0d9f..b5e54d5f079b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
@@ -5,89 +5,55 @@ import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
import androidx.compose.ui.platform.ComposeView
-import androidx.core.view.isVisible
+import androidx.core.view.isGone
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.keyguard.ViewMediatorCallback
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.composable.BouncerContainer
+import com.android.systemui.bouncer.ui.viewmodel.BouncerContainerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
+import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.launch
+import com.android.systemui.lifecycle.setSnapshotBinding
+import com.android.systemui.lifecycle.viewModel
+import kotlinx.coroutines.awaitCancellation
/** View binder responsible for binding the compose version of the bouncer. */
object ComposeBouncerViewBinder {
fun bind(
view: ViewGroup,
- legacyInteractor: PrimaryBouncerInteractor,
viewModelFactory: BouncerSceneContentViewModel.Factory,
dialogFactory: BouncerDialogFactory,
- authenticationInteractor: AuthenticationInteractor,
- selectedUserInteractor: SelectedUserInteractor,
- viewMediatorCallback: ViewMediatorCallback?,
+ bouncerContainerViewModelFactory: BouncerContainerViewModel.Factory,
) {
- view.addView(
- ComposeView(view.context).apply {
- repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- setViewTreeOnBackPressedDispatcherOwner(
- object : OnBackPressedDispatcherOwner {
- override val onBackPressedDispatcher =
- OnBackPressedDispatcher().apply {
- setOnBackInvokedDispatcher(
- view.viewRootImpl.onBackInvokedDispatcher
- )
- }
-
- override val lifecycle: Lifecycle =
- this@repeatWhenAttached.lifecycle
- }
- )
- setContent { BouncerContainer(viewModelFactory, dialogFactory) }
- }
- }
- }
- )
-
view.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- legacyInteractor.isShowing.collectLatest { bouncerShowing ->
- view.isVisible = bouncerShowing
- }
- }
+ view.viewModel(
+ minWindowLifecycleState = WindowLifecycleState.ATTACHED,
+ factory = { bouncerContainerViewModelFactory.create() },
+ traceName = "ComposeBouncerViewBinder",
+ ) { viewModel ->
+ try {
+ view.setViewTreeOnBackPressedDispatcherOwner(
+ object : OnBackPressedDispatcherOwner {
+ override val onBackPressedDispatcher =
+ OnBackPressedDispatcher().apply {
+ setOnBackInvokedDispatcher(
+ view.viewRootImpl.onBackInvokedDispatcher
+ )
+ }
- launch {
- authenticationInteractor.onAuthenticationResult.collectLatest {
- authenticationSucceeded ->
- if (authenticationSucceeded) {
- // Some dismiss actions require that keyguard be dismissed right away or
- // deferred until something else later on dismisses keyguard (eg. end of
- // a hide animation).
- val deferKeyguardDone =
- legacyInteractor.bouncerDismissAction?.onDismissAction?.onDismiss()
- legacyInteractor.setDismissAction(null, null)
+ override val lifecycle: Lifecycle = this@repeatWhenAttached.lifecycle
+ }
+ )
- viewMediatorCallback?.let {
- val selectedUserId = selectedUserInteractor.getSelectedUserId()
- if (deferKeyguardDone == true) {
- it.keyguardDonePending(selectedUserId)
- } else {
- it.keyguardDone(selectedUserId)
- }
- }
+ view.addView(
+ ComposeView(view.context).apply {
+ setContent { BouncerContainer(viewModelFactory, dialogFactory) }
}
- }
- }
- launch {
- legacyInteractor.startingDisappearAnimation.collectLatest {
- it.run()
- legacyInteractor.hide()
- }
+ )
+ view.setSnapshotBinding { view.isGone = !viewModel.isVisible }
+ awaitCancellation()
+ } finally {
+ view.removeAllViews()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
new file mode 100644
index 000000000000..d223657aa74d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bouncer.ui.viewmodel
+
+import androidx.compose.runtime.getValue
+import com.android.keyguard.ViewMediatorCallback
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+class BouncerContainerViewModel
+@AssistedInject
+constructor(
+ private val legacyInteractor: PrimaryBouncerInteractor,
+ private val authenticationInteractor: AuthenticationInteractor,
+ private val selectedUserInteractor: SelectedUserInteractor,
+ private val viewMediatorCallback: ViewMediatorCallback?,
+) : ExclusiveActivatable() {
+
+ private val hydrator = Hydrator("BouncerContainerViewModel")
+
+ val isVisible: Boolean by
+ hydrator.hydratedStateOf(traceName = "isVisible", source = legacyInteractor.isShowing)
+
+ override suspend fun onActivated(): Nothing {
+ coroutineScope {
+ launch {
+ authenticationInteractor.onAuthenticationResult.collect { authenticationSucceeded ->
+ if (authenticationSucceeded) {
+ // Some dismiss actions require that keyguard be dismissed right away or
+ // deferred until something else later on dismisses keyguard (eg. end of
+ // a hide animation).
+ val deferKeyguardDone =
+ legacyInteractor.bouncerDismissAction?.onDismissAction?.onDismiss()
+ legacyInteractor.setDismissAction(null, null)
+
+ viewMediatorCallback?.let {
+ val selectedUserId = selectedUserInteractor.getSelectedUserId()
+ if (deferKeyguardDone == true) {
+ it.keyguardDonePending(selectedUserId)
+ } else {
+ it.keyguardDone(selectedUserId)
+ }
+ }
+ }
+ }
+ }
+
+ launch {
+ legacyInteractor.startingDisappearAnimation.collect {
+ it.run()
+ legacyInteractor.hide()
+ }
+ }
+
+ hydrator.activate()
+ }
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): BouncerContainerViewModel
+ }
+}