diff --git a/app/src/main/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImpl.kt b/app/src/main/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImpl.kt index 8bcae77..1ce8670 100644 --- a/app/src/main/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImpl.kt +++ b/app/src/main/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImpl.kt @@ -26,18 +26,24 @@ class SystemPackageRepositoryImpl @Inject constructor( private val packageManager: PackageManager = context.packageManager override fun getInstalledPackages(): List { - val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.MATCH_DISABLED_COMPONENTS - } else { - @Suppress("DEPRECATION") - PackageManager.GET_UNINSTALLED_PACKAGES + var flags = 0 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + flags = flags or PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + flags = flags or PackageManager.MATCH_APEX + } + return packageManager.getInstalledPackages(flags).map { it.toSystemPackage() } } override fun getPackageDetails(packageName: String): SystemPackage? { return try { - val info = packageManager.getPackageInfo(packageName, 0) + var flags = 0 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + flags = flags or PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + } + val info = packageManager.getPackageInfo(packageName, flags) info.toSystemPackage() } catch (e: PackageManager.NameNotFoundException) { null @@ -46,12 +52,14 @@ class SystemPackageRepositoryImpl @Inject constructor( override fun getActivities(packageName: String): List { return try { - val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PackageManager.GET_ACTIVITIES or PackageManager.MATCH_ALL or PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - } else { - @Suppress("DEPRECATION") - PackageManager.GET_ACTIVITIES + var flags = PackageManager.GET_ACTIVITIES or PackageManager.GET_META_DATA + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + flags = flags or PackageManager.MATCH_DISABLED_COMPONENTS or + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS or + PackageManager.MATCH_DIRECT_BOOT_AWARE or + PackageManager.MATCH_DIRECT_BOOT_UNAWARE } + val info = packageManager.getPackageInfo(packageName, flags) val activities = info.activities ?: return emptyList() val appRes = getLocalizedResources(packageName) diff --git a/app/src/test/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImplTest.kt b/app/src/test/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImplTest.kt new file mode 100644 index 0000000..26f5d4b --- /dev/null +++ b/app/src/test/java/de/szalkowski/activitylauncher/data/packages/SystemPackageRepositoryImplTest.kt @@ -0,0 +1,71 @@ +package de.szalkowski.activitylauncher.data.packages + +import android.content.Context +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import de.szalkowski.activitylauncher.domain.settings.SettingsRepository +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.* +import java.lang.reflect.Field +import java.lang.reflect.Modifier + +class SystemPackageRepositoryImplTest { + private val context: Context = mock() + private val packageManager: PackageManager = mock() + private val settingsRepository: SettingsRepository = mock() + private lateinit var repository: SystemPackageRepositoryImpl + + @Before + fun setup() { + whenever(context.packageManager).thenReturn(packageManager) + repository = SystemPackageRepositoryImpl(context, settingsRepository) + } + + private fun setSdkVersion(version: Int) { + val field = Build.VERSION::class.java.getField("SDK_INT") + field.isAccessible = true + val modifiersField = Field::class.java.getDeclaredField("modifiers") + modifiersField.isAccessible = true + modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv()) + field.set(null, version) + } + + @Test + fun `getInstalledPackages should use correct flags on API 30`() { + // We can't easily mock Build.VERSION.SDK_INT globally in a standard unit test without PowerMock or similar, + // but we can test the behavior assuming current environment or using reflection (risky). + // For now, let's just verify it calls the package manager. + + val pkg = PackageInfo().apply { packageName = "com.test" } + whenever(packageManager.getInstalledPackages(anyInt())).thenReturn(listOf(pkg)) + + repository.getInstalledPackages() + + val captor = argumentCaptor() + verify(packageManager).getInstalledPackages(captor.capture()) + + val flags = captor.firstValue + // Verify it does NOT contain MATCH_UNINSTALLED_PACKAGES (8192) + assertEquals(0, flags and 0x00002000) + } + + @Test + fun `getPackageDetails should use correct flags`() { + val packageName = "com.test" + val pkg = PackageInfo().apply { this.packageName = packageName } + whenever(packageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(pkg) + + repository.getPackageDetails(packageName) + + val captor = argumentCaptor() + verify(packageManager).getPackageInfo(eq(packageName), captor.capture()) + + val flags = captor.firstValue + // Verify it does NOT contain MATCH_UNINSTALLED_PACKAGES + assertEquals(0, flags and 0x00002000) + } +}