Added Background install control UI code.

Change-Id: I1b629fdc04d1df1b08998c9aaae3df3446fab3fe
Bug: 238451991
Test: Manually with settings, atest
This commit is contained in:
George Chan
2022-12-01 18:19:40 +00:00
parent d0c68b3807
commit d18b422c51
5 changed files with 614 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
/*
* 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.settings.spa.app.backgroundinstall
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.IBackgroundInstallControlService
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ParceledListSlice
import android.net.Uri
import android.os.UserHandle
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
import com.android.settingslib.spa.testutils.any
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.google.common.truth.Truth
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
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@RunWith(AndroidJUnit4::class)
class BackgroundInstalledAppsPageProviderTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
private val context: Context = ApplicationProvider.getApplicationContext()
@Mock
private lateinit var mockContext: Context
@Mock
private lateinit var mockPackageManager: PackageManager
@Mock
private lateinit var mockBackgroundInstallControlService: IBackgroundInstallControlService
private var packageInfoFlagsCaptor =
ArgumentCaptor.forClass(PackageManager.PackageInfoFlags::class.java)
private var intentCaptor =
ArgumentCaptor.forClass(Intent::class.java)
private val fakeNavControllerWrapper = FakeNavControllerWrapper()
@Before
fun setup() {
Mockito.`when`(mockContext.packageManager).thenReturn(mockPackageManager)
}
@Test
fun allAppListPageProvider_name() {
Truth.assertThat(BackgroundInstalledAppsPageProvider.name)
.isEqualTo(EXPECTED_PROVIDER_NAME)
}
@Test
fun injectEntry_title() {
Mockito.`when`(mockBackgroundInstallControlService
.getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
.thenReturn(ParceledListSlice(listOf()))
setInjectEntry(false)
composeTestRule.onNodeWithText(
context.getString(R.string.background_install_title)).assertIsDisplayed()
}
@Test
fun injectEntry_title_disabled() {
setInjectEntry(true)
composeTestRule.onNodeWithText(
context.getString(R.string.background_install_title)).assertDoesNotExist()
}
@Test
fun injectEntry_summary() {
Mockito.`when`(mockBackgroundInstallControlService
.getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
.thenReturn(ParceledListSlice(listOf()))
setInjectEntry(false)
composeTestRule.onNodeWithText("0 apps").assertIsDisplayed()
}
@Test
fun injectEntry_summary_disabled() {
setInjectEntry(true)
composeTestRule.onNodeWithText("0 apps").assertDoesNotExist()
}
@Test
fun injectEntry_onClick_navigate() {
Mockito.`when`(mockBackgroundInstallControlService
.getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
.thenReturn(ParceledListSlice(listOf()))
setInjectEntry(false)
composeTestRule.onNodeWithText(
context.getString(R.string.background_install_title)).performClick()
Truth.assertThat(fakeNavControllerWrapper.navigateCalledWith)
.isEqualTo(EXPECTED_PROVIDER_NAME)
}
private fun setInjectEntry(disableFeature: Boolean = false) {
composeTestRule.setContent {
fakeNavControllerWrapper.Wrapper {
BackgroundInstalledAppsPageProvider
.setBackgroundInstallControlService(mockBackgroundInstallControlService)
.setDisableFeature(disableFeature)
.buildInjectEntry().build().UiLayout()
}
}
}
@Test
fun title_displayed() {
composeTestRule.setContent {
BackgroundInstalledAppList()
}
composeTestRule.onNodeWithText(
context.getString(R.string.background_install_title)).assertIsDisplayed()
}
@Test
fun item_labelDisplayed() {
setItemContent()
composeTestRule.onNodeWithText(TEST_LABEL).assertIsDisplayed()
}
@Test
fun item_onClick_navigate() {
setItemContent()
composeTestRule.onNodeWithText(TEST_LABEL).performClick()
Truth.assertThat(fakeNavControllerWrapper.navigateCalledWith)
.isEqualTo("AppInfoSettings/package.name/0")
}
@Suppress
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun startUninstallActivity_success() = runTest {
val expectedPackageUri = Uri.parse("package:package.name")
val mockUserHandle = UserHandle(0)
Mockito.`when`(mockContext.user).thenReturn(mockUserHandle)
Mockito.`when`(mockContext.startActivityAsUser(
intentCaptor.capture(),
eq(mockUserHandle)
)).then { }
startUninstallActivity(mockContext, TEST_PACKAGE_NAME)
Truth.assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
Truth.assertThat(intentCaptor.value.data).isEqualTo(expectedPackageUri)
Truth.assertThat(intentCaptor.value.extras?.getBoolean(Intent.EXTRA_UNINSTALL_ALL_USERS))
.isEqualTo(false)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleOne() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
val actualGroupTitle = listModel
.getGroupTitle(0,
BackgroundInstalledAppListWithGroupingAppRecord(
APP,
System.currentTimeMillis()
))
Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed in the last 6 months")
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleTwo() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(context)
val actualGroupTitle = listModel
.getGroupTitle(0,
BackgroundInstalledAppListWithGroupingAppRecord(
APP,
0L
))
Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed more than 6 months ago")
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_transform() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
Mockito.`when`(mockPackageManager.getPackageInfoAsUser(
eq(TEST_PACKAGE_NAME),
packageInfoFlagsCaptor.capture(),
eq(TEST_USER_ID))
)
.thenReturn(PACKAGE_INFO)
val recordListFlow = listModel.transform(flowOf(TEST_USER_ID), flowOf(listOf(APP)))
val recordList = recordListFlow.first()
Truth.assertThat(recordList).hasSize(1)
Truth.assertThat(recordList[0].app).isSameInstanceAs(APP)
Truth.assertThat(packageInfoFlagsCaptor.value.value).isEqualTo(EXPECTED_PACKAGE_INFO_FLAG)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_filter() = runTest {
val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
listModel.setBackgroundInstallControlService(mockBackgroundInstallControlService)
Mockito.`when`(mockBackgroundInstallControlService.getBackgroundInstalledPackages(
PackageManager.MATCH_ALL.toLong(),
TEST_USER_ID
)).thenReturn(ParceledListSlice(listOf(PACKAGE_INFO)))
val recordListFlow = listModel.filter(
flowOf(TEST_USER_ID),
0,
flowOf(listOf(APP_RECORD_WITH_PACKAGE_MATCH, APP_RECORD_WITHOUT_PACKAGE_MATCH))
)
val recordList = recordListFlow.first()
Truth.assertThat(recordList).hasSize(1)
Truth.assertThat(recordList[0]).isSameInstanceAs(APP_RECORD_WITH_PACKAGE_MATCH)
}
private fun setItemContent() {
composeTestRule.setContent {
BackgroundInstalledAppList {
fakeNavControllerWrapper.Wrapper {
with(BackgroundInstalledAppsWithGroupingListModel(context)) {
AppListItemModel(
record = BackgroundInstalledAppListWithGroupingAppRecord(
app = APP,
dateOfInstall = TEST_FIRST_INSTALL_TIME),
label = TEST_LABEL,
summary = stateOf(TEST_SUMMARY),
).AppItem()
}
}
}
}
}
private companion object {
private const val TEST_USER_ID = 0
private const val TEST_PACKAGE_NAME = "package.name"
private const val TEST_NO_MATCH_PACKAGE_NAME = "no.match"
private const val TEST_LABEL = "Label"
private const val TEST_SUMMARY = "Summary"
private const val TEST_FIRST_INSTALL_TIME = 0L
private const val EXPECTED_PROVIDER_NAME = "BackgroundInstalledAppsPage"
private const val EXPECTED_PACKAGE_INFO_FLAG = 0L
val APP = ApplicationInfo().apply {
packageName = TEST_PACKAGE_NAME
}
val APP_NO_RECORD = ApplicationInfo().apply {
packageName = TEST_NO_MATCH_PACKAGE_NAME
}
val APP_RECORD_WITH_PACKAGE_MATCH = BackgroundInstalledAppListWithGroupingAppRecord(
APP,
TEST_FIRST_INSTALL_TIME
)
val APP_RECORD_WITHOUT_PACKAGE_MATCH = BackgroundInstalledAppListWithGroupingAppRecord(
APP_NO_RECORD,
TEST_FIRST_INSTALL_TIME
)
val PACKAGE_INFO = PackageInfo().apply {
packageName = TEST_PACKAGE_NAME
applicationInfo = APP
firstInstallTime = TEST_FIRST_INSTALL_TIME
}
}
}