1 /* 2 * 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.domain.interactor 18 19 import android.annotation.CurrentTimeMillisLong 20 import android.app.usage.UsageEvents 21 import android.content.pm.UserInfo 22 import android.os.UserHandle 23 import androidx.test.ext.junit.runners.AndroidJUnit4 24 import androidx.test.filters.SmallTest 25 import com.android.systemui.SysuiTestCase 26 import com.android.systemui.common.usagestats.data.repository.fakeUsageStatsRepository 27 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel 28 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel.Lifecycle 29 import com.android.systemui.kosmos.testScope 30 import com.android.systemui.settings.fakeUserTracker 31 import com.android.systemui.testKosmos 32 import com.android.systemui.util.time.fakeSystemClock 33 import com.google.common.truth.Truth.assertThat 34 import kotlinx.coroutines.test.runTest 35 import org.junit.Before 36 import org.junit.Test 37 import org.junit.runner.RunWith 38 39 @SmallTest 40 @RunWith(AndroidJUnit4::class) 41 class UsageStatsInteractorTest : SysuiTestCase() { 42 43 private val kosmos = testKosmos() 44 private val testScope = kosmos.testScope 45 46 private val userTracker = kosmos.fakeUserTracker 47 private val systemClock = kosmos.fakeSystemClock 48 private val repository = kosmos.fakeUsageStatsRepository 49 50 private val underTest = kosmos.usageStatsInteractor 51 52 @Before setUpnull53 fun setUp() { 54 userTracker.set(listOf(MAIN_USER, SECONDARY_USER), 0) 55 } 56 57 @Test testQueryWithBeginAndEndTimenull58 fun testQueryWithBeginAndEndTime() = 59 testScope.runTest { 60 // This event is outside the queried time, and therefore should 61 // not be returned. 62 addEvent( 63 instanceId = 1, 64 type = UsageEvents.Event.ACTIVITY_RESUMED, 65 timestamp = 5, 66 ) 67 addEvent( 68 type = UsageEvents.Event.ACTIVITY_PAUSED, 69 timestamp = 10, 70 instanceId = 1, 71 ) 72 addEvent( 73 type = UsageEvents.Event.ACTIVITY_STOPPED, 74 timestamp = 20, 75 instanceId = 2, 76 ) 77 // This event is outside the queried time, and therefore should 78 // not be returned. 79 addEvent( 80 type = UsageEvents.Event.ACTIVITY_DESTROYED, 81 timestamp = 50, 82 instanceId = 2, 83 ) 84 85 assertThat(underTest.queryActivityEvents(startTime = 10, endTime = 50)) 86 .containsExactly( 87 ActivityEventModel( 88 instanceId = 1, 89 packageName = DEFAULT_PACKAGE, 90 lifecycle = Lifecycle.PAUSED, 91 timestamp = 10, 92 ), 93 ActivityEventModel( 94 instanceId = 2, 95 packageName = DEFAULT_PACKAGE, 96 lifecycle = Lifecycle.STOPPED, 97 timestamp = 20, 98 ), 99 ) 100 } 101 102 @Test testQueryForDifferentUsersnull103 fun testQueryForDifferentUsers() = 104 testScope.runTest { 105 addEvent( 106 user = MAIN_USER.userHandle, 107 type = UsageEvents.Event.ACTIVITY_PAUSED, 108 timestamp = 10, 109 instanceId = 1, 110 ) 111 addEvent( 112 user = SECONDARY_USER.userHandle, 113 type = UsageEvents.Event.ACTIVITY_RESUMED, 114 timestamp = 11, 115 instanceId = 2, 116 ) 117 118 assertThat(underTest.queryActivityEvents(startTime = 10, endTime = 15)) 119 .containsExactly( 120 ActivityEventModel( 121 instanceId = 1, 122 packageName = DEFAULT_PACKAGE, 123 lifecycle = Lifecycle.PAUSED, 124 timestamp = 10, 125 ), 126 ) 127 } 128 129 @Test testQueryWithUserSpecifiednull130 fun testQueryWithUserSpecified() = 131 testScope.runTest { 132 addEvent( 133 user = MAIN_USER.userHandle, 134 type = UsageEvents.Event.ACTIVITY_PAUSED, 135 timestamp = 10, 136 instanceId = 1, 137 ) 138 addEvent( 139 user = SECONDARY_USER.userHandle, 140 type = UsageEvents.Event.ACTIVITY_RESUMED, 141 timestamp = 11, 142 instanceId = 2, 143 ) 144 145 assertThat( 146 underTest.queryActivityEvents( 147 startTime = 10, 148 endTime = 15, 149 userHandle = SECONDARY_USER.userHandle, 150 ), 151 ) 152 .containsExactly( 153 ActivityEventModel( 154 instanceId = 2, 155 packageName = DEFAULT_PACKAGE, 156 lifecycle = Lifecycle.RESUMED, 157 timestamp = 11, 158 ), 159 ) 160 } 161 162 @Test testQueryForSpecificPackagesnull163 fun testQueryForSpecificPackages() = 164 testScope.runTest { 165 addEvent( 166 packageName = DEFAULT_PACKAGE, 167 type = UsageEvents.Event.ACTIVITY_PAUSED, 168 timestamp = 10, 169 instanceId = 1, 170 ) 171 addEvent( 172 packageName = OTHER_PACKAGE, 173 type = UsageEvents.Event.ACTIVITY_RESUMED, 174 timestamp = 11, 175 instanceId = 2, 176 ) 177 178 assertThat( 179 underTest.queryActivityEvents( 180 startTime = 10, 181 endTime = 10000, 182 packageNames = listOf(OTHER_PACKAGE), 183 ), 184 ) 185 .containsExactly( 186 ActivityEventModel( 187 instanceId = 2, 188 packageName = OTHER_PACKAGE, 189 lifecycle = Lifecycle.RESUMED, 190 timestamp = 11, 191 ), 192 ) 193 } 194 195 @Test testNonActivityEventnull196 fun testNonActivityEvent() = 197 testScope.runTest { 198 addEvent( 199 type = UsageEvents.Event.CHOOSER_ACTION, 200 timestamp = 10, 201 instanceId = 1, 202 ) 203 204 assertThat(underTest.queryActivityEvents(startTime = 1, endTime = 20)).isEmpty() 205 } 206 207 @Test testNoEndTimeSpecifiednull208 fun testNoEndTimeSpecified() = 209 testScope.runTest { 210 systemClock.setCurrentTimeMillis(30) 211 212 addEvent( 213 type = UsageEvents.Event.ACTIVITY_PAUSED, 214 timestamp = 10, 215 instanceId = 1, 216 ) 217 addEvent( 218 type = UsageEvents.Event.ACTIVITY_STOPPED, 219 timestamp = 20, 220 instanceId = 2, 221 ) 222 // This event is outside the queried time, and therefore should 223 // not be returned. 224 addEvent( 225 type = UsageEvents.Event.ACTIVITY_DESTROYED, 226 timestamp = 50, 227 instanceId = 2, 228 ) 229 230 assertThat(underTest.queryActivityEvents(startTime = 1)) 231 .containsExactly( 232 ActivityEventModel( 233 instanceId = 1, 234 packageName = DEFAULT_PACKAGE, 235 lifecycle = Lifecycle.PAUSED, 236 timestamp = 10, 237 ), 238 ActivityEventModel( 239 instanceId = 2, 240 packageName = DEFAULT_PACKAGE, 241 lifecycle = Lifecycle.STOPPED, 242 timestamp = 20, 243 ), 244 ) 245 } 246 addEventnull247 private fun addEvent( 248 instanceId: Int, 249 user: UserHandle = MAIN_USER.userHandle, 250 packageName: String = DEFAULT_PACKAGE, 251 @UsageEvents.Event.EventType type: Int, 252 @CurrentTimeMillisLong timestamp: Long, 253 ) { 254 repository.addEvent( 255 instanceId = instanceId, 256 user = user, 257 packageName = packageName, 258 type = type, 259 timestamp = timestamp, 260 ) 261 } 262 263 private companion object { 264 const val DEFAULT_PACKAGE = "pkg.default" 265 const val OTHER_PACKAGE = "pkg.other" 266 val MAIN_USER: UserInfo = UserInfo(0, "primary", UserInfo.FLAG_MAIN) 267 val SECONDARY_USER: UserInfo = UserInfo(10, "secondary", 0) 268 } 269 } 270