Glitchy notifs on clock size change
Notifications weren't animating Y position changes as expected. In order
to synchronize the animation, we tether the intrablueprint transition
state into KeyguardRootViewBinder which listens for placeholder position
changes and forwards them to the notification code. This function now
skips certain layouts during transitions to prevent later layout changes
from conflicting with the running animation. These layouts are erronous
to the transition and suppressed by the transition directly for other
relevant lockscreen elements.
To facilitate two binders relying on the same transition state, I've
moved the transition management logic from the binder to the model, but
otherwise not modified it much. This makes the state available to more
components, allows the binder to be stateless, and lets us convert it
to being a top-level kotlin object like other binders.
I've also corrected an issue where the notif shelf would animate in when
the clock size changed. AodNotificationIconsSection.applyConstraints was
not setting the visibility, so it'd default to VISIBLE for a moment when
it was applied. The transition would pick up this incorrect transient
visibility value and animate the element in.
Bug: 341932557
Test: Manual & Presubmits
Flag: com.android.systemui.migrate_clocks_to_blueprint
Change-Id: Ib447caeb142f55a04f77f34cf8bd7fe6e7e83896
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index a50cc8f..306f4ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -103,7 +103,6 @@
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
private val lockscreenContentViewModel: LockscreenContentViewModel,
private val lockscreenSceneBlueprintsLazy: Lazy<Set<LockscreenSceneBlueprint>>,
- private val keyguardBlueprintViewBinder: KeyguardBlueprintViewBinder,
private val clockInteractor: KeyguardClockInteractor,
private val keyguardViewMediator: KeyguardViewMediator,
) : CoreStartable {
@@ -150,7 +149,7 @@
cs.connect(composeView.id, BOTTOM, PARENT_ID, BOTTOM)
keyguardRootView.addView(composeView)
} else {
- keyguardBlueprintViewBinder.bind(
+ KeyguardBlueprintViewBinder.bind(
keyguardRootView,
keyguardBlueprintViewModel,
keyguardClockViewModel,
@@ -197,12 +196,14 @@
KeyguardRootViewBinder.bind(
keyguardRootView,
keyguardRootViewModel,
+ keyguardBlueprintViewModel,
configuration,
occludingAppDeviceEntryMessageViewModel,
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
clockInteractor,
+ keyguardClockViewModel,
interactionJankMonitor,
deviceEntryHapticsInteractor,
vibratorHelper,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index 8160335..bec8f3d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -17,17 +17,12 @@
package com.android.systemui.keyguard.ui.binder
-import android.os.Handler
-import android.transition.Transition
-import android.transition.TransitionManager
import android.util.Log
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launch
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition
@@ -40,47 +35,9 @@
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import com.android.systemui.util.kotlin.pairwise
-import javax.inject.Inject
-import kotlin.math.max
-@SysUISingleton
-class KeyguardBlueprintViewBinder
-@Inject
-constructor(
- @Main private val handler: Handler,
-) {
- private var runningPriority = -1
- private val runningTransitions = mutableSetOf<Transition>()
- private val isTransitionRunning: Boolean
- get() = runningTransitions.size > 0
- private val transitionListener =
- object : Transition.TransitionListener {
- override fun onTransitionCancel(transition: Transition) {
- if (DEBUG) Log.e(TAG, "onTransitionCancel: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionEnd(transition: Transition) {
- if (DEBUG) Log.e(TAG, "onTransitionEnd: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionPause(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionPause: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionResume(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionResume: ${transition::class.simpleName}")
- runningTransitions.add(transition)
- }
-
- override fun onTransitionStart(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionStart: ${transition::class.simpleName}")
- runningTransitions.add(transition)
- }
- }
-
+object KeyguardBlueprintViewBinder {
+ @JvmStatic
fun bind(
constraintLayout: ConstraintLayout,
viewModel: KeyguardBlueprintViewModel,
@@ -118,7 +75,7 @@
)
}
- runTransition(constraintLayout, transition, config) {
+ viewModel.runTransition(constraintLayout, transition, config) {
// Replace sections from the previous blueprint with the new ones
blueprint.replaceViews(
constraintLayout,
@@ -146,7 +103,7 @@
viewModel.refreshTransition.collect { config ->
val blueprint = viewModel.blueprint.value
- runTransition(
+ viewModel.runTransition(
constraintLayout,
IntraBlueprintTransition(config, clockViewModel, smartspaceViewModel),
config,
@@ -167,50 +124,6 @@
}
}
- private fun runTransition(
- constraintLayout: ConstraintLayout,
- transition: Transition,
- config: Config,
- apply: () -> Unit,
- ) {
- val currentPriority = if (isTransitionRunning) runningPriority else -1
- if (config.checkPriority && config.type.priority < currentPriority) {
- if (DEBUG) {
- Log.w(
- TAG,
- "runTransition: skipping ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
- )
- }
- apply()
- return
- }
-
- if (DEBUG) {
- Log.i(
- TAG,
- "runTransition: running ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
- )
- }
-
- // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to
- // the running set until the copy is started by the handler.
- runningTransitions.add(transition)
- transition.addListener(transitionListener)
- runningPriority = max(currentPriority, config.type.priority)
-
- handler.post {
- if (config.terminatePrevious) {
- TransitionManager.endTransitions(constraintLayout)
- }
-
- TransitionManager.beginDelayedTransition(constraintLayout, transition)
- runningTransitions.remove(transition)
- apply()
- }
- }
-
private fun logAlphaVisibilityOfAppliedConstraintSet(
cs: ConstraintSet,
viewModel: KeyguardClockViewModel
@@ -237,8 +150,6 @@
)
}
- companion object {
- private const val TAG = "KeyguardBlueprintViewBinder"
- private const val DEBUG = false
- }
+ private const val TAG = "KeyguardBlueprintViewBinder"
+ private const val DEBUG = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 39db22d..fc92afe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -22,6 +22,7 @@
import android.annotation.SuppressLint
import android.graphics.Point
import android.graphics.Rect
+import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.View.OnLayoutChangeListener
@@ -56,8 +57,11 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
+import com.android.systemui.keyguard.ui.viewmodel.TransitionData
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
@@ -93,12 +97,14 @@
fun bind(
view: ViewGroup,
viewModel: KeyguardRootViewModel,
+ blueprintViewModel: KeyguardBlueprintViewModel,
configuration: ConfigurationState,
occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel?,
chipbarCoordinator: ChipbarCoordinator?,
screenOffAnimationController: ScreenOffAnimationController,
shadeInteractor: ShadeInteractor,
clockInteractor: KeyguardClockInteractor,
+ clockViewModel: KeyguardClockViewModel,
interactionJankMonitor: InteractionJankMonitor?,
deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor?,
vibratorHelper: VibratorHelper?,
@@ -348,7 +354,16 @@
}
}
- disposables += view.onLayoutChanged(OnLayoutChange(viewModel, childViews, burnInParams))
+ disposables +=
+ view.onLayoutChanged(
+ OnLayoutChange(
+ viewModel,
+ blueprintViewModel,
+ clockViewModel,
+ childViews,
+ burnInParams
+ )
+ )
// Views will be added or removed after the call to bind(). This is needed to avoid many
// calls to findViewById
@@ -404,9 +419,13 @@
private class OnLayoutChange(
private val viewModel: KeyguardRootViewModel,
+ private val blueprintViewModel: KeyguardBlueprintViewModel,
+ private val clockViewModel: KeyguardClockViewModel,
private val childViews: Map<Int, View>,
private val burnInParams: MutableStateFlow<BurnInParameters>,
) : OnLayoutChangeListener {
+ var prevTransition: TransitionData? = null
+
override fun onLayoutChange(
view: View,
left: Int,
@@ -418,11 +437,21 @@
oldRight: Int,
oldBottom: Int
) {
+ // After layout, ensure the notifications are positioned correctly
childViews[nsslPlaceholderId]?.let { notificationListPlaceholder ->
- // After layout, ensure the notifications are positioned correctly
+ // Do not update a second time while a blueprint transition is running
+ val transition = blueprintViewModel.currentTransition.value
+ val shouldAnimate = transition != null && transition.config.type.animateNotifChanges
+ if (prevTransition == transition && shouldAnimate) {
+ if (DEBUG) Log.w(TAG, "Skipping; layout during transition")
+ return
+ }
+
+ prevTransition = transition
viewModel.onNotificationContainerBoundsChanged(
notificationListPlaceholder.top.toFloat(),
notificationListPlaceholder.bottom.toFloat(),
+ animate = shouldAnimate
)
}
@@ -585,4 +614,6 @@
private const val ID = "occluding_app_device_entry_unlock_msg"
private const val AOD_ICONS_APPEAR_DURATION: Long = 200
+ private const val TAG = "KeyguardRootViewBinder"
+ private const val DEBUG = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index fb1853f..777c873 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -68,7 +68,9 @@
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
@@ -134,6 +136,7 @@
private val vibratorHelper: VibratorHelper,
private val indicationController: KeyguardIndicationController,
private val keyguardRootViewModel: KeyguardRootViewModel,
+ private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
@Assisted bundle: Bundle,
private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
private val chipbarCoordinator: ChipbarCoordinator,
@@ -143,6 +146,7 @@
private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
private val defaultShortcutsSection: DefaultShortcutsSection,
private val keyguardClockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
) {
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -379,12 +383,14 @@
KeyguardRootViewBinder.bind(
keyguardRootView,
keyguardRootViewModel,
+ keyguardBlueprintViewModel,
configuration,
occludingAppDeviceEntryMessageViewModel,
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
keyguardClockInteractor,
+ keyguardClockViewModel,
null, // jank monitor not required for preview mode
null, // device entry haptics not required preview mode
null, // device entry haptics not required for preview mode
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
index 02e9ca5..39f1ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
@@ -31,16 +31,16 @@
enum class Type(
val priority: Int,
+ val animateNotifChanges: Boolean,
) {
- ClockSize(100),
- ClockCenter(99),
- DefaultClockStepping(98),
- AodNotifIconsTransition(97),
- SmartspaceVisibility(2),
- DefaultTransition(1),
+ ClockSize(100, true),
+ ClockCenter(99, false),
+ DefaultClockStepping(98, false),
+ SmartspaceVisibility(2, true),
+ DefaultTransition(1, false),
// When transition between blueprint, we don't need any duration or interpolator but we need
// all elements go to correct state
- NoTransition(0),
+ NoTransition(0, false),
}
data class Config(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index 2832e9d..d77b548 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -19,6 +19,8 @@
import android.content.Context
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -29,6 +31,7 @@
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -38,6 +41,7 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.ui.SystemBarUtilsState
+import com.android.systemui.util.ui.value
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
@@ -51,6 +55,7 @@
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
private val notificationIconAreaController: NotificationIconAreaController,
private val systemBarUtilsState: SystemBarUtilsState,
+ private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
private var nicBindingDisposable: DisposableHandle? = null
@@ -101,20 +106,14 @@
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
+
val bottomMargin =
context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
-
- val useSplitShade = context.resources.getBoolean(R.bool.config_use_split_notification_shade)
-
- val topAlignment =
- if (useSplitShade) {
- TOP
- } else {
- BOTTOM
- }
+ val isVisible = rootViewModel.isNotifIconContainerVisible.value
constraintSet.apply {
connect(nicId, TOP, R.id.smart_space_barrier_bottom, BOTTOM, bottomMargin)
setGoneMargin(nicId, BOTTOM, bottomMargin)
+ setVisibility(nicId, if (isVisible.value) VISIBLE else GONE)
connect(
nicId,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 7c745bc..f17dbd2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -369,6 +369,21 @@
addTarget(R.id.status_view_media_container)
}
+ override fun mutateBounds(
+ view: View,
+ fromIsVis: Boolean,
+ toIsVis: Boolean,
+ fromBounds: Rect,
+ toBounds: Rect,
+ fromSSBounds: Rect?,
+ toSSBounds: Rect?
+ ) {
+ // If view is changing visibility, hold it in place
+ if (fromIsVis == toIsVis) return
+ if (DEBUG) Log.i(TAG, "Holding position of ${view.id}")
+ toBounds.set(fromBounds)
+ }
+
companion object {
const val STATUS_AREA_MOVE_UP_MILLIS = 967L
const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index b1f1898..7ac03bf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -17,15 +17,119 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.Handler
+import android.transition.Transition
+import android.transition.TransitionManager
+import android.util.Log
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+data class TransitionData(
+ val config: Config,
+ val start: Long = System.currentTimeMillis(),
+)
class KeyguardBlueprintViewModel
@Inject
constructor(
+ @Main private val handler: Handler,
keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
) {
val blueprint = keyguardBlueprintInteractor.blueprint
val blueprintId = keyguardBlueprintInteractor.blueprintId
val refreshTransition = keyguardBlueprintInteractor.refreshTransition
+
+ private val _currentTransition = MutableStateFlow<TransitionData?>(null)
+ val currentTransition = _currentTransition.asStateFlow()
+
+ private val runningTransitions = mutableSetOf<Transition>()
+ private val transitionListener =
+ object : Transition.TransitionListener {
+ override fun onTransitionCancel(transition: Transition) {
+ if (DEBUG) Log.e(TAG, "onTransitionCancel: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionEnd(transition: Transition) {
+ if (DEBUG) Log.e(TAG, "onTransitionEnd: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionPause(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionPause: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionResume(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionResume: ${transition::class.simpleName}")
+ updateTransitions(null) { add(transition) }
+ }
+
+ override fun onTransitionStart(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionStart: ${transition::class.simpleName}")
+ updateTransitions(null) { add(transition) }
+ }
+ }
+
+ fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) {
+ runningTransitions.mutate()
+
+ if (runningTransitions.size <= 0) _currentTransition.value = null
+ else if (data != null) _currentTransition.value = data
+ }
+
+ fun runTransition(
+ constraintLayout: ConstraintLayout,
+ transition: Transition,
+ config: Config,
+ apply: () -> Unit,
+ ) {
+ val currentPriority = currentTransition.value?.let { it.config.type.priority } ?: -1
+ if (config.checkPriority && config.type.priority < currentPriority) {
+ if (DEBUG) {
+ Log.w(
+ TAG,
+ "runTransition: skipping ${transition::class.simpleName}: " +
+ "currentPriority=$currentPriority; config=$config"
+ )
+ }
+ apply()
+ return
+ }
+
+ if (DEBUG) {
+ Log.i(
+ TAG,
+ "runTransition: running ${transition::class.simpleName}: " +
+ "currentPriority=$currentPriority; config=$config"
+ )
+ }
+
+ // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to
+ // the running set until the copy is started by the handler.
+ updateTransitions(TransitionData(config)) { add(transition) }
+ transition.addListener(transitionListener)
+
+ handler.post {
+ if (config.terminatePrevious) {
+ TransitionManager.endTransitions(constraintLayout)
+ }
+
+ TransitionManager.beginDelayedTransition(constraintLayout, transition)
+ apply()
+
+ // Delay removal until after copied transition has started
+ handler.post { updateTransitions(null) { remove(transition) } }
+ }
+ }
+
+ companion object {
+ private const val TAG = "KeyguardBlueprintViewModel"
+ private const val DEBUG = true
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index aaec69f..1ec2a49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -58,6 +58,8 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
@@ -67,13 +69,14 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class KeyguardRootViewModel
@Inject
constructor(
- @Application private val scope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val dozeParameters: DozeParameters,
private val keyguardInteractor: KeyguardInteractor,
@@ -280,7 +283,7 @@
burnInJob?.cancel()
burnInJob =
- scope.launch("$TAG#aodBurnInViewModel") {
+ applicationScope.launch("$TAG#aodBurnInViewModel") {
aodBurnInViewModel.movement(params).collect { _burnInModel.value = it }
}
}
@@ -294,7 +297,7 @@
}
/** Is the notification icon container visible? */
- val isNotifIconContainerVisible: Flow<AnimatedValue<Boolean>> =
+ val isNotifIconContainerVisible: StateFlow<AnimatedValue<Boolean>> =
combine(
goneToAodTransitionRunning,
keyguardTransitionInteractor.finishedKeyguardState.map {
@@ -336,11 +339,15 @@
}
}
}
- .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = AnimatedValue.NotAnimating(false),
+ )
- fun onNotificationContainerBoundsChanged(top: Float, bottom: Float) {
+ fun onNotificationContainerBoundsChanged(top: Float, bottom: Float, animate: Boolean = false) {
keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = top, bottom = bottom)
+ NotificationContainerBounds(top = top, bottom = bottom, isAnimated = animate)
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
index a18b033..ec2a1d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
@@ -17,9 +17,11 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.fakeExecutorHandler
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.testKosmos
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,12 +35,16 @@
class KeyguardBlueprintViewModelTest : SysuiTestCase() {
@Mock private lateinit var keyguardBlueprintInteractor: KeyguardBlueprintInteractor
private lateinit var undertest: KeyguardBlueprintViewModel
+ private val kosmos = testKosmos()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
undertest =
- KeyguardBlueprintViewModel(keyguardBlueprintInteractor = keyguardBlueprintInteractor)
+ KeyguardBlueprintViewModel(
+ handler = kosmos.fakeExecutorHandler,
+ keyguardBlueprintInteractor = keyguardBlueprintInteractor,
+ )
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt
deleted file mode 100644
index 24d2c2f..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2023 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.keyguard.ui.binder
-
-import android.os.fakeExecutorHandler
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.keyguardBlueprintViewBinder by
- Kosmos.Fixture { KeyguardBlueprintViewBinder(fakeExecutorHandler) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
index 63b87c0..0c538ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
@@ -16,8 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.fakeExecutorHandler
import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
import com.android.systemui.kosmos.Kosmos
val Kosmos.keyguardBlueprintViewModel by
- Kosmos.Fixture { KeyguardBlueprintViewModel(keyguardBlueprintInteractor) }
+ Kosmos.Fixture {
+ KeyguardBlueprintViewModel(
+ fakeExecutorHandler,
+ keyguardBlueprintInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index f856d27..2567ffe 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -32,7 +32,7 @@
val Kosmos.keyguardRootViewModel by Fixture {
KeyguardRootViewModel(
- scope = applicationCoroutineScope,
+ applicationScope = applicationCoroutineScope,
deviceEntryInteractor = deviceEntryInteractor,
dozeParameters = dozeParameters,
keyguardInteractor = keyguardInteractor,