Merge "Move AppItem into AppListModel"

This commit is contained in:
Chaohui Wang
2022-12-16 07:27:03 +00:00
committed by Android (Google) Code Review
11 changed files with 207 additions and 94 deletions

View File

@@ -4,6 +4,8 @@ import android.content.pm.ApplicationInfo
import android.icu.text.CollationKey
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import com.android.settingslib.spaprivileged.template.app.AppListItem
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import kotlinx.coroutines.flow.Flow
data class AppEntry<T : AppRecord>(
@@ -69,4 +71,9 @@ interface AppListModel<T : AppRecord> {
*/
@Composable
fun getSummary(option: Int, record: T): State<String>? = null
@Composable
fun AppListItemModel<T>.AppItem() {
AppListItem {}
}
}

View File

@@ -60,7 +60,6 @@ data class AppListInput<T : AppRecord>(
val listModel: AppListModel<T>,
val state: AppListState,
val header: @Composable () -> Unit,
val appItem: @Composable AppListItemModel<T>.() -> Unit,
val bottomPadding: Dp,
)
@@ -80,15 +79,13 @@ internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
) {
LogCompositions(TAG, config.userId.toString())
val appListData = appListDataSupplier()
AppListWidget(appListData, listModel, header, appItem, bottomPadding)
listModel.AppListWidget(appListData, header, bottomPadding)
}
@Composable
private fun <T : AppRecord> AppListWidget(
private fun <T : AppRecord> AppListModel<T>.AppListWidget(
appListData: State<AppListData<T>?>,
listModel: AppListModel<T>,
header: @Composable () -> Unit,
appItem: @Composable (itemState: AppListItemModel<T>) -> Unit,
bottomPadding: Dp,
) {
val timeMeasurer = rememberTimeMeasurer(TAG)
@@ -108,14 +105,14 @@ private fun <T : AppRecord> AppListWidget(
}
items(count = list.size, key = { option to list[it].record.app.packageName }) {
remember(list) { listModel.getGroupTitleIfFirst(option, list, it) }
remember(list) { getGroupTitleIfFirst(option, list, it) }
?.let { group -> CategoryTitle(title = group) }
val appEntry = list[it]
val summary = listModel.getSummary(option, appEntry.record) ?: "".toState()
appItem(remember(appEntry) {
val summary = getSummary(option, appEntry.record) ?: "".toState()
remember(appEntry) {
AppListItemModel(appEntry.record, appEntry.label, summary)
})
}.AppItem()
}
}
}

View File

@@ -48,7 +48,6 @@ fun <T : AppRecord> AppListPage(
moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
header: @Composable () -> Unit = {},
appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
appItem: @Composable AppListItemModel<T>.() -> Unit,
) {
val showSystem = rememberSaveable { mutableStateOf(false) }
SearchScaffold(
@@ -77,7 +76,6 @@ fun <T : AppRecord> AppListPage(
searchQuery = searchQuery,
),
header = header,
appItem = appItem,
bottomPadding = bottomPadding,
)
appList(appListInput)

View File

@@ -85,27 +85,6 @@ internal class TogglePermissionAppInfoPageProvider(
fun navigator(permissionType: String, app: ApplicationInfo) =
navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
@Composable
fun <T : AppRecord> EntryItem(
permissionType: String,
app: ApplicationInfo,
listModel: TogglePermissionAppListModel<T>,
) {
val context = LocalContext.current
val internalListModel = remember {
TogglePermissionInternalAppListModel(context, listModel, ::RestrictionsProviderImpl)
}
val record = remember { listModel.transformItem(app) }
if (!remember { listModel.isChangeable(record) }) return
Preference(
object : PreferenceModel {
override val title = stringResource(listModel.pageTitleResId)
override val summary = internalListModel.getSummary(record)
override val onClick = navigator(permissionType, app)
}
)
}
fun buildPageData(permissionType: String): SettingsPage {
return SettingsPage.create(
name = PAGE_NAME,
@@ -116,6 +95,32 @@ internal class TogglePermissionAppInfoPageProvider(
}
}
@Composable
internal fun <T : AppRecord> TogglePermissionAppListModel<T>.TogglePermissionAppInfoPageEntryItem(
permissionType: String,
app: ApplicationInfo,
) {
val record = remember { transformItem(app) }
if (!remember { isChangeable(record) }) return
val context = LocalContext.current
val internalListModel = remember {
TogglePermissionInternalAppListModel(
context = context,
permissionType = permissionType,
listModel = this,
restrictionsProviderFactory = ::RestrictionsProviderImpl,
)
}
Preference(
object : PreferenceModel {
override val title = stringResource(pageTitleResId)
override val summary = internalListModel.getSummary(record)
override val onClick =
TogglePermissionAppInfoPageProvider.navigator(permissionType, app)
}
)
}
@VisibleForTesting
@Composable
internal fun TogglePermissionAppListModel<out AppRecord>.TogglePermissionAppInfoPage(

View File

@@ -96,7 +96,7 @@ interface TogglePermissionAppListProvider {
@Composable
fun InfoPageEntryItem(app: ApplicationInfo) {
val listModel = rememberContext(::createModel)
TogglePermissionAppInfoPageProvider.EntryItem(permissionType, app, listModel)
listModel.TogglePermissionAppInfoPageEntryItem(permissionType, app)
}
}

View File

@@ -117,25 +117,23 @@ internal fun <T : AppRecord> TogglePermissionAppListModel<T>.TogglePermissionApp
appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
) {
val context = LocalContext.current
val internalListModel = remember {
TogglePermissionInternalAppListModel(context, this, restrictionsProviderFactory)
}
AppListPage(
title = stringResource(pageTitleResId),
listModel = internalListModel,
appList = appList,
) {
AppListItem(
onClick = TogglePermissionAppInfoPageProvider.navigator(
listModel = remember {
TogglePermissionInternalAppListModel(
context = context,
permissionType = permissionType,
app = record.app,
),
)
}
listModel = this,
restrictionsProviderFactory = restrictionsProviderFactory,
)
},
appList = appList,
)
}
internal class TogglePermissionInternalAppListModel<T : AppRecord>(
private val context: Context,
private val permissionType: String,
private val listModel: TogglePermissionAppListModel<T>,
private val restrictionsProviderFactory: RestrictionsProviderFactory,
) : AppListModel<T> {
@@ -178,4 +176,14 @@ internal class TogglePermissionInternalAppListModel<T : AppRecord>(
null -> context.getString(R.string.summary_placeholder)
}
}
@Composable
override fun AppListItemModel<T>.AppItem() {
AppListItem(
onClick = TogglePermissionAppInfoPageProvider.navigator(
permissionType = permissionType,
app = record.app,
),
)
}
}

View File

@@ -122,7 +122,6 @@ class AppListPageTest {
title = TITLE,
listModel = TestAppListModel(options),
header = header,
appItem = { AppListItem {} },
appList = { appListState.value = this },
)
}

View File

@@ -99,7 +99,6 @@ class AppListTest {
searchQuery = "".toState(),
),
header = header,
appItem = { AppListItem {} },
bottomPadding = 0.dp,
)
appListInput.AppListImpl { stateOf(AppListData(appEntries, option = 0)) }

View File

@@ -20,13 +20,18 @@ 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.assertIsNotDisplayed
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.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
@@ -55,6 +60,8 @@ class TogglePermissionAppInfoPageTest {
@Mock
private lateinit var packageManagers: IPackageManagers
private val fakeNavControllerWrapper = FakeNavControllerWrapper()
private val fakeRestrictionsProvider = FakeRestrictionsProvider()
private val appListTemplate =
@@ -78,7 +85,58 @@ class TogglePermissionAppInfoPageTest {
}
@Test
fun title_isDisplayed() {
fun entryItem_whenNotChangeable_notDisplayed() {
val listModel = TestTogglePermissionAppListModel(isChangeable = false)
setEntryItem(listModel)
composeTestRule.onRoot().assertIsNotDisplayed()
}
@Test
fun entryItem_whenChangeable_titleDisplayed() {
val listModel = TestTogglePermissionAppListModel(isChangeable = true)
setEntryItem(listModel)
composeTestRule.onNodeWithText(context.getString(listModel.pageTitleResId))
.assertIsDisplayed()
}
@Test
fun entryItem_whenAllowed_summaryIsAllowed() {
val listModel = TestTogglePermissionAppListModel(isAllowed = true, isChangeable = true)
setEntryItem(listModel)
composeTestRule.onNodeWithText(context.getString(R.string.app_permission_summary_allowed))
.assertIsDisplayed()
}
@Test
fun entryItem_whenNotAllowed_summaryIsNotAllowed() {
val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = true)
setEntryItem(listModel)
composeTestRule.onNodeWithText(
context.getString(R.string.app_permission_summary_not_allowed)
).assertIsDisplayed()
}
@Test
fun entryItem_onClick() {
val listModel = TestTogglePermissionAppListModel(isChangeable = true)
setEntryItem(listModel)
composeTestRule.onRoot().performClick()
assertThat(fakeNavControllerWrapper.navigateCalledWith)
.isEqualTo("TogglePermissionAppInfoPage/test.PERMISSION/package.name/0")
}
@Test
fun infoPage_title_isDisplayed() {
val listModel = TestTogglePermissionAppListModel()
setTogglePermissionAppInfoPage(listModel)
@@ -88,7 +146,7 @@ class TogglePermissionAppInfoPageTest {
}
@Test
fun whenAllowed_switchIsOn() {
fun infoPage_whenAllowed_switchIsOn() {
val listModel = TestTogglePermissionAppListModel(isAllowed = true)
setTogglePermissionAppInfoPage(listModel)
@@ -98,7 +156,7 @@ class TogglePermissionAppInfoPageTest {
}
@Test
fun whenNotAllowed_switchIsOff() {
fun infoPage_whenNotAllowed_switchIsOff() {
val listModel = TestTogglePermissionAppListModel(isAllowed = false)
setTogglePermissionAppInfoPage(listModel)
@@ -108,7 +166,31 @@ class TogglePermissionAppInfoPageTest {
}
@Test
fun whenNotChangeable_switchNotEnabled() {
fun infoPage_whenChangeableAndClick() {
val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = true)
setTogglePermissionAppInfoPage(listModel)
composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
.performClick()
composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
.assertIsOn()
}
@Test
fun infoPage_whenNotChangeableAndClick() {
val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = false)
setTogglePermissionAppInfoPage(listModel)
composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
.performClick()
composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
.assertIsOff()
}
@Test
fun infoPage_whenNotChangeable_switchNotEnabled() {
val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = false)
setTogglePermissionAppInfoPage(listModel)
@@ -119,7 +201,7 @@ class TogglePermissionAppInfoPageTest {
}
@Test
fun footer_isDisplayed() {
fun infoPage_footer_isDisplayed() {
val listModel = TestTogglePermissionAppListModel()
setTogglePermissionAppInfoPage(listModel)
@@ -128,6 +210,17 @@ class TogglePermissionAppInfoPageTest {
.assertIsDisplayed()
}
private fun setEntryItem(listModel: TestTogglePermissionAppListModel) {
composeTestRule.setContent {
fakeNavControllerWrapper.Wrapper {
listModel.TogglePermissionAppInfoPageEntryItem(
permissionType = PERMISSION_TYPE,
app = APP,
)
}
}
}
private fun setTogglePermissionAppInfoPage(listModel: TestTogglePermissionAppListModel) {
composeTestRule.setContent {
listModel.TogglePermissionAppInfoPage(
@@ -140,6 +233,7 @@ class TogglePermissionAppInfoPageTest {
}
private companion object {
const val PERMISSION_TYPE = "test.PERMISSION"
const val USER_ID = 0
const val PACKAGE_NAME = "package.name"
val APP = ApplicationInfo().apply {

View File

@@ -51,50 +51,49 @@ class TogglePermissionAppListPageTest {
private val fakeRestrictionsProvider = FakeRestrictionsProvider()
@Test
fun internalAppListModel_whenAllowed() {
fun pageTitle() {
val listModel = TestTogglePermissionAppListModel()
composeTestRule.setContent {
listModel.TogglePermissionAppList(
permissionType = PERMISSION_TYPE,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
appList = {},
)
}
composeTestRule.onNodeWithText(context.getString(listModel.pageTitleResId))
.assertIsDisplayed()
}
@Test
fun summary_whenAllowed() {
fakeRestrictionsProvider.restrictedMode = NoRestricted
val listModel = TestTogglePermissionAppListModel(isAllowed = true)
val internalAppListModel = TogglePermissionInternalAppListModel(
context = context,
listModel = listModel,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
)
val summaryState = getSummary(internalAppListModel)
val summaryState = getSummary(listModel)
assertThat(summaryState.value).isEqualTo(
context.getString(R.string.app_permission_summary_allowed)
)
assertThat(summaryState.value)
.isEqualTo(context.getString(R.string.app_permission_summary_allowed))
}
@Test
fun internalAppListModel_whenNotAllowed() {
fun summary_whenNotAllowed() {
fakeRestrictionsProvider.restrictedMode = NoRestricted
val listModel = TestTogglePermissionAppListModel(isAllowed = false)
val internalAppListModel = TogglePermissionInternalAppListModel(
context = context,
listModel = listModel,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
)
val summaryState = getSummary(internalAppListModel)
val summaryState = getSummary(listModel)
assertThat(summaryState.value).isEqualTo(
context.getString(R.string.app_permission_summary_not_allowed)
)
assertThat(summaryState.value)
.isEqualTo(context.getString(R.string.app_permission_summary_not_allowed))
}
@Test
fun internalAppListModel_whenComputingAllowed() {
fun summary_whenComputingAllowed() {
fakeRestrictionsProvider.restrictedMode = NoRestricted
val listModel = TestTogglePermissionAppListModel(isAllowed = null)
val internalAppListModel = TogglePermissionInternalAppListModel(
context = context,
listModel = listModel,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
)
val summaryState = getSummary(internalAppListModel)
val summaryState = getSummary(listModel)
assertThat(summaryState.value).isEqualTo(
context.getString(R.string.summary_placeholder)
@@ -105,16 +104,13 @@ class TogglePermissionAppListPageTest {
fun appListItem_onClick_navigate() {
val listModel = TestTogglePermissionAppListModel()
composeTestRule.setContent {
listModel.TogglePermissionAppList(
permissionType = PERMISSION_TYPE,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
) {
fakeNavControllerWrapper.Wrapper {
fakeNavControllerWrapper.Wrapper {
with(createInternalAppListModel(listModel)) {
AppListItemModel(
record = listModel.transformItem(APP),
label = LABEL,
summary = stateOf(SUMMARY),
).appItem()
).AppItem()
}
}
}
@@ -149,12 +145,18 @@ class TogglePermissionAppListPageTest {
.assertIsDisplayed()
}
private fun getSummary(
internalAppListModel: TogglePermissionInternalAppListModel<TestAppRecord>,
): State<String> {
private fun createInternalAppListModel(listModel: TestTogglePermissionAppListModel) =
TogglePermissionInternalAppListModel(
context = context,
permissionType = PERMISSION_TYPE,
listModel = listModel,
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
)
private fun getSummary(listModel: TestTogglePermissionAppListModel): State<String> {
lateinit var summary: State<String>
composeTestRule.setContent {
summary = internalAppListModel.getSummary(record = TestAppRecord(APP))
summary = createInternalAppListModel(listModel).getSummary(record = TestAppRecord(APP))
}
return summary
}

View File

@@ -18,28 +18,32 @@ package com.android.settingslib.spaprivileged.tests.testutils
import android.content.pm.ApplicationInfo
import androidx.compose.runtime.Composable
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spaprivileged.test.R
import androidx.compose.runtime.mutableStateOf
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
import com.android.settingslib.spaprivileged.test.R
import kotlinx.coroutines.flow.Flow
class TestTogglePermissionAppListModel(
private val isAllowed: Boolean? = null,
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
private val isAllowedState = mutableStateOf(isAllowed)
override fun transformItem(app: ApplicationInfo) = TestAppRecord(app = app)
override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<TestAppRecord>>) =
recordListFlow
@Composable
override fun isAllowed(record: TestAppRecord) = stateOf(isAllowed)
override fun isAllowed(record: TestAppRecord) = isAllowedState
override fun isChangeable(record: TestAppRecord) = isChangeable
override fun setAllowed(record: TestAppRecord, newAllowed: Boolean) {}
override fun setAllowed(record: TestAppRecord, newAllowed: Boolean) {
isAllowedState.value = newAllowed
}
}