mirror of
https://github.com/bitwarden/android.git
synced 2024-11-24 02:15:53 +03:00
PM-11643: Add LauncherPackageNameManager for tracking launcher apps (#3861)
This commit is contained in:
parent
b672418c45
commit
c02afb6714
5 changed files with 141 additions and 0 deletions
|
@ -245,6 +245,10 @@
|
|||
<intent>
|
||||
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.di
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilityAutofillManager
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilityAutofillManagerImpl
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.LauncherPackageNameManager
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.LauncherPackageNameManagerImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.time.Clock
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
|
@ -18,4 +22,15 @@ object AccessibilityModule {
|
|||
@Provides
|
||||
fun providesAccessibilityInvokeManager(): AccessibilityAutofillManager =
|
||||
AccessibilityAutofillManagerImpl()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun providesLauncherPackageNameManager(
|
||||
clock: Clock,
|
||||
packageManager: PackageManager,
|
||||
): LauncherPackageNameManager =
|
||||
LauncherPackageNameManagerImpl(
|
||||
clockProvider = { clock },
|
||||
packageManager = packageManager,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.manager
|
||||
|
||||
/**
|
||||
* A manager for getting the launcher packages from the operating system.
|
||||
*/
|
||||
interface LauncherPackageNameManager {
|
||||
/**
|
||||
* A list of launcher packages from the operating system.
|
||||
*/
|
||||
val launcherPackages: List<String>
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.manager
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import java.time.Clock
|
||||
|
||||
/**
|
||||
* How frequently the cached launcher list should be refreshed.
|
||||
*/
|
||||
private const val REFRESH_CACHE_MS: Long = 1L * 60L * 60L * 1000L
|
||||
|
||||
/**
|
||||
* The default implementation of the [LauncherPackageNameManager].
|
||||
*/
|
||||
class LauncherPackageNameManagerImpl(
|
||||
private val clockProvider: () -> Clock,
|
||||
private val packageManager: PackageManager,
|
||||
) : LauncherPackageNameManager {
|
||||
private var lastLauncherFetchMs: Long = 0L
|
||||
private var cachedLauncherPackages: List<String>? = null
|
||||
|
||||
override val launcherPackages: List<String>
|
||||
get() {
|
||||
if (cachedLauncherPackages == null ||
|
||||
clockProvider().millis() - lastLauncherFetchMs > REFRESH_CACHE_MS
|
||||
) {
|
||||
updateCachedLauncherPackages()
|
||||
}
|
||||
return cachedLauncherPackages.orEmpty()
|
||||
}
|
||||
|
||||
private fun updateCachedLauncherPackages() {
|
||||
cachedLauncherPackages = packageManager
|
||||
.queryIntentActivities(
|
||||
Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
|
||||
0,
|
||||
)
|
||||
.map { it.activityInfo.packageName }
|
||||
lastLauncherFetchMs = clockProvider().millis()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.manager
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
|
||||
class LauncherPackageNameManagerTest {
|
||||
private val packageManager: PackageManager = mockk()
|
||||
private var mutableClock: Clock = FIXED_CLOCK
|
||||
|
||||
private val launcherPackageNameManager: LauncherPackageNameManager =
|
||||
LauncherPackageNameManagerImpl(
|
||||
clockProvider = { mutableClock },
|
||||
packageManager = packageManager,
|
||||
)
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `launcherPackages should populate cache on first attempt and use cached value for second attempt and repopulate the cache after an hour`() {
|
||||
val testPackageName = "testPackageName"
|
||||
val testActivityInfo = ActivityInfo().apply {
|
||||
packageName = testPackageName
|
||||
}
|
||||
val resolveInfo = ResolveInfo().apply {
|
||||
activityInfo = testActivityInfo
|
||||
}
|
||||
val packages = listOf(resolveInfo)
|
||||
every { packageManager.queryIntentActivities(any(), any<Int>()) } returns packages
|
||||
|
||||
val firstResult = launcherPackageNameManager.launcherPackages
|
||||
|
||||
assertEquals(listOf(testPackageName), firstResult)
|
||||
verify(exactly = 1) {
|
||||
packageManager.queryIntentActivities(any(), any<Int>())
|
||||
}
|
||||
clearMocks(packageManager)
|
||||
|
||||
val secondResult = launcherPackageNameManager.launcherPackages
|
||||
|
||||
assertEquals(listOf(testPackageName), secondResult)
|
||||
verify(exactly = 0) {
|
||||
packageManager.queryIntentActivities(any(), any<Int>())
|
||||
}
|
||||
clearMocks(packageManager)
|
||||
|
||||
every { packageManager.queryIntentActivities(any(), any<Int>()) } returns emptyList()
|
||||
mutableClock = Clock.offset(FIXED_CLOCK, Duration.ofMinutes(61))
|
||||
val thirdResult = launcherPackageNameManager.launcherPackages
|
||||
|
||||
assertEquals(emptyList<String>(), thirdResult)
|
||||
verify(exactly = 1) {
|
||||
packageManager.queryIntentActivities(any(), any<Int>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val FIXED_CLOCK: Clock = Clock.fixed(
|
||||
Instant.parse("2023-10-27T12:00:00Z"),
|
||||
ZoneOffset.UTC,
|
||||
)
|
Loading…
Reference in a new issue