1 /*
2  * Copyright (C) 2023 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
18 
19 import android.annotation.WorkerThread
20 import android.content.ComponentCallbacks2
21 import android.util.Log
22 import com.android.systemui.CoreStartable
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.dagger.qualifiers.Application
25 import com.android.systemui.dagger.qualifiers.Background
26 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
27 import com.android.systemui.keyguard.shared.model.Edge
28 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
29 import com.android.systemui.keyguard.shared.model.TransitionState
30 import com.android.systemui.scene.domain.interactor.SceneInteractor
31 import com.android.systemui.scene.shared.flag.SceneContainerFlag
32 import com.android.systemui.scene.shared.model.Scenes
33 import com.android.systemui.utils.GlobalWindowManager
34 import javax.inject.Inject
35 import kotlinx.coroutines.CoroutineDispatcher
36 import kotlinx.coroutines.CoroutineScope
37 import kotlinx.coroutines.flow.filter
38 import kotlinx.coroutines.launch
39 
40 /**
41  * Releases cached resources on allocated by keyguard.
42  *
43  * We release most resources when device goes idle since that's the least likely time it'll cause
44  * jank during use. Idle in this case means after lockscreen -> AoD transition completes or when the
45  * device screen is turned off, depending on settings.
46  */
47 @SysUISingleton
48 class ResourceTrimmer
49 @Inject
50 constructor(
51     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
52     private val globalWindowManager: GlobalWindowManager,
53     @Application private val applicationScope: CoroutineScope,
54     @Background private val bgDispatcher: CoroutineDispatcher,
55     private val sceneInteractor: SceneInteractor,
56 ) : CoreStartable {
57 
startnull58     override fun start() {
59         Log.d(LOG_TAG, "Resource trimmer registered.")
60         applicationScope.launch(bgDispatcher) {
61             // We drop 1 to avoid triggering on initial collect().
62             if (SceneContainerFlag.isEnabled) {
63                 sceneInteractor.transitionState
64                     .filter { it.isIdle(Scenes.Gone) }
65                     .collect { onKeyguardGone() }
66             } else {
67                 keyguardTransitionInteractor.transition(Edge.create(to = GONE)).collect {
68                     if (it.transitionState == TransitionState.FINISHED) {
69                         onKeyguardGone()
70                     }
71                 }
72             }
73         }
74     }
75 
76     @WorkerThread
onKeyguardGonenull77     private fun onKeyguardGone() {
78         // We want to clear temporary caches we've created while rendering and animating
79         // lockscreen elements, especially clocks.
80         Log.d(LOG_TAG, "Sending TRIM_MEMORY_UI_HIDDEN.")
81         globalWindowManager.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
82     }
83 
84     companion object {
85         private const val LOG_TAG = "ResourceTrimmer"
86     }
87 }
88