1 /*
<lambda>null2  * Copyright (C) 2024 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.common.data.repository
18 
19 import android.content.pm.PackageInstaller
20 import android.os.Handler
21 import com.android.internal.annotations.GuardedBy
22 import com.android.systemui.common.shared.model.PackageInstallSession
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.dagger.qualifiers.Background
25 import com.android.systemui.log.LogBuffer
26 import com.android.systemui.log.core.Logger
27 import com.android.systemui.log.dagger.PackageChangeRepoLog
28 import javax.inject.Inject
29 import kotlinx.coroutines.CoroutineScope
30 import kotlinx.coroutines.flow.Flow
31 import kotlinx.coroutines.flow.MutableStateFlow
32 import kotlinx.coroutines.flow.asStateFlow
33 import kotlinx.coroutines.flow.distinctUntilChanged
34 import kotlinx.coroutines.flow.dropWhile
35 import kotlinx.coroutines.flow.launchIn
36 import kotlinx.coroutines.flow.map
37 import kotlinx.coroutines.flow.onEach
38 
39 /** Monitors package install sessions for all users. */
40 @SysUISingleton
41 class PackageInstallerMonitor
42 @Inject
43 constructor(
44     @Background private val bgHandler: Handler,
45     @Background private val bgScope: CoroutineScope,
46     @PackageChangeRepoLog logBuffer: LogBuffer,
47     private val packageInstaller: PackageInstaller,
48 ) : PackageInstaller.SessionCallback() {
49 
50     private val logger = Logger(logBuffer, TAG)
51 
52     @GuardedBy("sessions") private val sessions = mutableMapOf<Int, PackageInstallSession>()
53 
54     private val _installSessions =
55         MutableStateFlow<List<PackageInstallSession>>(emptyList()).apply {
56             subscriptionCount
57                 .map { count -> count > 0 }
58                 .distinctUntilChanged()
59                 // Drop initial false value
60                 .dropWhile { !it }
61                 .onEach { isActive ->
62                     if (isActive) {
63                         synchronized(sessions) {
64                             sessions.putAll(
65                                 packageInstaller.allSessions
66                                     .map { session -> session.toModel() }
67                                     .associateBy { it.sessionId }
68                             )
69                             updateInstallerSessionsFlow()
70                         }
71                         packageInstaller.registerSessionCallback(
72                             this@PackageInstallerMonitor,
73                             bgHandler
74                         )
75                     } else {
76                         synchronized(sessions) {
77                             sessions.clear()
78                             updateInstallerSessionsFlow()
79                         }
80                         packageInstaller.unregisterSessionCallback(this@PackageInstallerMonitor)
81                     }
82                 }
83                 .launchIn(bgScope)
84         }
85 
86     val installSessionsForPrimaryUser: Flow<List<PackageInstallSession>> =
87         _installSessions.asStateFlow()
88 
89     /** Called when a new installer session is created. */
90     override fun onCreated(sessionId: Int) {
91         logger.i({ "session created $int1" }) { int1 = sessionId }
92         updateSession(sessionId)
93     }
94 
95     /** Called when new installer session has finished. */
96     override fun onFinished(sessionId: Int, success: Boolean) {
97         logger.i({ "session finished $int1" }) { int1 = sessionId }
98         synchronized(sessions) {
99             sessions.remove(sessionId)
100             updateInstallerSessionsFlow()
101         }
102     }
103 
104     /**
105      * Badging details for the session changed. For example, the app icon or label has been updated.
106      */
107     override fun onBadgingChanged(sessionId: Int) {
108         logger.i({ "session badging changed $int1" }) { int1 = sessionId }
109         updateSession(sessionId)
110     }
111 
112     /**
113      * A session is considered active when there is ongoing forward progress being made. For
114      * example, a package started downloading.
115      */
116     override fun onActiveChanged(sessionId: Int, active: Boolean) {
117         // Active status updates are not tracked for now
118     }
119 
120     override fun onProgressChanged(sessionId: Int, progress: Float) {
121         // Progress updates are not tracked for now
122     }
123 
124     private fun updateSession(sessionId: Int) {
125         val session = packageInstaller.getSessionInfo(sessionId)
126 
127         synchronized(sessions) {
128             if (session == null) {
129                 sessions.remove(sessionId)
130             } else {
131                 sessions[sessionId] = session.toModel()
132             }
133             updateInstallerSessionsFlow()
134         }
135     }
136 
137     @GuardedBy("sessions")
138     private fun updateInstallerSessionsFlow() {
139         _installSessions.value = sessions.values.toList()
140     }
141 
142     companion object {
143         const val TAG = "PackageInstallerMonitor"
144 
145         private fun PackageInstaller.SessionInfo.toModel(): PackageInstallSession {
146             return PackageInstallSession(
147                 sessionId = this.sessionId,
148                 packageName = this.appPackageName,
149                 icon = this.getAppIcon(),
150                 user = this.user,
151             )
152         }
153     }
154 }
155