blob: cd6745110812149dea9d5ae400973d7d9ad43ab5 [file] [log] [blame]
/*
* Copyright (C) 2021 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 android.safetycenter.cts
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.UserHandle.USER_NULL
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterEntry
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY
import android.safetycenter.SafetyCenterEntryGroup
import android.safetycenter.SafetyCenterEntryOrGroup
import android.safetycenter.SafetyCenterErrorDetails
import android.safetycenter.SafetyCenterIssue
import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION
import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
import android.safetycenter.SafetyCenterStaticEntry
import android.safetycenter.SafetyCenterStaticEntryGroup
import android.safetycenter.SafetyCenterStatus
import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS
import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS
import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_NONE
import android.safetycenter.SafetySourceData
import android.safetycenter.SafetySourceErrorDetails
import android.safetycenter.cts.testing.Coroutines.TIMEOUT_SHORT
import android.safetycenter.cts.testing.FakeExecutor
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.addOnSafetyCenterDataChangedListenerWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.clearAllSafetySourceDataForTestsWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.clearSafetyCenterConfigForTestsWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.executeSafetyCenterIssueActionWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterDataWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.getSafetySourceDataWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.refreshSafetySourcesWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.removeOnSafetyCenterDataChangedListenerWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.setSafetyCenterConfigForTestsWithPermission
import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.setSafetySourceDataWithPermission
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.COMPLEX_CONFIG
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_ALL_OPTIONAL_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_BAREBONE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_DISABLED_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_GROUP_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_HIDDEN_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_HIDDEN_WITH_SEARCH_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_IN_COLLAPSIBLE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_IN_RIGID_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.DYNAMIC_OTHER_PACKAGE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.ISSUE_ONLY_ALL_OPTIONAL_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.ISSUE_ONLY_BAREBONE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.ISSUE_ONLY_IN_RIGID_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.MIXED_COLLAPSIBLE_GROUP_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.MULTIPLE_SOURCES_CONFIG
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.NO_PAGE_OPEN_CONFIG
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SEVERITY_ZERO_CONFIG
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SINGLE_SOURCE_CONFIG
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SINGLE_SOURCE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SOURCE_ID_1
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SOURCE_ID_2
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.SOURCE_ID_3
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.STATIC_BAREBONE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsConfigs.STATIC_IN_COLLAPSIBLE_ID
import android.safetycenter.cts.testing.SafetyCenterCtsData
import android.safetycenter.cts.testing.SafetyCenterCtsHelper
import android.safetycenter.cts.testing.SafetyCenterCtsListener
import android.safetycenter.cts.testing.SafetyCenterFlags
import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import android.safetycenter.cts.testing.SafetySourceCtsData
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.CRITICAL_ISSUE_ACTION_ID
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.CRITICAL_ISSUE_ID
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.EVENT_SOURCE_STATE_CHANGED
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.INFORMATION_ISSUE_ACTION_ID
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.INFORMATION_ISSUE_ID
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.RECOMMENDATION_ISSUE_ACTION_ID
import android.safetycenter.cts.testing.SafetySourceCtsData.Companion.RECOMMENDATION_ISSUE_ID
import android.safetycenter.cts.testing.SafetySourceReceiver
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.SafetySourceDataKey
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.SafetySourceDataKey.Reason.REFRESH_FETCH_FRESH_DATA
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.SafetySourceDataKey.Reason.REFRESH_GET_DATA
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.SafetySourceDataKey.Reason.RESOLVING_ACTION
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.executeSafetyCenterIssueActionWithReceiverPermissionAndWait
import android.safetycenter.cts.testing.SafetySourceReceiver.Companion.refreshSafetySourcesWithReceiverPermissionAndWait
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import kotlin.test.assertFailsWith
import kotlinx.coroutines.TimeoutCancellationException
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
class SafetyCenterManagerTest {
private val context: Context = getApplicationContext()
private val safetyCenterCtsHelper = SafetyCenterCtsHelper(context)
private val safetySourceCtsData = SafetySourceCtsData(context)
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
private val stubPendingIntent =
PendingIntent.getActivity(
context, 0 /* requestCode */, Intent("Stub"), PendingIntent.FLAG_IMMUTABLE)
private val safetyCenterStatusOk =
SafetyCenterStatus.Builder("All good", "No problemo maestro")
.setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
.build()
private val safetyCenterStatusCritical =
SafetyCenterStatus.Builder("Uh-oh", "Code red")
.setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
.build()
private val safetyCenterEntryOrGroupCritical =
SafetyCenterEntryOrGroup(safetyCenterEntryCritical(SINGLE_SOURCE_ID))
private val safetyCenterEntryGroupMixedFromComplexConfig =
SafetyCenterEntryOrGroup(
SafetyCenterEntryGroup.Builder(
SafetyCenterCtsData.entryGroupId(MIXED_COLLAPSIBLE_GROUP_ID), "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
.setSummary("OK")
.setEntries(
listOf(
safetyCenterEntryDefaultBuilder(DYNAMIC_IN_COLLAPSIBLE_ID).build(),
SafetyCenterEntry.Builder(
SafetyCenterCtsData.entryId(STATIC_IN_COLLAPSIBLE_ID), "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
.setSummary("OK")
.setPendingIntent(stubPendingIntent)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
.build()))
.build())
private val safetyCenterStaticEntryGroupFromComplexConfig =
SafetyCenterStaticEntryGroup(
"OK",
listOf(
SafetyCenterStaticEntry.Builder("OK").setPendingIntent(stubPendingIntent).build(),
SafetyCenterStaticEntry.Builder("OK")
.setSummary("OK")
.setPendingIntent(stubPendingIntent)
.build()))
private val safetyCenterStaticEntryGroupMixedFromComplexConfig =
SafetyCenterStaticEntryGroup(
"OK",
listOf(
SafetyCenterStaticEntry.Builder("OK")
.setSummary("OK")
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.build(),
SafetyCenterStaticEntry.Builder("OK")
.setSummary("OK")
.setPendingIntent(stubPendingIntent)
.build()))
private val safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig =
SafetyCenterStaticEntryGroup(
"OK",
listOf(
SafetyCenterStaticEntry.Builder("Unspecified title")
.setSummary("Unspecified summary")
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.build(),
SafetyCenterStaticEntry.Builder("OK")
.setSummary("OK")
.setPendingIntent(stubPendingIntent)
.build()))
private val safetyCenterDataFromConfig =
SafetyCenterData(
safetyCenterStatusOk,
emptyList(),
listOf(
SafetyCenterEntryOrGroup(
safetyCenterEntryDefaultBuilder(SINGLE_SOURCE_ID).build())),
emptyList())
private val safetyCenterDataUnspecified =
SafetyCenterData(
safetyCenterStatusOk,
emptyList(),
listOf(SafetyCenterEntryOrGroup(safetyCenterEntryUnspecified(SINGLE_SOURCE_ID))),
emptyList())
private val safetyCenterDataOk =
SafetyCenterData(
safetyCenterStatusOk,
emptyList(),
listOf(SafetyCenterEntryOrGroup(safetyCenterEntryOk(SINGLE_SOURCE_ID))),
emptyList())
private val safetyCenterDataCritical =
SafetyCenterData(
safetyCenterStatusCritical,
listOf(safetyCenterIssueCritical(SINGLE_SOURCE_ID)),
listOf(safetyCenterEntryOrGroupCritical),
emptyList())
private val safetyCenterDataCriticalInFlightAction =
SafetyCenterData(
safetyCenterStatusCritical,
listOf(safetyCenterIssueCritical(SINGLE_SOURCE_ID, isActionInFlight = true)),
listOf(safetyCenterEntryOrGroupCritical),
emptyList())
private val safetyCenterDataCriticalWithDismissedIssue =
SafetyCenterData(
safetyCenterStatusOk,
emptyList(),
listOf(safetyCenterEntryOrGroupCritical),
emptyList())
private val safetyCenterDataFromComplexConfig =
SafetyCenterData(
safetyCenterStatusOk,
emptyList(),
listOf(
SafetyCenterEntryOrGroup(
SafetyCenterEntryGroup.Builder(
SafetyCenterCtsData.entryGroupId(DYNAMIC_GROUP_ID), "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
.setSummary("OK")
.setEntries(
listOf(
safetyCenterEntryDefaultBuilder(DYNAMIC_BAREBONE_ID).build(),
safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
.setEnabled(false)
.build(),
safetyCenterEntryDefaultBuilder(DYNAMIC_DISABLED_ID)
.setPendingIntent(null)
.setEnabled(false)
.build(),
safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
.setPendingIntent(null)
.setEnabled(false)
.build()))
.build()),
safetyCenterEntryGroupMixedFromComplexConfig),
listOf(
safetyCenterStaticEntryGroupFromComplexConfig,
safetyCenterStaticEntryGroupMixedFromComplexConfig))
private val safetyCenterDataFromComplexConfigUpdated =
SafetyCenterData(
safetyCenterStatusCritical,
listOf(
safetyCenterIssueCritical(DYNAMIC_BAREBONE_ID),
safetyCenterIssueCritical(ISSUE_ONLY_BAREBONE_ID),
safetyCenterIssueRecommendation(DYNAMIC_DISABLED_ID),
safetyCenterIssueRecommendation(ISSUE_ONLY_ALL_OPTIONAL_ID),
safetyCenterIssueInformation(DYNAMIC_IN_RIGID_ID),
safetyCenterIssueInformation(ISSUE_ONLY_IN_RIGID_ID)),
listOf(
SafetyCenterEntryOrGroup(
SafetyCenterEntryGroup.Builder(
SafetyCenterCtsData.entryGroupId(DYNAMIC_GROUP_ID), "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY)
// TODO(b/229076771): Check that the first summary of the most critical
// entries is used.
.setSummary("Critical summary")
.setEntries(
listOf(
safetyCenterEntryCritical(DYNAMIC_BAREBONE_ID),
safetyCenterEntryDefaultBuilder(DYNAMIC_ALL_OPTIONAL_ID)
.setEnabled(false)
.build(),
safetyCenterEntryRecommendation(DYNAMIC_DISABLED_ID),
safetyCenterEntryUnspecified(
DYNAMIC_HIDDEN_ID, pendingIntent = null),
safetyCenterEntryOk(DYNAMIC_HIDDEN_WITH_SEARCH_ID),
safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID)
.setPendingIntent(null)
.setEnabled(false)
.build()))
.build()),
safetyCenterEntryGroupMixedFromComplexConfig),
listOf(
safetyCenterStaticEntryGroupFromComplexConfig,
safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig))
// JUnit's Assume is not supported in @BeforeClass by the CTS tests runner, so this is used to
// manually skip the setup and teardown methods.
private val shouldRunTests = context.deviceSupportsSafetyCenter()
@Before
fun assumeDeviceSupportsSafetyCenterToRunTests() {
assumeTrue(shouldRunTests)
}
@Before
fun enableSafetyCenterBeforeTest() {
if (!shouldRunTests) {
return
}
safetyCenterCtsHelper.setEnabled(true)
}
@After
fun clearDataAfterTest() {
if (!shouldRunTests) {
return
}
safetyCenterCtsHelper.reset()
}
@Test
fun isSafetyCenterEnabled_withFlagEnabled_returnsTrue() {
val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
assertThat(isSafetyCenterEnabled).isTrue()
}
@Test
fun isSafetyCenterEnabled_withFlagDisabled_returnsFalse() {
safetyCenterCtsHelper.setEnabled(false)
val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
assertThat(isSafetyCenterEnabled).isFalse()
}
@Test
fun isSafetyCenterEnabled_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) { safetyCenterManager.isSafetyCenterEnabled }
}
@Test
fun setSafetySourceData_validId_setsValue() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val dataToSet = safetySourceCtsData.unspecified
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_twice_replacesValue() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.unspecified)
val dataToSet = safetySourceCtsData.criticalWithIssue
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_null_clearsValue() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.unspecified)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun setSafetySourceData_sourceInRigidGroupUnspecified_setsValue() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val dataToSet = safetySourceCtsData.unspecified
safetyCenterCtsHelper.setData(DYNAMIC_IN_RIGID_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_IN_RIGID_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_unknownId_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.unspecified)
}
assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
}
@Test
fun setSafetySourceData_staticId_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(STATIC_BAREBONE_ID, safetySourceCtsData.unspecified)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
}
@Test
fun setSafetySourceData_differentPackage_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
DYNAMIC_OTHER_PACKAGE_ID, safetySourceCtsData.unspecified)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected package name: ${context.packageName}, for safety source: " +
DYNAMIC_OTHER_PACKAGE_ID)
}
@Test
fun setSafetySourceData_sourceInRigidGroupNotUnspecified_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(DYNAMIC_IN_RIGID_ID, safetySourceCtsData.information)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Safety source: $DYNAMIC_IN_RIGID_ID is in a rigid group but specified a severity" +
" level: ${SafetySourceData.SEVERITY_LEVEL_INFORMATION}")
}
@Test
fun setSafetySourceData_nullUnknownId_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
}
assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
}
@Test
fun setSafetySourceData_nullStaticId_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(STATIC_BAREBONE_ID, safetySourceData = null)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
}
@Test
fun setSafetySourceData_nullDifferentPackage_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(DYNAMIC_OTHER_PACKAGE_ID, safetySourceData = null)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected package name: ${context.packageName}, for safety source: " +
DYNAMIC_OTHER_PACKAGE_ID)
}
@Test
fun setSafetySourceData_issueOnlyWithStatus_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
ISSUE_ONLY_BAREBONE_ID, safetySourceCtsData.unspecified)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Unexpected status for issue only safety source: $ISSUE_ONLY_BAREBONE_ID")
}
@Test
fun setSafetySourceData_dynamicWithIssueOnly_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
DYNAMIC_BAREBONE_ID,
SafetySourceCtsData.issuesOnly(safetySourceCtsData.informationIssue))
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Missing status for dynamic safety source: $DYNAMIC_BAREBONE_ID")
}
@Test
fun setSafetySourceData_withMaxSevZeroAndSourceSevUnspecified_setsValue() {
safetyCenterCtsHelper.setConfig(SEVERITY_ZERO_CONFIG)
val dataToSet = safetySourceCtsData.unspecified
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_withMaxSevZeroAndSourceSevInformation_setsValue() {
safetyCenterCtsHelper.setConfig(SEVERITY_ZERO_CONFIG)
val dataToSet = safetySourceCtsData.information
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_withMaxSevZeroAndSourceSevInformationWithIssue_throwsException() {
safetyCenterCtsHelper.setConfig(SEVERITY_ZERO_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
SINGLE_SOURCE_ID, safetySourceCtsData.informationWithIssue)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected severity level: ${
SafetySourceData.SEVERITY_LEVEL_INFORMATION
}, for issue in safety source: $SINGLE_SOURCE_ID")
}
@Test
fun setSafetySourceData_withMaxSevZeroAndSourceSevCritical_throwsException() {
safetyCenterCtsHelper.setConfig(SEVERITY_ZERO_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected severity level: ${
SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
}, for safety source: $SINGLE_SOURCE_ID")
}
@Test
fun setSafetySourceData_withMaxSevRecommendation_met() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val dataToSet = safetySourceCtsData.recommendationWithIssue
safetyCenterCtsHelper.setData(DYNAMIC_ALL_OPTIONAL_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_ALL_OPTIONAL_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_withMaxSevRecommendation_notMet() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
DYNAMIC_ALL_OPTIONAL_ID, safetySourceCtsData.criticalWithIssue)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected severity level: ${
SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
}, for safety source: $DYNAMIC_ALL_OPTIONAL_ID")
}
@Test
fun setSafetySourceData_issueOnlyWithMaxSevRecommendation_met() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val dataToSet = SafetySourceCtsData.issuesOnly(safetySourceCtsData.recommendationIssue)
safetyCenterCtsHelper.setData(ISSUE_ONLY_ALL_OPTIONAL_ID, dataToSet)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(ISSUE_ONLY_ALL_OPTIONAL_ID)
assertThat(apiSafetySourceData).isEqualTo(dataToSet)
}
@Test
fun setSafetySourceData_issueOnlyWithMaxSevRecommendation_notMet() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterCtsHelper.setData(
ISSUE_ONLY_ALL_OPTIONAL_ID,
SafetySourceCtsData.issuesOnly(safetySourceCtsData.criticalIssue))
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected severity level: ${
SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
}, for issue in safety source: $ISSUE_ONLY_ALL_OPTIONAL_ID")
}
@Test
fun setSafetySourceData_withFlagDisabled_doesntSetData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.setSafetySourceDataWithPermission(
SINGLE_SOURCE_ID, safetySourceCtsData.unspecified, EVENT_SOURCE_STATE_CHANGED)
safetyCenterCtsHelper.setEnabled(true)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun setSafetySourceData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.setSafetySourceData(
SINGLE_SOURCE_ID, safetySourceCtsData.unspecified, EVENT_SOURCE_STATE_CHANGED)
}
}
@Test
fun getSafetySourceData_validId_noData_returnsNull() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun getSafetySourceData_unknownId_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
}
assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
}
@Test
fun getSafetySourceData_staticId_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.getSafetySourceDataWithPermission(STATIC_BAREBONE_ID)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
}
@Test
fun getSafetySourceData_differentPackage_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_OTHER_PACKAGE_ID)
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected package name: ${context.packageName}, for safety source: " +
DYNAMIC_OTHER_PACKAGE_ID)
}
@Test
fun getSafetySourceData_withFlagDisabled_returnsNull() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.unspecified)
safetyCenterCtsHelper.setEnabled(false)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun getSafetySourceData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.getSafetySourceData(SINGLE_SOURCE_ID)
}
}
@Test
fun reportSafetySourceError_callsErrorListener() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.reportSafetySourceErrorWithPermission(
SINGLE_SOURCE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
val safetyCenterErrorDetailsFromListener = listener.receiveSafetyCenterErrorDetails()
assertThat(safetyCenterErrorDetailsFromListener)
.isEqualTo(SafetyCenterErrorDetails("Error reported from source: $SINGLE_SOURCE_ID"))
}
@Test
fun reportSafetySourceError_unknownId_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.reportSafetySourceErrorWithPermission(
SINGLE_SOURCE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
}
assertThat(thrown).hasMessageThat().isEqualTo("Unexpected safety source: $SINGLE_SOURCE_ID")
}
@Test
fun reportSafetySourceError_staticId_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.reportSafetySourceErrorWithPermission(
STATIC_BAREBONE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Unexpected safety source: $STATIC_BAREBONE_ID")
}
@Test
fun reportSafetySourceError_differentPackage_throwsIllegalArgumentException() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.reportSafetySourceErrorWithPermission(
DYNAMIC_OTHER_PACKAGE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
}
assertThat(thrown)
.hasMessageThat()
.isEqualTo(
"Unexpected package name: ${context.packageName}, for safety source: " +
DYNAMIC_OTHER_PACKAGE_ID)
}
@Test
fun reportSafetySourceError_withFlagDisabled_doesntCallErrorListener() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.reportSafetySourceErrorWithPermission(
SINGLE_SOURCE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT)
}
}
@Test
fun reportSafetySourceError_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.reportSafetySourceError(
SINGLE_SOURCE_ID, SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED))
}
}
@Test
fun safetyCenterEnabledChanged_whenImplicitReceiverHasPermission_receiverCalled() {
val enabledChangedReceiver = safetyCenterCtsHelper.addEnabledChangedReceiver()
var receiverValue =
enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(false)
assertThat(receiverValue).isFalse()
val toggledReceiverValue =
enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(true)
assertThat(toggledReceiverValue).isTrue()
}
@Test
fun safetyCenterEnabledChanged_whenImplicitReceiverDoesntHavePermission_receiverNotCalled() {
val enabledChangedReceiver = safetyCenterCtsHelper.addEnabledChangedReceiver()
SafetyCenterFlags.isEnabled = false
assertFailsWith(TimeoutCancellationException::class) {
enabledChangedReceiver.receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT)
}
}
@Test
fun safetyCenterEnabledChanged_whenSourceReceiverHasPermission_receiverCalled() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
var receiverValue =
SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(false)
assertThat(receiverValue).isFalse()
val toggledReceiverValue =
SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(true)
assertThat(toggledReceiverValue).isTrue()
}
@Test
fun safetyCenterEnabledChanged_valueDoesntChange_receiverNotCalled() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
assertFailsWith(TimeoutCancellationException::class) {
SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
true, TIMEOUT_SHORT)
}
}
@Test
fun safetyCenterEnabledChanged_whenSourceReceiverDoesntHavePermission_receiverNotCalled() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetyCenterFlags.isEnabled = false
assertFailsWith(TimeoutCancellationException::class) {
SafetySourceReceiver.receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT)
}
}
@Test
fun safetyCenterEnabledChanged_whenSourceReceiverNotInConfig_receiverNotCalled() {
assertFailsWith(TimeoutCancellationException::class) {
SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait(
false, TIMEOUT_SHORT)
}
}
@Test
fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.criticalWithIssue
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(safetySourceCtsData.criticalWithIssue)
}
@Test
fun refreshSafetySources_withRefreshReasonPageOpen_sourceSendsPageOpenData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(safetySourceCtsData.information)
}
@Test
fun refreshSafetySources_withRefreshReasonPageOpen_notCalledIfSourceDoesntSupportPageOpen() {
safetyCenterCtsHelper.setConfig(NO_PAGE_OPEN_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN, TIMEOUT_SHORT)
}
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun refreshSafetySources_whenSourceClearsData_sourceSendsNullData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] = null
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun refreshSafetySources_withMultipleSourcesInConfig_multipleSourcesSendData() {
safetyCenterCtsHelper.setConfig(MULTIPLE_SOURCES_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SOURCE_ID_1)] =
safetySourceCtsData.criticalWithIssue
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SOURCE_ID_3)] =
safetySourceCtsData.information
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val apiSafetySourceData1 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
assertThat(apiSafetySourceData1).isEqualTo(safetySourceCtsData.criticalWithIssue)
val apiSafetySourceData2 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
assertThat(apiSafetySourceData2).isNull()
val apiSafetySourceData3 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
assertThat(apiSafetySourceData3).isEqualTo(safetySourceCtsData.information)
}
@Test
fun refreshSafetySources_withMultipleSourcesOnPageOpen_onlyUpdatesAllowedSources() {
safetyCenterCtsHelper.setConfig(MULTIPLE_SOURCES_CONFIG)
SafetySourceReceiver.safetySourceData[SafetySourceDataKey(REFRESH_GET_DATA, SOURCE_ID_1)] =
safetySourceCtsData.criticalWithIssue
SafetySourceReceiver.safetySourceData[SafetySourceDataKey(REFRESH_GET_DATA, SOURCE_ID_3)] =
safetySourceCtsData.information
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
val apiSafetySourceData1 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
assertThat(apiSafetySourceData1).isEqualTo(safetySourceCtsData.criticalWithIssue)
val apiSafetySourceData2 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
assertThat(apiSafetySourceData2).isNull()
// SOURCE_ID_3 doesn't support refresh on page open.
val apiSafetySourceData3 =
safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_3)
assertThat(apiSafetySourceData3).isNull()
}
@Test
fun refreshSafetySources_whenReceiverDoesntHavePermission_sourceDoesntSendData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.criticalWithIssue
safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK)
assertFailsWith(TimeoutCancellationException::class) {
SafetySourceReceiver.receiveRefreshSafetySources(TIMEOUT_SHORT)
}
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isNull()
}
@Test
fun refreshSafetySources_whenSourceNotInConfig_sourceDoesntSendData() {
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN, TIMEOUT_SHORT)
}
}
@Test
fun refreshSafetySources_sendsBroadcastId() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val lastReceivedBroadcastId =
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
assertThat(lastReceivedBroadcastId).isNotNull()
}
@Test
fun refreshSafetySources_sendsDifferentBroadcastIdsOnEachMethodCall() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
val broadcastId1 =
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val broadcastId2 =
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
assertThat(broadcastId1).isNotEqualTo(broadcastId2)
}
@Test
fun refreshSafetySources_refreshAfterSuccessfulRefresh_completesSuccessfully() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.criticalWithIssue
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(safetySourceCtsData.criticalWithIssue)
}
@Test
fun refreshSafetySources_refreshAfterFailedRefresh_completesSuccessfully() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
SafetySourceReceiver.shouldReportSafetySourceError = true
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
SafetySourceReceiver.shouldReportSafetySourceError = false
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(safetySourceCtsData.information)
}
@Test
fun refreshSafetySources_withoutAllowingPreviousRefreshToTimeout_completesSuccessfully() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
assertThat(apiSafetySourceData).isEqualTo(safetySourceCtsData.information)
}
@Test
fun refreshSafetySources_withRefreshReasonRescanButtonClick_notifiesUiDuringRescan() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_FETCH_FRESH_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK)
val refreshStatus1 = listener.receiveSafetyCenterData().status.refreshStatus
assertThat(refreshStatus1).isEqualTo(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS)
val refreshStatus2 = listener.receiveSafetyCenterData().status.refreshStatus
assertThat(refreshStatus2).isEqualTo(REFRESH_STATUS_NONE)
}
@Test
fun refreshSafetySources_withRefreshReasonPageOpen_notifiesUiWithFetch() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(REFRESH_GET_DATA, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN)
val refreshStatus1 = listener.receiveSafetyCenterData().status.refreshStatus
assertThat(refreshStatus1).isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS)
val refreshStatus2 = listener.receiveSafetyCenterData().status.refreshStatus
assertThat(refreshStatus2).isEqualTo(REFRESH_STATUS_NONE)
}
@Test
fun refreshSafetySources_withFlagDisabled_doesntRefreshSources() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setEnabled(false)
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_PAGE_OPEN, TIMEOUT_SHORT)
}
}
@Test
fun refreshSafetySources_withInvalidRefreshSeason_throwsIllegalArgumentException() {
val thrown =
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.refreshSafetySourcesWithPermission(143201)
}
assertThat(thrown).hasMessageThat().isEqualTo("Unexpected refresh reason: 143201")
}
@Test
fun refreshSafetySources_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.refreshSafetySources(REFRESH_REASON_RESCAN_BUTTON_CLICK)
}
}
@Test
fun getSafetyCenterConfig_withFlagEnabled_isNotNull() {
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isNotNull()
}
@Test
fun getSafetyCenterConfig_withFlagDisabled_isNotNull() {
safetyCenterCtsHelper.setEnabled(false)
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isNotNull()
}
@Test
fun getSafetyCenterConfig_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterConfig }
}
@Test
fun getSafetyCenterData_withoutDataProvided_returnsDataFromConfig() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataFromConfig)
}
@Test
fun getSafetyCenterData_withComplexConfigWithoutDataProvided_returnsDataFromConfig() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
val apiSafetyCenterData =
safetyCenterManager.getSafetyCenterDataWithPermission().normalize()
assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataFromComplexConfig)
}
@Test
fun getSafetyCenterData_withSomeDataProvided_returnsDataProvided() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.unspecified)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataUnspecified)
}
@Test
fun getSafetyCenterData_withUpdatedData_returnsUpdatedData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
val previousApiSafetyCenterData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
assertThat(apiSafetyCenterData).isNotEqualTo(previousApiSafetyCenterData)
assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataCritical)
}
@Test
fun getSafetyCenterData_withComplexConfigWithSomeDataProvided_returnsDataProvided() {
safetyCenterCtsHelper.setConfig(COMPLEX_CONFIG)
safetyCenterCtsHelper.setData(DYNAMIC_BAREBONE_ID, safetySourceCtsData.criticalWithIssue)
safetyCenterCtsHelper.setData(
DYNAMIC_DISABLED_ID, safetySourceCtsData.recommendationWithIssue)
safetyCenterCtsHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceCtsData.unspecified)
safetyCenterCtsHelper.setData(
DYNAMIC_HIDDEN_WITH_SEARCH_ID, safetySourceCtsData.information)
safetyCenterCtsHelper.setData(
ISSUE_ONLY_BAREBONE_ID,
SafetySourceCtsData.issuesOnly(safetySourceCtsData.criticalIssue))
safetyCenterCtsHelper.setData(
ISSUE_ONLY_ALL_OPTIONAL_ID,
SafetySourceCtsData.issuesOnly(safetySourceCtsData.recommendationIssue))
safetyCenterCtsHelper.setData(DYNAMIC_IN_RIGID_ID, safetySourceCtsData.unspecifiedWithIssue)
safetyCenterCtsHelper.setData(
ISSUE_ONLY_IN_RIGID_ID,
SafetySourceCtsData.issuesOnly(safetySourceCtsData.informationIssue))
val apiSafetyCenterData =
safetyCenterManager.getSafetyCenterDataWithPermission().normalize()
assertThat(apiSafetyCenterData).isEqualTo(safetyCenterDataFromComplexConfigUpdated)
}
@Test
fun getSafetyCenterData_withFlagDisabled_returnsDefaultData() {
safetyCenterCtsHelper.setEnabled(false)
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
assertThat(apiSafetyCenterData).isEqualTo(SafetyCenterCtsData.DEFAULT)
}
@Test
fun getSafetyCenterData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterData }
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterDataFromConfig() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener(skipInitialData = false)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataFromConfig)
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledOnSafetySourceData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataOk)
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataChanges() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataCritical)
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataCleared() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener).isEqualTo(safetyCenterDataFromConfig)
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataStaysNull() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceData = null)
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataDoesntChange() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
val dataToSet = safetySourceCtsData.information
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
// Receive update from #setSafetySourceData call.
listener.receiveSafetyCenterData()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, dataToSet)
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun addOnSafetyCenterDataChangedListener_oneShot_doesntDeadlock() {
val listener = SafetyCenterCtsListener()
val oneShotListener =
object : OnSafetyCenterDataChangedListener {
override fun onSafetyCenterDataChanged(safetyCenterData: SafetyCenterData) {
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(this)
listener.onSafetyCenterDataChanged(safetyCenterData)
}
}
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
directExecutor(), oneShotListener)
// Check that we don't deadlock when using a one-shot listener. This is because adding the
// listener could call it while holding a lock; which would cause a deadlock if the listener
// wasn't oneway.
listener.receiveSafetyCenterData()
}
@Test
fun addOnSafetyCenterDataChangedListener_withFlagDisabled_listenerNotCalled() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setEnabled(false)
val listener = SafetyCenterCtsListener()
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
directExecutor(), listener)
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun addOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
val listener = SafetyCenterCtsListener()
assertFailsWith(SecurityException::class) {
safetyCenterManager.addOnSafetyCenterDataChangedListener(directExecutor(), listener)
}
}
@Test
fun removeOnSafetyCenterDataChangedListener_listenerRemovedNotCalledOnSafetySourceData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener1 = safetyCenterCtsHelper.addListener()
val listener2 = safetyCenterCtsHelper.addListener()
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener2)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
listener1.receiveSafetyCenterData()
assertFailsWith(TimeoutCancellationException::class) {
listener2.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun removeOnSafetyCenterDataChangedListener_listenerNeverCalledAfterRemoving() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val fakeExecutor = FakeExecutor()
val listener = SafetyCenterCtsListener()
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
fakeExecutor, listener)
fakeExecutor.getNextTask().run()
listener.receiveSafetyCenterData()
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
val callListenerTask = fakeExecutor.getNextTask()
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
// Simulate the submitted task being run *after* the remove call completes. Our API should
// guard against this raciness, as users of this class likely don't expect their listener to
// be called after calling #removeOnSafetyCenterDataChangedListener.
callListenerTask.run()
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun removeOnSafetyCenterDataChangedListener_withFlagDisabled_removesListener() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
safetyCenterCtsHelper.setEnabled(true)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
// Listener is removed as a side effect of the ENABLED_CHANGED broadcast.
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun removeOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
val listener = safetyCenterCtsHelper.addListener()
assertFailsWith(SecurityException::class) {
safetyCenterManager.removeOnSafetyCenterDataChangedListener(listener)
}
}
@Test
fun dismissSafetyCenterIssue_existing_callsListenerAndDismisses() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID))
val safetyCenterDataFromListener = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListener)
.isEqualTo(safetyCenterDataCriticalWithDismissedIssue)
}
@Test
fun dismissSafetyCenterIssue_nonExisting_doesntCallListenerOrDismiss() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, "some_unknown_id"))
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun dismissSafetyCenterIssue_alreadyDismissed_doesntCallListenerOrDismiss() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID))
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID))
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun dismissSafetyCenterIssue_withFlagDisabled_doesntCallListenerOrDismiss() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID))
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun dismissSafetyCenterIssue_invalidId_throwsIllegalArgumentException() {
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.dismissSafetyCenterIssueWithPermission("bleh")
}
}
@Test
fun dismissSafetyCenterIssue_invalidUser_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.dismissSafetyCenterIssueWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, USER_NULL))
}
}
@Test
fun dismissSafetyCenterIssue_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.dismissSafetyCenterIssue("bleh")
}
}
@Test
fun executeSafetyCenterIssueAction_existing_callsListenerWithInFlightActionAndExecutes() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(RESOLVING_ACTION, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID))
val safetyCenterDataFromListenerDuringInlineAction = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListenerDuringInlineAction)
.isEqualTo(safetyCenterDataCriticalInFlightAction)
val safetyCenterDataFromListenerAfterInlineAction = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListenerAfterInlineAction).isEqualTo(safetyCenterDataOk)
}
@Test
fun executeSafetyCenterIssueAction_existing_unmarkInFlightWhenInlineActionError() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
SafetySourceReceiver.shouldReportSafetySourceError = true
SafetySourceReceiver.safetySourceData[
SafetySourceDataKey(RESOLVING_ACTION, SINGLE_SOURCE_ID)] =
safetySourceCtsData.information
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID))
val safetyCenterDataFromListenerDuringInlineAction = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListenerDuringInlineAction)
.isEqualTo(safetyCenterDataCriticalInFlightAction)
val safetyCenterDataFromListenerAfterInlineAction = listener.receiveSafetyCenterData()
assertThat(safetyCenterDataFromListenerAfterInlineAction)
.isEqualTo(safetyCenterDataCritical)
val error = listener.receiveSafetyCenterErrorDetails()
assertThat(error)
.isEqualTo(SafetyCenterErrorDetails("Error reported from source: $SINGLE_SOURCE_ID"))
}
@Test
fun executeSafetyCenterIssueAction_nonExisting_doesntCallListenerOrExecute() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.information)
val listener = safetyCenterCtsHelper.addListener()
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID),
TIMEOUT_SHORT)
}
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun executeSafetyCenterIssueAction_alreadyInFlight_doesntCallListenerOrExecute() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID))
listener.receiveSafetyCenterData()
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID),
TIMEOUT_SHORT)
}
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun executeSafetyCenterIssueAction_withFlagDisabled_doesntCallListenerOrExecute() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
val listener = safetyCenterCtsHelper.addListener()
safetyCenterCtsHelper.setEnabled(false)
assertFailsWith(TimeoutCancellationException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithReceiverPermissionAndWait(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID),
TIMEOUT_SHORT)
}
assertFailsWith(TimeoutCancellationException::class) {
listener.receiveSafetyCenterData(TIMEOUT_SHORT)
}
}
@Test
fun executeSafetyCenterIssueAction_invalidId_throwsIllegalArgumentException() {
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithPermission("barf", "burgh")
}
}
@Test
fun executeSafetyCenterIssueAction_idsDontMatch_throwsIllegalArgumentException() {
assertFailsWith(IllegalArgumentException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID),
SafetyCenterCtsData.issueActionId(
SOURCE_ID_1, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID))
}
}
@Test
fun executeSafetyCenterIssueAction_invalidUser_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.executeSafetyCenterIssueActionWithPermission(
SafetyCenterCtsData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, USER_NULL),
SafetyCenterCtsData.issueActionId(
SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID, USER_NULL))
}
}
@Test
fun executeSafetyCenterIssueAction_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.executeSafetyCenterIssueAction("bleh", "blah")
}
}
@Test
fun clearAllSafetySourceDataForTests_clearsAllSafetySourceData() {
safetyCenterCtsHelper.setConfig(MULTIPLE_SOURCES_CONFIG)
safetyCenterCtsHelper.setData(SOURCE_ID_1, safetySourceCtsData.unspecified)
safetyCenterCtsHelper.setData(SOURCE_ID_2, safetySourceCtsData.criticalWithIssue)
safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
val data1AfterClearing = safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_1)
assertThat(data1AfterClearing).isNull()
val data2AfterClearing = safetyCenterManager.getSafetySourceDataWithPermission(SOURCE_ID_2)
assertThat(data2AfterClearing).isNull()
}
@Test
fun clearAllSafetySourceDataForTests_withFlagDisabled_clearsData() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setData(SINGLE_SOURCE_ID, safetySourceCtsData.criticalWithIssue)
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission()
safetyCenterCtsHelper.setEnabled(true)
val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID)
// Data is cleared as a side effect of the ENABLED_CHANGED broadcast.
assertThat(apiSafetySourceData).isNull()
}
@Test
fun clearAllSafetySourceDataForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.clearAllSafetySourceDataForTests()
}
}
@Test
fun setSafetyCenterConfigForTests_setsConfig() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isEqualTo(SINGLE_SOURCE_CONFIG)
}
@Test
fun setSafetyCenterConfigForTests_withFlagDisabled_doesntSetConfig() {
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.setSafetyCenterConfigForTestsWithPermission(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setEnabled(true)
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isNotEqualTo(SINGLE_SOURCE_CONFIG)
}
@Test
fun setSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.setSafetyCenterConfigForTests(SINGLE_SOURCE_CONFIG)
}
}
@Test
fun clearSafetyCenterConfigForTests_clearsConfigSetForTests_doesntSetConfigToNull() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isNotNull()
assertThat(config).isNotEqualTo(SINGLE_SOURCE_CONFIG)
}
@Test
fun clearSafetyCenterConfigForTests_withFlagDisabled_doesntClearConfig() {
safetyCenterCtsHelper.setConfig(SINGLE_SOURCE_CONFIG)
safetyCenterCtsHelper.setEnabled(false)
safetyCenterManager.clearSafetyCenterConfigForTestsWithPermission()
safetyCenterCtsHelper.setEnabled(true)
val config = safetyCenterManager.getSafetyCenterConfigWithPermission()
assertThat(config).isEqualTo(SINGLE_SOURCE_CONFIG)
}
@Test
fun clearSafetyCenterConfigForTests_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.clearSafetyCenterConfigForTests()
}
}
private fun safetyCenterEntryDefaultBuilder(sourceId: String) =
SafetyCenterEntry.Builder(SafetyCenterCtsData.entryId(sourceId), "OK")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
.setSummary("OK")
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
private fun safetyCenterEntryUnspecified(
sourceId: String,
pendingIntent: PendingIntent? = safetySourceCtsData.redirectPendingIntent
) =
SafetyCenterEntry.Builder(SafetyCenterCtsData.entryId(sourceId), "Unspecified title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
.setSummary("Unspecified summary")
.setPendingIntent(pendingIntent)
.setEnabled(false)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
private fun safetyCenterEntryOk(sourceId: String) =
SafetyCenterEntry.Builder(SafetyCenterCtsData.entryId(sourceId), "Ok title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_OK)
.setSummary("Ok summary")
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
private fun safetyCenterEntryRecommendation(
sourceId: String,
summary: String = "Recommendation summary"
) =
SafetyCenterEntry.Builder(SafetyCenterCtsData.entryId(sourceId), "Recommendation title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
.setSummary(summary)
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
private fun safetyCenterEntryCritical(sourceId: String) =
SafetyCenterEntry.Builder(SafetyCenterCtsData.entryId(sourceId), "Critical title")
.setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
.setSummary("Critical summary")
.setPendingIntent(safetySourceCtsData.redirectPendingIntent)
.setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
.build()
private fun safetyCenterIssueInformation(sourceId: String) =
SafetyCenterIssue.Builder(
SafetyCenterCtsData.issueId(sourceId, INFORMATION_ISSUE_ID),
"Information issue title",
"Information issue summary")
.setSeverityLevel(ISSUE_SEVERITY_LEVEL_OK)
.setActions(
listOf(
SafetyCenterIssue.Action.Builder(
SafetyCenterCtsData.issueActionId(
sourceId, INFORMATION_ISSUE_ID, INFORMATION_ISSUE_ACTION_ID),
"Review",
safetySourceCtsData.redirectPendingIntent)
.build()))
.build()
private fun safetyCenterIssueRecommendation(sourceId: String) =
SafetyCenterIssue.Builder(
SafetyCenterCtsData.issueId(sourceId, RECOMMENDATION_ISSUE_ID),
"Recommendation issue title",
"Recommendation issue summary")
.setSeverityLevel(ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
.setActions(
listOf(
SafetyCenterIssue.Action.Builder(
SafetyCenterCtsData.issueActionId(
sourceId, RECOMMENDATION_ISSUE_ID, RECOMMENDATION_ISSUE_ACTION_ID),
"See issue",
safetySourceCtsData.redirectPendingIntent)
.build()))
.build()
private fun safetyCenterIssueCritical(sourceId: String, isActionInFlight: Boolean = false) =
SafetyCenterIssue.Builder(
SafetyCenterCtsData.issueId(sourceId, CRITICAL_ISSUE_ID),
"Critical issue title",
"Critical issue summary")
.setSeverityLevel(ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
.setActions(
listOf(
SafetyCenterIssue.Action.Builder(
SafetyCenterCtsData.issueActionId(
sourceId, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID),
"Solve issue",
safetySourceCtsData.criticalIssueActionPendingIntent)
.setWillResolve(true)
.setIsInFlight(isActionInFlight)
.build()))
.build()
private fun SafetyCenterData.normalize() =
SafetyCenterData(
status,
issues,
entriesOrGroups.map {
if (it.entry != null) SafetyCenterEntryOrGroup(it.entry!!.normalize())
else SafetyCenterEntryOrGroup(it.entryGroup!!.normalize())
},
staticEntryGroups.map { it.normalize() })
private fun SafetyCenterEntryGroup.normalize() =
SafetyCenterEntryGroup.Builder(this).setEntries(entries.map { it.normalize() }).build()
private fun SafetyCenterEntry.normalize() =
SafetyCenterEntry.Builder(this).setPendingIntent(pendingIntent.normalize()).build()
private fun SafetyCenterStaticEntryGroup.normalize() =
SafetyCenterStaticEntryGroup(title, staticEntries.map { it.normalize() })
private fun SafetyCenterStaticEntry.normalize() =
SafetyCenterStaticEntry.Builder(this).setPendingIntent(pendingIntent.normalize()).build()
private fun PendingIntent?.normalize() =
if (this != null && creatorPackage != context.packageName) stubPendingIntent else this
}