Refresh the App Info Settings
When apk upgraded or downgraded. And only close the page when the package is fully removed. Bug: 314562958 Test: manual - on App Info Settings Test: unit test Change-Id: Ifdff714da99e31f9c5f237a0c3342de7a0797ec4
This commit is contained in:
@@ -23,7 +23,9 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.outlined.Report
|
import androidx.compose.material.icons.outlined.Report
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settingslib.RestrictedLockUtils
|
import com.android.settingslib.RestrictedLockUtils
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
|
||||||
@@ -35,6 +37,9 @@ import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
|
|||||||
import com.android.settingslib.spaprivileged.model.app.hasFlag
|
import com.android.settingslib.spaprivileged.model.app.hasFlag
|
||||||
import com.android.settingslib.spaprivileged.model.app.isActiveAdmin
|
import com.android.settingslib.spaprivileged.model.app.isActiveAdmin
|
||||||
import com.android.settingslib.spaprivileged.model.app.userId
|
import com.android.settingslib.spaprivileged.model.app.userId
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
|
||||||
class AppForceStopButton(
|
class AppForceStopButton(
|
||||||
private val packageInfoPresenter: PackageInfoPresenter,
|
private val packageInfoPresenter: PackageInfoPresenter,
|
||||||
@@ -47,9 +52,13 @@ class AppForceStopButton(
|
|||||||
fun getActionButton(app: ApplicationInfo): ActionButton {
|
fun getActionButton(app: ApplicationInfo): ActionButton {
|
||||||
val dialogPresenter = confirmDialogPresenter()
|
val dialogPresenter = confirmDialogPresenter()
|
||||||
return ActionButton(
|
return ActionButton(
|
||||||
text = context.getString(R.string.force_stop),
|
text = stringResource(R.string.force_stop),
|
||||||
imageVector = Icons.Outlined.Report,
|
imageVector = Icons.Outlined.Report,
|
||||||
enabled = isForceStopButtonEnable(app),
|
enabled = remember(app) {
|
||||||
|
flow {
|
||||||
|
emit(isForceStopButtonEnable(app))
|
||||||
|
}.flowOn(Dispatchers.Default)
|
||||||
|
}.collectAsStateWithLifecycle(false).value,
|
||||||
) { onForceStopButtonClicked(app, dialogPresenter) }
|
) { onForceStopButtonClicked(app, dialogPresenter) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.android.settings.flags.Flags
|
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.applications.AppInfoBase
|
import com.android.settings.applications.AppInfoBase
|
||||||
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
|
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
|
||||||
|
import com.android.settings.flags.Flags
|
||||||
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
|
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
|
||||||
import com.android.settings.spa.app.appcompat.UserAspectRatioAppPreference
|
import com.android.settings.spa.app.appcompat.UserAspectRatioAppPreference
|
||||||
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
|
import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
|
||||||
@@ -45,7 +45,6 @@ import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListPro
|
|||||||
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
|
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
|
||||||
import com.android.settings.spa.app.specialaccess.VoiceActivationAppsListProvider
|
import com.android.settings.spa.app.specialaccess.VoiceActivationAppsListProvider
|
||||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
import com.android.settingslib.spa.framework.compose.LifecycleEffect
|
|
||||||
import com.android.settingslib.spa.framework.compose.navigator
|
import com.android.settingslib.spa.framework.compose.navigator
|
||||||
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
||||||
import com.android.settingslib.spa.widget.ui.Category
|
import com.android.settingslib.spa.widget.ui.Category
|
||||||
@@ -75,7 +74,7 @@ object AppInfoSettingsProvider : SettingsPageProvider {
|
|||||||
PackageInfoPresenter(context, packageName, userId, coroutineScope)
|
PackageInfoPresenter(context, packageName, userId, coroutineScope)
|
||||||
}
|
}
|
||||||
AppInfoSettings(packageInfoPresenter)
|
AppInfoSettings(packageInfoPresenter)
|
||||||
packageInfoPresenter.PackageRemoveDetector()
|
packageInfoPresenter.PackageFullyRemovedEffect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -120,8 +119,7 @@ object AppInfoSettingsProvider : SettingsPageProvider {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
||||||
LifecycleEffect(onStart = { packageInfoPresenter.reloadPackageInfo() })
|
val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?:return
|
||||||
val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?: return
|
|
||||||
val app = checkNotNull(packageInfo.applicationInfo)
|
val app = checkNotNull(packageInfo.applicationInfo)
|
||||||
val featureFlags: FeatureFlags = FeatureFlagsImpl()
|
val featureFlags: FeatureFlags = FeatureFlagsImpl()
|
||||||
RegularScaffold(
|
RegularScaffold(
|
||||||
@@ -131,7 +129,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
|||||||
AppInfoSettingsMoreOptions(packageInfoPresenter, app)
|
AppInfoSettingsMoreOptions(packageInfoPresenter, app)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
val appInfoProvider = remember { AppInfoProvider(packageInfo) }
|
val appInfoProvider = remember(packageInfo) { AppInfoProvider(packageInfo) }
|
||||||
|
|
||||||
appInfoProvider.AppInfo()
|
appInfoProvider.AppInfo()
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import androidx.navigation.NavType
|
|||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
import com.android.settingslib.spa.framework.compose.LifecycleEffect
|
|
||||||
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
||||||
import com.android.settingslib.spaprivileged.model.app.toRoute
|
import com.android.settingslib.spaprivileged.model.app.toRoute
|
||||||
import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
|
import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
|
||||||
@@ -54,7 +53,7 @@ object CloneAppInfoSettingsProvider : SettingsPageProvider {
|
|||||||
PackageInfoPresenter(context, packageName, userId, coroutineScope)
|
PackageInfoPresenter(context, packageName, userId, coroutineScope)
|
||||||
}
|
}
|
||||||
CloneAppInfoSettings(packageInfoPresenter)
|
CloneAppInfoSettings(packageInfoPresenter)
|
||||||
packageInfoPresenter.PackageRemoveDetector()
|
packageInfoPresenter.PackageFullyRemovedEffect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -70,7 +69,6 @@ object CloneAppInfoSettingsProvider : SettingsPageProvider {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CloneAppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
private fun CloneAppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
|
||||||
LifecycleEffect(onStart = { packageInfoPresenter.reloadPackageInfo() })
|
|
||||||
val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?: return
|
val packageInfo = packageInfoPresenter.flow.collectAsStateWithLifecycle().value ?: return
|
||||||
RegularScaffold(
|
RegularScaffold(
|
||||||
title = stringResource(R.string.application_info_label),
|
title = stringResource(R.string.application_info_label),
|
||||||
|
|||||||
@@ -32,14 +32,20 @@ import com.android.settings.spa.app.startUninstallActivity
|
|||||||
import com.android.settingslib.spa.framework.compose.LocalNavController
|
import com.android.settingslib.spa.framework.compose.LocalNavController
|
||||||
import com.android.settingslib.spaprivileged.framework.common.activityManager
|
import com.android.settingslib.spaprivileged.framework.common.activityManager
|
||||||
import com.android.settingslib.spaprivileged.framework.common.asUser
|
import com.android.settingslib.spaprivileged.framework.common.asUser
|
||||||
|
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverAsUserFlow
|
||||||
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
|
import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
|
||||||
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
|
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
|
||||||
import com.android.settingslib.spaprivileged.model.app.PackageManagers
|
import com.android.settingslib.spaprivileged.model.app.PackageManagers
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
|
||||||
private const val TAG = "PackageInfoPresenter"
|
private const val TAG = "PackageInfoPresenter"
|
||||||
|
|
||||||
@@ -58,34 +64,33 @@ class PackageInfoPresenter(
|
|||||||
private val userHandle = UserHandle.of(userId)
|
private val userHandle = UserHandle.of(userId)
|
||||||
val userContext by lazy { context.asUser(userHandle) }
|
val userContext by lazy { context.asUser(userHandle) }
|
||||||
val userPackageManager: PackageManager by lazy { userContext.packageManager }
|
val userPackageManager: PackageManager by lazy { userContext.packageManager }
|
||||||
private val _flow: MutableStateFlow<PackageInfo?> = MutableStateFlow(null)
|
|
||||||
|
|
||||||
val flow: StateFlow<PackageInfo?> = _flow
|
val flow: StateFlow<PackageInfo?> = merge(
|
||||||
|
flowOf(null), // kick an initial value
|
||||||
fun reloadPackageInfo() {
|
context.broadcastReceiverAsUserFlow(
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
intentFilter = IntentFilter().apply {
|
||||||
_flow.value = getPackageInfo()
|
addAction(Intent.ACTION_PACKAGE_CHANGED)
|
||||||
}
|
addAction(Intent.ACTION_PACKAGE_REPLACED)
|
||||||
}
|
addAction(Intent.ACTION_PACKAGE_RESTARTED)
|
||||||
|
addDataScheme("package")
|
||||||
|
},
|
||||||
|
userHandle = userHandle,
|
||||||
|
),
|
||||||
|
).map { getPackageInfo() }
|
||||||
|
.stateIn(coroutineScope + Dispatchers.Default, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects the package removed event.
|
* Detects the package fully removed event, and close the current page.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun PackageRemoveDetector() {
|
fun PackageFullyRemovedEffect() {
|
||||||
val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_REMOVED).apply {
|
val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_FULLY_REMOVED).apply {
|
||||||
addDataScheme("package")
|
addDataScheme("package")
|
||||||
}
|
}
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
DisposableBroadcastReceiverAsUser(intentFilter, userHandle) { intent ->
|
DisposableBroadcastReceiverAsUser(intentFilter, userHandle) { intent ->
|
||||||
if (packageName == intent.data?.schemeSpecificPart) {
|
if (packageName == intent.data?.schemeSpecificPart) {
|
||||||
val packageInfo = flow.value
|
navController.navigateBack()
|
||||||
if (packageInfo != null && packageInfo.applicationInfo?.isSystemApp == true) {
|
|
||||||
// System app still exists after uninstalling the updates, refresh the page.
|
|
||||||
reloadPackageInfo()
|
|
||||||
} else {
|
|
||||||
navController.navigateBack()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +102,6 @@ class PackageInfoPresenter(
|
|||||||
userPackageManager.setApplicationEnabledSetting(
|
userPackageManager.setApplicationEnabledSetting(
|
||||||
packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
|
packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
|
||||||
)
|
)
|
||||||
reloadPackageInfo()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +112,6 @@ class PackageInfoPresenter(
|
|||||||
userPackageManager.setApplicationEnabledSetting(
|
userPackageManager.setApplicationEnabledSetting(
|
||||||
packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
|
packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
|
||||||
)
|
)
|
||||||
reloadPackageInfo()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +126,6 @@ class PackageInfoPresenter(
|
|||||||
logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
|
logAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
userPackageManager.deletePackageAsUser(packageName, null, 0, userId)
|
userPackageManager.deletePackageAsUser(packageName, null, 0, userId)
|
||||||
reloadPackageInfo()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +135,6 @@ class PackageInfoPresenter(
|
|||||||
coroutineScope.launch(Dispatchers.Default) {
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
Log.d(TAG, "Stopping package $packageName")
|
Log.d(TAG, "Stopping package $packageName")
|
||||||
context.activityManager.forceStopPackageAsUser(packageName, userId)
|
context.activityManager.forceStopPackageAsUser(packageName, userId)
|
||||||
reloadPackageInfo()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ class PackageInfoPresenter(
|
|||||||
metricsFeatureProvider.action(context, category, packageName)
|
metricsFeatureProvider.action(context, category, packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPackageInfo() =
|
private fun getPackageInfo(): PackageInfo? =
|
||||||
packageManagers.getPackageInfoAsUser(
|
packageManagers.getPackageInfoAsUser(
|
||||||
packageName = packageName,
|
packageName = packageName,
|
||||||
flags = PackageManager.MATCH_ANY_USER.toLong() or
|
flags = PackageManager.MATCH_ANY_USER.toLong() or
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import android.app.ActivityManager
|
|||||||
import android.app.settings.SettingsEnums
|
import android.app.settings.SettingsEnums
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.FakeFeatureFlagsImpl
|
|
||||||
import android.content.pm.Flags
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
@@ -30,91 +28,79 @@ import com.android.settings.testutils.mockAsUser
|
|||||||
import com.android.settingslib.spaprivileged.framework.common.activityManager
|
import com.android.settingslib.spaprivileged.framework.common.activityManager
|
||||||
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
|
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Before
|
import kotlinx.coroutines.test.TestScope
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.kotlin.any
|
||||||
import org.mockito.Mock
|
import org.mockito.kotlin.argumentCaptor
|
||||||
import org.mockito.Mockito.any
|
import org.mockito.kotlin.doNothing
|
||||||
import org.mockito.Mockito.doNothing
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.Spy
|
import org.mockito.kotlin.spy
|
||||||
import org.mockito.junit.MockitoJUnit
|
import org.mockito.kotlin.verify
|
||||||
import org.mockito.junit.MockitoRule
|
import org.mockito.kotlin.whenever
|
||||||
import org.mockito.Mockito.`when` as whenever
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class PackageInfoPresenterTest {
|
class PackageInfoPresenterTest {
|
||||||
@get:Rule
|
|
||||||
val mockito: MockitoRule = MockitoJUnit.rule()
|
|
||||||
|
|
||||||
@Spy
|
private val mockPackageManager = mock<PackageManager>()
|
||||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
|
||||||
|
|
||||||
@Mock
|
private val mockActivityManager = mock<ActivityManager>()
|
||||||
private lateinit var packageManager: PackageManager
|
|
||||||
|
|
||||||
@Mock
|
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||||
private lateinit var activityManager: ActivityManager
|
on { packageManager } doReturn mockPackageManager
|
||||||
|
on { activityManager } doReturn mockActivityManager
|
||||||
|
doNothing().whenever(mock).startActivityAsUser(any(), any())
|
||||||
|
mock.mockAsUser()
|
||||||
|
}
|
||||||
|
|
||||||
@Mock
|
private val packageManagers = mock<IPackageManagers>()
|
||||||
private lateinit var packageManagers: IPackageManagers
|
|
||||||
|
|
||||||
private val fakeFeatureFactory = FakeFeatureFactory()
|
private val fakeFeatureFactory = FakeFeatureFactory()
|
||||||
private val metricsFeatureProvider = fakeFeatureFactory.metricsFeatureProvider
|
private val metricsFeatureProvider = fakeFeatureFactory.metricsFeatureProvider
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
context.mockAsUser()
|
|
||||||
whenever(context.packageManager).thenReturn(packageManager)
|
|
||||||
whenever(context.activityManager).thenReturn(activityManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun enable() = runTest {
|
fun enable() = runBlocking {
|
||||||
coroutineScope {
|
val packageInfoPresenter =
|
||||||
val packageInfoPresenter =
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
|
||||||
|
|
||||||
packageInfoPresenter.enable()
|
packageInfoPresenter.enable()
|
||||||
}
|
delay(100)
|
||||||
|
|
||||||
verifyAction(SettingsEnums.ACTION_SETTINGS_ENABLE_APP)
|
verifyAction(SettingsEnums.ACTION_SETTINGS_ENABLE_APP)
|
||||||
verify(packageManager).setApplicationEnabledSetting(
|
verify(mockPackageManager).setApplicationEnabledSetting(
|
||||||
PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
|
PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun disable() = runTest {
|
fun disable() = runBlocking {
|
||||||
coroutineScope {
|
val packageInfoPresenter =
|
||||||
val packageInfoPresenter =
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
|
||||||
|
|
||||||
packageInfoPresenter.disable()
|
packageInfoPresenter.disable()
|
||||||
}
|
delay(100)
|
||||||
|
|
||||||
verifyAction(SettingsEnums.ACTION_SETTINGS_DISABLE_APP)
|
verifyAction(SettingsEnums.ACTION_SETTINGS_DISABLE_APP)
|
||||||
verify(packageManager).setApplicationEnabledSetting(
|
verify(mockPackageManager).setApplicationEnabledSetting(
|
||||||
PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
|
PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startUninstallActivity() = runTest {
|
fun startUninstallActivity() = runBlocking {
|
||||||
doNothing().`when`(context).startActivityAsUser(any(), any())
|
|
||||||
val packageInfoPresenter =
|
val packageInfoPresenter =
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
|
|
||||||
packageInfoPresenter.startUninstallActivity()
|
packageInfoPresenter.startUninstallActivity()
|
||||||
|
|
||||||
verifyAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
|
verifyAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
|
||||||
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
|
val intent = argumentCaptor<Intent> {
|
||||||
verify(context).startActivityAsUser(intentCaptor.capture(), any())
|
verify(context).startActivityAsUser(capture(), any())
|
||||||
with(intentCaptor.value) {
|
}.firstValue
|
||||||
|
with(intent) {
|
||||||
assertThat(action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
|
assertThat(action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
|
||||||
assertThat(data?.schemeSpecificPart).isEqualTo(PACKAGE_NAME)
|
assertThat(data?.schemeSpecificPart).isEqualTo(PACKAGE_NAME)
|
||||||
assertThat(getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true)).isEqualTo(false)
|
assertThat(getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true)).isEqualTo(false)
|
||||||
@@ -122,76 +108,39 @@ class PackageInfoPresenterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun clearInstantApp() = runTest {
|
fun clearInstantApp() = runBlocking {
|
||||||
coroutineScope {
|
val packageInfoPresenter =
|
||||||
val packageInfoPresenter =
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
|
||||||
|
|
||||||
packageInfoPresenter.clearInstantApp()
|
packageInfoPresenter.clearInstantApp()
|
||||||
}
|
delay(100)
|
||||||
|
|
||||||
verifyAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
|
verifyAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
|
||||||
verify(packageManager).deletePackageAsUser(PACKAGE_NAME, null, 0, USER_ID)
|
verify(mockPackageManager).deletePackageAsUser(PACKAGE_NAME, null, 0, USER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun forceStop() = runTest {
|
fun forceStop() = runBlocking {
|
||||||
coroutineScope {
|
val packageInfoPresenter =
|
||||||
val packageInfoPresenter =
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
|
||||||
|
|
||||||
packageInfoPresenter.forceStop()
|
packageInfoPresenter.forceStop()
|
||||||
}
|
delay(100)
|
||||||
|
|
||||||
verifyAction(SettingsEnums.ACTION_APP_FORCE_STOP)
|
verifyAction(SettingsEnums.ACTION_APP_FORCE_STOP)
|
||||||
verify(activityManager).forceStopPackageAsUser(PACKAGE_NAME, USER_ID)
|
verify(mockActivityManager).forceStopPackageAsUser(PACKAGE_NAME, USER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun logAction() = runTest {
|
fun logAction() = runBlocking {
|
||||||
val packageInfoPresenter =
|
val packageInfoPresenter =
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
|
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, TestScope(), packageManagers)
|
||||||
|
|
||||||
packageInfoPresenter.logAction(123)
|
packageInfoPresenter.logAction(123)
|
||||||
|
|
||||||
verifyAction(123)
|
verifyAction(123)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun reloadPackageInfo_archivingDisabled() = runTest {
|
|
||||||
coroutineScope {
|
|
||||||
val fakeFeatureFlags = FakeFeatureFlagsImpl()
|
|
||||||
fakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, false)
|
|
||||||
val packageInfoPresenter =
|
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers, fakeFeatureFlags)
|
|
||||||
|
|
||||||
packageInfoPresenter.reloadPackageInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
val flags = PackageManager.MATCH_ANY_USER.toLong() or
|
|
||||||
PackageManager.MATCH_DISABLED_COMPONENTS.toLong() or
|
|
||||||
PackageManager.GET_PERMISSIONS.toLong()
|
|
||||||
verify(packageManagers).getPackageInfoAsUser(PACKAGE_NAME, flags, USER_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun reloadPackageInfo_archivingEnabled() = runTest {
|
|
||||||
coroutineScope {
|
|
||||||
val fakeFeatureFlags = FakeFeatureFlagsImpl()
|
|
||||||
fakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, true)
|
|
||||||
val packageInfoPresenter =
|
|
||||||
PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers, fakeFeatureFlags)
|
|
||||||
|
|
||||||
packageInfoPresenter.reloadPackageInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
val flags = PackageManager.MATCH_ANY_USER.toLong() or
|
|
||||||
PackageManager.MATCH_DISABLED_COMPONENTS.toLong() or
|
|
||||||
PackageManager.GET_PERMISSIONS.toLong() or
|
|
||||||
PackageManager.MATCH_ARCHIVED_PACKAGES
|
|
||||||
verify(packageManagers).getPackageInfoAsUser(PACKAGE_NAME, flags, USER_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun verifyAction(category: Int) {
|
private fun verifyAction(category: Int) {
|
||||||
verify(metricsFeatureProvider).action(context, category, PACKAGE_NAME)
|
verify(metricsFeatureProvider).action(context, category, PACKAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user