Refactor TogglePermissionAppInfoPageProvider

Also add unit tests.

Bug: 260660819
Test: Unit test
Test: Manually with Settings
Change-Id: Ifb6844f4127f07ea5d211d68806e683144310589
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
index a618c3d..ae362c8 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -74,6 +74,8 @@
     fun restrictedModeState(): State<RestrictedMode?>
 }
 
+typealias RestrictionsProviderFactory = (Context, Restrictions) -> RestrictionsProvider
+
 internal class RestrictionsProviderImpl(
     private val context: Context,
     private val restrictions: Restrictions,
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
index 8b19c5b..0b45da6 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
@@ -16,11 +16,12 @@
 
 package com.android.settingslib.spaprivileged.template.app
 
+import android.content.pm.PackageInfo
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 import com.android.settingslib.spa.widget.ui.Footer
-import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 
 @Composable
 fun AppInfoPage(
@@ -28,18 +29,16 @@
     packageName: String,
     userId: Int,
     footerText: String,
-    content: @Composable () -> Unit,
+    packageManagers: IPackageManagers,
+    content: @Composable PackageInfo.() -> Unit,
 ) {
+    val packageInfo = remember(packageName, userId) {
+        packageManagers.getPackageInfoAsUser(packageName, userId)
+    } ?: return
     RegularScaffold(title = title) {
-        val appInfoProvider = remember {
-            PackageManagers.getPackageInfoAsUser(packageName, userId)?.let { packageInfo ->
-                AppInfoProvider(packageInfo)
-            }
-        } ?: return@RegularScaffold
+        remember(packageInfo) { AppInfoProvider(packageInfo) }.AppInfo(displayVersion = true)
 
-        appInfoProvider.AppInfo(displayVersion = true)
-
-        content()
+        packageInfo.content()
 
         Footer(footerText)
     }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
index 8287693..5ae5ada 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.os.Bundle
+import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.State
@@ -38,23 +39,15 @@
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
 import com.android.settingslib.spaprivileged.model.app.toRoute
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
 import kotlinx.coroutines.Dispatchers
 
-private const val ENTRY_NAME = "AllowControl"
-private const val PERMISSION = "permission"
-private const val PACKAGE_NAME = "rt_packageName"
-private const val USER_ID = "rt_userId"
-private const val PAGE_NAME = "TogglePermissionAppInfoPage"
-private val PAGE_PARAMETER = listOf(
-    navArgument(PERMISSION) { type = NavType.StringType },
-    navArgument(PACKAGE_NAME) { type = NavType.StringType },
-    navArgument(USER_ID) { type = NavType.IntType },
-)
-
 internal class TogglePermissionAppInfoPageProvider(
     private val appListTemplate: TogglePermissionAppListTemplate,
 ) : SettingsPageProvider {
@@ -64,11 +57,7 @@
 
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
-        val entryList = mutableListOf<SettingsEntry>()
-        entryList.add(
-            SettingsEntryBuilder.create(ENTRY_NAME, owner).build()
-        )
-        return entryList
+        return listOf(SettingsEntryBuilder.create("AllowControl", owner).build())
     }
 
     @Composable
@@ -76,11 +65,22 @@
         val permissionType = arguments?.getString(PERMISSION)!!
         val packageName = arguments.getString(PACKAGE_NAME)!!
         val userId = arguments.getInt(USER_ID)
-        val listModel = appListTemplate.rememberModel(permissionType)
-        TogglePermissionAppInfoPage(listModel, packageName, userId)
+        appListTemplate.rememberModel(permissionType)
+            .TogglePermissionAppInfoPage(packageName, userId)
     }
 
     companion object {
+        private const val PAGE_NAME = "TogglePermissionAppInfoPage"
+        private const val PERMISSION = "permission"
+        private const val PACKAGE_NAME = "rt_packageName"
+        private const val USER_ID = "rt_userId"
+
+        private val PAGE_PARAMETER = listOf(
+            navArgument(PERMISSION) { type = NavType.StringType },
+            navArgument(PACKAGE_NAME) { type = NavType.StringType },
+            navArgument(USER_ID) { type = NavType.IntType },
+        )
+
         @Composable
         fun navigator(permissionType: String, app: ApplicationInfo) =
             navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
@@ -116,43 +116,36 @@
     }
 }
 
+@VisibleForTesting
 @Composable
-private fun TogglePermissionAppInfoPage(
-    listModel: TogglePermissionAppListModel<out AppRecord>,
+internal fun TogglePermissionAppListModel<out AppRecord>.TogglePermissionAppInfoPage(
     packageName: String,
     userId: Int,
+    packageManagers: IPackageManagers = PackageManagers,
+    restrictionsProviderFactory: RestrictionsProviderFactory = ::RestrictionsProviderImpl,
 ) {
     AppInfoPage(
-        title = stringResource(listModel.pageTitleResId),
+        title = stringResource(pageTitleResId),
         packageName = packageName,
         userId = userId,
-        footerText = stringResource(listModel.footerResId),
+        footerText = stringResource(footerResId),
+        packageManagers = packageManagers,
     ) {
-        val model = createSwitchModel(listModel, packageName, userId) ?: return@AppInfoPage
-        LaunchedEffect(model, Dispatchers.Default) {
-            model.initState()
-        }
-        RestrictedSwitchPreference(model, Restrictions(userId, listModel.switchRestrictionKeys))
+        val model = createSwitchModel(applicationInfo)
+        val restrictions = Restrictions(userId, switchRestrictionKeys)
+        RestrictedSwitchPreference(model, restrictions, restrictionsProviderFactory)
     }
 }
 
 @Composable
-private fun <T : AppRecord> createSwitchModel(
-    listModel: TogglePermissionAppListModel<T>,
-    packageName: String,
-    userId: Int,
-): TogglePermissionSwitchModel<T>? {
-    val record = remember {
-        PackageManagers.getApplicationInfoAsUser(packageName, userId)?.let { app ->
-            listModel.transformItem(app)
-        }
-    } ?: return null
-
+private fun <T : AppRecord> TogglePermissionAppListModel<T>.createSwitchModel(
+    app: ApplicationInfo,
+): TogglePermissionSwitchModel<T> {
     val context = LocalContext.current
-    val isAllowed = listModel.isAllowed(record)
-    return remember {
-        TogglePermissionSwitchModel(context, listModel, record, isAllowed)
-    }
+    val record = remember(app) { transformItem(app) }
+    val isAllowed = isAllowed(record)
+    return remember(record) { TogglePermissionSwitchModel(context, this, record, isAllowed) }
+        .also { model -> LaunchedEffect(model, Dispatchers.IO) { model.initState() } }
 }
 
 private class TogglePermissionSwitchModel<T : AppRecord>(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
index a003da8..b08b6df 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
@@ -38,19 +38,14 @@
 import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
-import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 
 @Composable
-fun RestrictedSwitchPreference(model: SwitchPreferenceModel, restrictions: Restrictions) {
-    RestrictedSwitchPreferenceImpl(model, restrictions, ::RestrictionsProviderImpl)
-}
-
-@Composable
-internal fun RestrictedSwitchPreferenceImpl(
+fun RestrictedSwitchPreference(
     model: SwitchPreferenceModel,
     restrictions: Restrictions,
-    restrictionsProviderFactory: (Context, Restrictions) -> RestrictionsProvider,
+    restrictionsProviderFactory: RestrictionsProviderFactory = ::RestrictionsProviderImpl,
 ) {
     if (restrictions.keys.isEmpty()) {
         SwitchPreference(model)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
new file mode 100644
index 0000000..ecad08a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.template.app
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
+import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListModel
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListProvider
+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.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+class TogglePermissionAppInfoPageTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var packageManagers: IPackageManagers
+
+    private val fakeRestrictionsProvider = FakeRestrictionsProvider()
+
+    private val appListTemplate =
+        TogglePermissionAppListTemplate(listOf(TestTogglePermissionAppListProvider))
+
+    private val appInfoPageProvider = TogglePermissionAppInfoPageProvider(appListTemplate)
+
+    @Before
+    fun setUp() {
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+        whenever(packageManagers.getPackageInfoAsUser(PACKAGE_NAME, USER_ID))
+            .thenReturn(PACKAGE_INFO)
+    }
+
+    @Test
+    fun buildEntry() {
+        val entryList = appInfoPageProvider.buildEntry(null)
+
+        assertThat(entryList).hasSize(1)
+        assertThat(entryList[0].displayName).isEqualTo("AllowControl")
+    }
+
+    @Test
+    fun title_isDisplayed() {
+        val listModel = TestTogglePermissionAppListModel()
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.pageTitleResId))
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun whenAllowed_switchIsOn() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = true)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsOn()
+    }
+
+    @Test
+    fun whenNotAllowed_switchIsOff() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = false)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsOff()
+    }
+
+    @Test
+    fun whenNotChangeable_switchNotEnabled() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = false)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsDisplayed()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun footer_isDisplayed() {
+        val listModel = TestTogglePermissionAppListModel()
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.footerResId))
+            .assertIsDisplayed()
+    }
+
+    private fun setTogglePermissionAppInfoPage(listModel: TestTogglePermissionAppListModel) {
+        composeTestRule.setContent {
+            listModel.TogglePermissionAppInfoPage(
+                packageName = PACKAGE_NAME,
+                userId = USER_ID,
+                packageManagers = packageManagers,
+                restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
+            )
+        }
+    }
+
+    private companion object {
+        const val USER_ID = 0
+        const val PACKAGE_NAME = "package.name"
+        val APP = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+        }
+        val PACKAGE_INFO = PackageInfo().apply {
+            packageName = PACKAGE_NAME
+            applicationInfo = APP
+        }
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
index 2d169e0..1818f2d 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
@@ -25,7 +25,7 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spaprivileged.test.R
-import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListModel
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListProvider
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -70,8 +70,3 @@
         assertThat(createPageProviders.any { it is TogglePermissionAppInfoPageProvider }).isTrue()
     }
 }
-
-private object TestTogglePermissionAppListProvider : TogglePermissionAppListProvider {
-    override val permissionType = "test.PERMISSION"
-    override fun createModel(context: Context) = TestTogglePermissionAppListModel()
-}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
index 7f57025..a13c483 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
@@ -142,7 +142,7 @@
 
     private fun setContent(restrictions: Restrictions) {
         composeTestRule.setContent {
-            RestrictedSwitchPreferenceImpl(switchPreferenceModel, restrictions) { _, _ ->
+            RestrictedSwitchPreference(switchPreferenceModel, restrictions) { _, _ ->
                 fakeRestrictionsProvider
             }
         }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
index 64bc11f..b13fbb3 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
@@ -23,7 +23,10 @@
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
 import kotlinx.coroutines.flow.Flow
 
-class TestTogglePermissionAppListModel : TogglePermissionAppListModel<TestAppRecord> {
+class TestTogglePermissionAppListModel(
+    private val isAllowed: Boolean? = null,
+    private val isChangeable: Boolean = false,
+) : TogglePermissionAppListModel<TestAppRecord> {
     override val pageTitleResId = R.string.test_permission_title
     override val switchTitleResId = R.string.test_permission_switch_title
     override val footerResId = R.string.test_permission_footer
@@ -34,9 +37,9 @@
         recordListFlow
 
     @Composable
-    override fun isAllowed(record: TestAppRecord) = stateOf(null)
+    override fun isAllowed(record: TestAppRecord) = stateOf(isAllowed)
 
-    override fun isChangeable(record: TestAppRecord) = false
+    override fun isChangeable(record: TestAppRecord) = isChangeable
 
     override fun setAllowed(record: TestAppRecord, newAllowed: Boolean) {}
 }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
new file mode 100644
index 0000000..354bbf5
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.tests.testutils
+
+import android.content.Context
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object TestTogglePermissionAppListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "test.PERMISSION"
+    override fun createModel(context: Context) = TestTogglePermissionAppListModel()
+}