diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt index cb0bfc6480905..69c6131679a98 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt @@ -21,11 +21,8 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED import android.content.pm.PackageManager -import android.util.Log import com.android.settingslib.spa.framework.util.asyncFilter -private const val TAG = "PackageManagers" - interface IPackageManagers { fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo? @@ -94,12 +91,7 @@ internal class PackageManagersImpl( }.toSet() override fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? = - try { - packageManagerWrapper.getPackageInfoAsUserCached(packageName, flags.toLong(), userId) - } catch (e: PackageManager.NameNotFoundException) { - Log.w(TAG, "getPackageInfoAsUserCached() failed", e) - null - } + packageManagerWrapper.getPackageInfoAsUserCached(packageName, flags.toLong(), userId) private fun Int.hasFlag(flag: Int) = (this and flag) > 0 } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index c4f2df2df50cd..26174c2e03ca6 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -17,13 +17,17 @@ package com.android.settingslib.spaprivileged.model.app import android.content.Context +import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags +import android.content.pm.ResolveInfo import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule @@ -51,24 +55,10 @@ class AppListRepositoryTest { private lateinit var repository: AppListRepository - private val normalApp = ApplicationInfo().apply { - packageName = "normal" - enabled = true - } - - private val instantApp = ApplicationInfo().apply { - packageName = "instant" - enabled = true - privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT - } - @Before fun setUp() { whenever(context.packageManager).thenReturn(packageManager) whenever(packageManager.getInstalledModules(anyInt())).thenReturn(emptyList()) - whenever( - packageManager.getInstalledApplicationsAsUser(any(), eq(USER_ID)) - ).thenReturn(listOf(normalApp, instantApp)) whenever( packageManager.queryIntentActivitiesAsUser(any(), any(), eq(USER_ID)) ).thenReturn(emptyList()) @@ -76,25 +66,151 @@ class AppListRepositoryTest { repository = AppListRepositoryImpl(context) } + private fun mockInstalledApplications(apps: List) { + whenever( + packageManager.getInstalledApplicationsAsUser(any(), eq(USER_ID)) + ).thenReturn(apps) + } + @Test - fun notShowInstantApps() = runTest { + fun loadApps_notShowInstantApps() = runTest { + mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) val appListFlow = repository.loadApps(appListConfig) - assertThat(appListFlow).containsExactly(normalApp) + assertThat(appListFlow).containsExactly(NORMAL_APP) } @Test - fun showInstantApps() = runTest { + fun loadApps_showInstantApps() = runTest { + mockInstalledApplications(listOf(NORMAL_APP, INSTANT_APP)) val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = true) val appListFlow = repository.loadApps(appListConfig) - assertThat(appListFlow).containsExactly(normalApp, instantApp) + assertThat(appListFlow).containsExactly(NORMAL_APP, INSTANT_APP) } + @Test + fun loadApps_isDisabledUntilUsed() = runTest { + val app = ApplicationInfo().apply { + packageName = "is.disabled.until.used" + enabled = false + enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + } + mockInstalledApplications(listOf(app)) + val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) + + val appListFlow = repository.loadApps(appListConfig) + + assertThat(appListFlow).containsExactly(app) + } + + @Test + fun loadApps_disabled() = runTest { + val app = ApplicationInfo().apply { + packageName = "disabled" + enabled = false + } + mockInstalledApplications(listOf(app)) + val appListConfig = AppListConfig(userId = USER_ID, showInstantApps = false) + + val appListFlow = repository.loadApps(appListConfig) + + assertThat(appListFlow).isEmpty() + } + + @Test + fun showSystemPredicate_showSystem() = runTest { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_SYSTEM + } + + val showSystemPredicate = getShowSystemPredicate(showSystem = true) + + assertThat(showSystemPredicate(app)).isTrue() + } + + @Test + fun showSystemPredicate_notShowSystemAndIsSystemApp() = runTest { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_SYSTEM + } + + val showSystemPredicate = getShowSystemPredicate(showSystem = false) + + assertThat(showSystemPredicate(app)).isFalse() + } + + @Test + fun showSystemPredicate_isUpdatedSystemApp() = runTest { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_SYSTEM or ApplicationInfo.FLAG_UPDATED_SYSTEM_APP + } + + val showSystemPredicate = getShowSystemPredicate(showSystem = false) + + assertThat(showSystemPredicate(app)).isTrue() + } + + @Test + fun showSystemPredicate_isHome() = runTest { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_SYSTEM + packageName = "home.app" + } + whenever(packageManager.getHomeActivities(any())).thenAnswer { + @Suppress("UNCHECKED_CAST") + val resolveInfos = it.arguments[0] as MutableList + resolveInfos.add(resolveInfoOf(packageName = app.packageName)) + null + } + + val showSystemPredicate = getShowSystemPredicate(showSystem = false) + + assertThat(showSystemPredicate(app)).isTrue() + } + + @Test + fun showSystemPredicate_appInLauncher() = runTest { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_SYSTEM + packageName = "app.in.launcher" + } + whenever( + packageManager.queryIntentActivitiesAsUser(any(), any(), eq(USER_ID)) + ).thenReturn(listOf(resolveInfoOf(packageName = app.packageName))) + + val showSystemPredicate = getShowSystemPredicate(showSystem = false) + + assertThat(showSystemPredicate(app)).isTrue() + } + + private suspend fun getShowSystemPredicate(showSystem: Boolean) = + repository.showSystemPredicate( + userIdFlow = flowOf(USER_ID), + showSystemFlow = flowOf(showSystem), + ).first() + private companion object { const val USER_ID = 0 + + val NORMAL_APP = ApplicationInfo().apply { + packageName = "normal" + enabled = true + } + + val INSTANT_APP = ApplicationInfo().apply { + packageName = "instant" + enabled = true + privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT + } + + fun resolveInfoOf(packageName: String) = ResolveInfo().apply { + activityInfo = ActivityInfo().apply { + this.packageName = packageName + } + } } } diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt new file mode 100644 index 0000000000000..a1b2df3acdfb3 --- /dev/null +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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.settingslib.spaprivileged.model.app + +import android.app.admin.DevicePolicyManager +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.os.UserManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager +import com.android.settingslib.spaprivileged.framework.common.userManager +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.Mockito.`when` as whenever + +@RunWith(AndroidJUnit4::class) +class ApplicationInfosTest { + @get:Rule + val mockito: MockitoRule = MockitoJUnit.rule() + + @Spy + private val context: Context = ApplicationProvider.getApplicationContext() + + @Mock + private lateinit var userManager: UserManager + + @Mock + private lateinit var devicePolicyManager: DevicePolicyManager + + @Before + fun setUp() { + whenever(context.userManager).thenReturn(userManager) + whenever(context.devicePolicyManager).thenReturn(devicePolicyManager) + } + + @Test + fun userId() { + val app = ApplicationInfo().apply { + uid = 123 + } + + val userId = app.userId + + assertThat(userId).isEqualTo(0) + } + + @Test + fun userHandle() { + val app = ApplicationInfo().apply { + uid = 123 + } + + val userHandle = app.userHandle + + assertThat(userHandle.identifier).isEqualTo(0) + } + + @Test + fun hasFlag() { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_INSTALLED + } + + val hasFlag = app.hasFlag(ApplicationInfo.FLAG_INSTALLED) + + assertThat(hasFlag).isTrue() + } + + @Test + fun installed() { + val app = ApplicationInfo().apply { + flags = ApplicationInfo.FLAG_INSTALLED + } + + val installed = app.installed + + assertThat(installed).isTrue() + } + + @Test + fun isDisabledUntilUsed() { + val app = ApplicationInfo().apply { + enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + } + + val isDisabledUntilUsed = app.isDisabledUntilUsed + + assertThat(isDisabledUntilUsed).isTrue() + } + + @Test + fun isDisallowControl() { + val app = ApplicationInfo().apply { + uid = 123 + } + whenever( + userManager.hasBaseUserRestriction(UserManager.DISALLOW_APPS_CONTROL, app.userHandle) + ).thenReturn(true) + + val isDisallowControl = app.isDisallowControl(context) + + assertThat(isDisallowControl).isTrue() + } + + @Test + fun isActiveAdmin() { + val app = ApplicationInfo().apply { + packageName = PACKAGE_NAME + uid = 123 + } + whenever(devicePolicyManager.packageHasActiveAdmins(PACKAGE_NAME, app.userId)) + .thenReturn(true) + + val isActiveAdmin = app.isActiveAdmin(context) + + assertThat(isActiveAdmin).isTrue() + } + + @Test + fun toRoute() { + val app = ApplicationInfo().apply { + packageName = PACKAGE_NAME + uid = 123 + } + + val route = app.toRoute() + + assertThat(route).isEqualTo("package.name/0") + } + + private companion object { + const val PACKAGE_NAME = "package.name" + } +} diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt index 6c31f4b7e2f16..7c928389d08fe 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt @@ -30,6 +30,74 @@ class PackageManagersTest { private val packageManagersImpl = PackageManagersImpl(fakePackageManagerWrapper) + @Test + fun getPackageInfoAsUser_notFound() { + fakePackageManagerWrapper.fakePackageInfo = null + + val packageInfo = packageManagersImpl.getPackageInfoAsUser(PACKAGE_NAME, 0) + + assertThat(packageInfo).isNull() + } + + @Test + fun getPackageInfoAsUser_found() { + fakePackageManagerWrapper.fakePackageInfo = PackageInfo() + + val packageInfo = packageManagersImpl.getPackageInfoAsUser(PACKAGE_NAME, 0) + + assertThat(packageInfo).isSameInstanceAs(fakePackageManagerWrapper.fakePackageInfo) + } + + @Test + fun hasRequestPermission_packageInfoIsNull_returnFalse() { + fakePackageManagerWrapper.fakePackageInfo = null + + val hasRequestPermission = with(packageManagersImpl) { + APP.hasRequestPermission(PERMISSION_A) + } + + assertThat(hasRequestPermission).isFalse() + } + + @Test + fun hasRequestPermission_requestedPermissionsIsNull_returnFalse() { + fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply { + requestedPermissions = null + } + + val hasRequestPermission = with(packageManagersImpl) { + APP.hasRequestPermission(PERMISSION_A) + } + + assertThat(hasRequestPermission).isFalse() + } + + @Test + fun hasRequestPermission_notRequested_returnFalse() { + fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply { + requestedPermissions = emptyArray() + } + + val hasRequestPermission = with(packageManagersImpl) { + APP.hasRequestPermission(PERMISSION_A) + } + + assertThat(hasRequestPermission).isFalse() + } + + @Test + fun hasRequestPermission_requested_returnTrue() { + fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply { + requestedPermissions = arrayOf(PERMISSION_A) + } + + val hasRequestPermission = with(packageManagersImpl) { + APP.hasRequestPermission(PERMISSION_A) + } + + assertThat(hasRequestPermission).isTrue() + } + @Test fun hasGrantPermission_packageInfoIsNull_returnFalse() { fakePackageManagerWrapper.fakePackageInfo = null @@ -43,7 +111,9 @@ class PackageManagersTest { @Test fun hasGrantPermission_requestedPermissionsIsNull_returnFalse() { - fakePackageManagerWrapper.fakePackageInfo = PackageInfo() + fakePackageManagerWrapper.fakePackageInfo = PackageInfo().apply { + requestedPermissions = null + } val hasGrantPermission = with(packageManagersImpl) { APP.hasGrantPermission(PERMISSION_A) @@ -94,18 +164,8 @@ class PackageManagersTest { assertThat(hasGrantPermission).isTrue() } - private inner class FakePackageManagerWrapper : PackageManagerWrapper { - var fakePackageInfo: PackageInfo? = null - - override fun getPackageInfoAsUserCached( - packageName: String, - flags: Long, - userId: Int, - ): PackageInfo? = fakePackageInfo - } - private companion object { - const val PACKAGE_NAME = "packageName" + const val PACKAGE_NAME = "package.name" const val PERMISSION_A = "permission.A" const val PERMISSION_B = "permission.B" const val UID = 123 @@ -115,3 +175,10 @@ class PackageManagersTest { } } } + +private class FakePackageManagerWrapper : PackageManagerWrapper { + var fakePackageInfo: PackageInfo? = null + + override fun getPackageInfoAsUserCached(packageName: String, flags: Long, userId: Int) = + fakePackageInfo +}