Add a useCase to get the remaining app time rounded down to minutes

The flag will be applied at the code using this use case.

Bug: 405974619
Fix: 405974619
Flag: com.android.launcher3.enable_refactor_digital_wellbeing_toast
Test: GetRemainingAppTimerDurationUseCaseTest
Change-Id: I939b3447b93e7e84eb69032aa0f67c1629f916c1
This commit is contained in:
Shamali P
2025-03-24 15:57:38 +00:00
parent 24ba38b393
commit 258d1297fe
2 changed files with 281 additions and 0 deletions
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.recents.domain.usecase
import android.os.UserHandle
import com.android.quickstep.recents.data.AppTimersRepository
import java.time.Duration
/**
* Use case that provides remaining duration on the app usage limit timer set for the given user.
*
* Responsible for applying business rules around how the remaining time is treated within overview
* module e.g. rounds partial minutes to the next minute.
*/
class GetRemainingAppTimerDurationUseCase(private val appTimersRepository: AppTimersRepository) {
suspend operator fun invoke(packageName: String, userHandle: UserHandle): Duration? {
val totalRemainingDuration =
appTimersRepository.getRemainingDuration(packageName, userHandle) ?: return null
val totalRemainingMs = totalRemainingDuration.toMillis()
val isLessThanAMinute = totalRemainingMs < MS_IN_A_MINUTE
val isInWholeMinutes = (totalRemainingMs % MS_IN_A_MINUTE) == 0L
return when {
isLessThanAMinute || isInWholeMinutes -> totalRemainingDuration
else -> Duration.ofMinutes(totalRemainingDuration.toMinutes() + 1)
}
}
companion object {
private const val MS_IN_A_MINUTE: Int = 60000
}
}
@@ -0,0 +1,235 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.recents.domain.usecase
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.quickstep.recents.data.FakeAppTimersRepository
import com.google.common.truth.Truth.assertThat
import java.time.Duration
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
/** Tests for [GetRemainingAppTimerDurationUseCase]. */
@RunWith(AndroidJUnit4::class)
class GetRemainingAppTimerDurationUseCaseTest {
private val appTimersRepository = FakeAppTimersRepository()
@OptIn(ExperimentalCoroutinesApi::class)
private val testScope = TestScope(UnconfinedTestDispatcher())
private val systemUnderTest = GetRemainingAppTimerDurationUseCase(appTimersRepository)
@Test
fun noSetLimit_returnsNull() =
testScope.runTest {
appTimersRepository.resetTimer(PACKAGE_NAME, USER_HANDLE)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isNull()
}
@Test
fun lessThanMinuteRemaining_aMilliSecondLess_noRounding() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(1).minusMillis(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(usageRemaining)
}
@Test
fun lessThanMinuteRemaining_aSecondLess_noRounding() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(1).minusSeconds(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(usageRemaining)
}
@Test
fun aWholeMinuteRemaining_returnsAMinute() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(usageRemaining)
}
@Test
fun littleOverAMinuteRemaining_aMilliSecondMore_roundsToTwoMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(1).plusMillis(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(2))
}
@Test
fun littleOverAMinuteRemaining_aSecondMore_roundsToTwoMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(1).plusSeconds(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(2))
}
@Test
fun littleUnderTwoMinuteRemaining_aMilliSecondLess_roundsToTwoMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(2).minusMillis(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(2))
}
@Test
fun littleUnderTwoMinuteRemaining_aSecondLess_roundsToTwoMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(2).minusSeconds(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(2))
}
@Test
fun severalMinutesAndLittleOverRemaining_aMilliSecondMore_returnsRoundedMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(5).plusMillis(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(6))
}
@Test
fun severalMinutesAndLittleOverRemaining_aSecondMore_returnsRoundedMinutes() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(5).plusSeconds(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(6))
}
@Test
fun multipleWholeMinutesRemaining_noRounding() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(5)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(5))
}
@Test
fun multipleHoursAndASecondOver_roundsSecondToAMinute() =
testScope.runTest {
val usageRemaining = Duration.ofHours(5).plusSeconds(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofHours(5).plusMinutes(1))
}
@Test
fun multipleHoursAndAMilliSecondOver_roundsMillisecondToAMinute() =
testScope.runTest {
val usageRemaining = Duration.ofHours(5).plusMillis(1)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofHours(5).plusMinutes(1))
}
@Test
fun returnsCorrectRemainingTimeOnEachInvocation() =
testScope.runTest {
val usageRemaining = Duration.ofMinutes(5).plusSeconds(10)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemaining)
val remainingDuration = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(remainingDuration).isEqualTo(Duration.ofMinutes(6))
appTimersRepository.resetTimer(PACKAGE_NAME, USER_HANDLE)
val newRemainingTime = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
assertThat(newRemainingTime).isNull()
}
@Test
fun differentApps_returnsCorrectRemainingTime() =
testScope.runTest {
val usageRemainingAppOne = Duration.ofMinutes(5)
val usageRemainingAppTwo = Duration.ofMinutes(2)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemainingAppOne)
appTimersRepository.setTimer(PACKAGE_NAME_TWO, USER_HANDLE, usageRemainingAppTwo)
val remainingDurationAppOne = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
val remainingDurationAppTwo = systemUnderTest.invoke(PACKAGE_NAME_TWO, USER_HANDLE)
assertThat(remainingDurationAppOne).isEqualTo(usageRemainingAppOne)
assertThat(remainingDurationAppTwo).isEqualTo(usageRemainingAppTwo)
}
@Test
fun appInMultipleUsers_returnsCorrectRemainingTime() =
testScope.runTest {
val usageRemainingUserOne = Duration.ofMinutes(5)
val usageRemainingUserTwo = Duration.ofMinutes(2)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE, usageRemainingUserOne)
appTimersRepository.setTimer(PACKAGE_NAME, USER_HANDLE_TWO, usageRemainingUserTwo)
val remainingDurationUserOne = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE)
val remainingDurationUserTwo = systemUnderTest.invoke(PACKAGE_NAME, USER_HANDLE_TWO)
assertThat(remainingDurationUserOne).isEqualTo(usageRemainingUserOne)
assertThat(remainingDurationUserTwo).isEqualTo(usageRemainingUserTwo)
}
companion object {
private const val PACKAGE_NAME = "com.test.1"
private val USER_HANDLE = UserHandle(0)
private const val PACKAGE_NAME_TWO = "com.test.2"
private val USER_HANDLE_TWO = UserHandle(2)
}
}