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.usagestats.data.repository
18
19 import android.app.usage.UsageEvents
20 import android.app.usage.UsageEventsQuery
21 import android.app.usage.UsageStatsManager
22 import com.android.app.tracing.coroutines.withContextTraced as withContext
23 import com.android.systemui.common.usagestats.data.model.UsageStatsQuery
24 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel
25 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel.Lifecycle
26 import com.android.systemui.dagger.SysUISingleton
27 import com.android.systemui.dagger.qualifiers.Background
28 import javax.inject.Inject
29 import kotlin.coroutines.CoroutineContext
30
31 /** Repository for querying UsageStatsManager */
32 interface UsageStatsRepository {
33 /** Query activity events. */
34 suspend fun queryActivityEvents(query: UsageStatsQuery): List<ActivityEventModel>
35 }
36
37 @SysUISingleton
38 class UsageStatsRepositoryImpl
39 @Inject
40 constructor(
41 @Background private val bgContext: CoroutineContext,
42 private val usageStatsManager: UsageStatsManager,
43 ) : UsageStatsRepository {
44 private companion object {
45 const val TAG = "UsageStatsRepository"
46 }
47
queryActivityEventsnull48 override suspend fun queryActivityEvents(query: UsageStatsQuery): List<ActivityEventModel> =
49 withContext("$TAG#queryActivityEvents", bgContext) {
50 val systemQuery: UsageEventsQuery =
51 UsageEventsQuery.Builder(query.startTime, query.endTime)
52 .apply {
53 setUserId(query.user.identifier)
54 setEventTypes(
55 UsageEvents.Event.ACTIVITY_RESUMED,
56 UsageEvents.Event.ACTIVITY_PAUSED,
57 UsageEvents.Event.ACTIVITY_STOPPED,
58 UsageEvents.Event.ACTIVITY_DESTROYED,
59 )
60 if (query.packageNames.isNotEmpty()) {
61 setPackageNames(*query.packageNames.toTypedArray())
62 }
63 }
64 .build()
65
66 val events: UsageEvents? = usageStatsManager.queryEvents(systemQuery)
67
68 buildList {
69 events.forEachEvent { event ->
70 val lifecycle =
71 when (event.eventType) {
72 UsageEvents.Event.ACTIVITY_RESUMED -> Lifecycle.RESUMED
73 UsageEvents.Event.ACTIVITY_PAUSED -> Lifecycle.PAUSED
74 UsageEvents.Event.ACTIVITY_STOPPED -> Lifecycle.STOPPED
75 UsageEvents.Event.ACTIVITY_DESTROYED -> Lifecycle.DESTROYED
76 else -> Lifecycle.UNKNOWN
77 }
78
79 add(
80 ActivityEventModel(
81 instanceId = event.instanceId,
82 packageName = event.packageName,
83 lifecycle = lifecycle,
84 timestamp = event.timeStamp,
85 )
86 )
87 }
88 }
89 }
90 }
91
forEachEventnull92 private inline fun UsageEvents?.forEachEvent(action: (UsageEvents.Event) -> Unit) {
93 this ?: return
94 val event = UsageEvents.Event()
95 while (getNextEvent(event)) {
96 action(event)
97 }
98 }
99