1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.keyguard.ui.binder 18 19 import android.view.ViewGroup 20 import androidx.lifecycle.Lifecycle 21 import androidx.lifecycle.repeatOnLifecycle 22 import com.android.app.tracing.coroutines.launchTraced as launch 23 import com.android.internal.jank.Cuj.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD 24 import com.android.internal.jank.Cuj.CUJ_LOCKSCREEN_TRANSITION_TO_AOD 25 import com.android.internal.jank.Cuj.CUJ_SCREEN_OFF_SHOW_AOD 26 import com.android.internal.jank.InteractionJankMonitor 27 import com.android.systemui.keyguard.KeyguardViewMediator 28 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor 29 import com.android.systemui.keyguard.shared.model.TransitionState 30 import com.android.systemui.keyguard.shared.model.TransitionStep 31 import com.android.systemui.keyguard.ui.viewmodel.KeyguardJankViewModel 32 import com.android.systemui.lifecycle.repeatWhenAttached 33 import com.android.systemui.scene.shared.flag.SceneContainerFlag 34 import kotlinx.coroutines.CoroutineDispatcher 35 import kotlinx.coroutines.DisposableHandle 36 import kotlinx.coroutines.ExperimentalCoroutinesApi 37 38 /** Jank monitoring related to keyguard and transitions. */ 39 @OptIn(ExperimentalCoroutinesApi::class) 40 object KeyguardJankBinder { 41 @JvmStatic bindnull42 fun bind( 43 view: ViewGroup, 44 viewModel: KeyguardJankViewModel, 45 jankMonitor: InteractionJankMonitor?, 46 clockInteractor: KeyguardClockInteractor, 47 keyguardViewMediator: KeyguardViewMediator?, 48 mainImmediateDispatcher: CoroutineDispatcher, 49 ): DisposableHandle? { 50 if (jankMonitor == null) { 51 return null 52 } 53 54 fun processStep(step: TransitionStep, cuj: Int) { 55 val clockId = clockInteractor.renderedClockId 56 when (step.transitionState) { 57 TransitionState.STARTED -> { 58 val builder = 59 InteractionJankMonitor.Configuration.Builder.withView(cuj, view) 60 .setTag(clockId) 61 jankMonitor.begin(builder) 62 } 63 64 TransitionState.CANCELED -> jankMonitor.cancel(cuj) 65 66 TransitionState.FINISHED -> jankMonitor.end(cuj) 67 68 TransitionState.RUNNING -> Unit 69 } 70 } 71 72 return view.repeatWhenAttached(mainImmediateDispatcher) { 73 repeatOnLifecycle(Lifecycle.State.CREATED) { 74 launch { 75 viewModel.goneToAodTransition.collect { 76 processStep(it, CUJ_SCREEN_OFF_SHOW_AOD) 77 if (it.transitionState == TransitionState.FINISHED) { 78 keyguardViewMediator?.maybeHandlePendingLock() 79 } 80 } 81 } 82 83 // The following is already done in KeyguardTransitionAnimationCallbackImpl. 84 if (!SceneContainerFlag.isEnabled) { 85 launch { 86 viewModel.lockscreenToAodTransition.collect { 87 processStep(it, CUJ_LOCKSCREEN_TRANSITION_TO_AOD) 88 } 89 } 90 91 launch { 92 viewModel.aodToLockscreenTransition.collect { 93 processStep(it, CUJ_LOCKSCREEN_TRANSITION_FROM_AOD) 94 } 95 } 96 } 97 } 98 } 99 } 100 } 101