From fb8069ae2ae416949807d019cbd2192272a955aa Mon Sep 17 00:00:00 2001 From: Joshua McCloskey Date: Tue, 26 Mar 2024 18:10:24 +0000 Subject: [PATCH 01/14] Updated FakeFingerprintManagerInteractor This class should use FingerprintSensorPropertiesInternal.toFingerprintSensor() instead of creating a FingerprintSensor(). Bug: 297082837 Test: atest Change-Id: I3b622563300931f1f1638ae63b1c44aa62189087 --- .../FingerprintEnrollIntroFragmentTest.kt | 18 +++- .../biometrics/fingerprint/Injector.kt | 23 ++++- .../FakeFingerprintManagerInteractor.kt | 30 ++++--- .../FingerprintManagerInteractorTest.kt | 33 +++++-- ...gerprintEnrollFindSensorViewModelV2Test.kt | 69 +++++++++++---- ...gerprintEnrollConfirmationViewModelTest.kt | 20 ++++- ...FingerprintEnrollEnrollingViewModelTest.kt | 23 +++-- .../FingerprintSettingsViewModelTest.kt | 87 ++++++++++++------- 8 files changed, 223 insertions(+), 80 deletions(-) diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt b/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt index cea72aa7753..e876289866e 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt @@ -17,6 +17,11 @@ package com.android.settings.biometrics.fingerprint2.fragment import android.content.Context +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.Bundle import androidx.fragment.app.testing.FragmentScenario import androidx.fragment.app.testing.launchFragmentInContainer @@ -47,6 +52,7 @@ import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.systemui.biometrics.shared.model.FingerprintSensor import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.android.setupdesign.GlifLayout import com.google.android.setupdesign.template.RequireScrollMixin import kotlinx.coroutines.test.StandardTestDispatcher @@ -67,7 +73,17 @@ class FingerprintEnrollIntroFragmentTest { private val backgroundDispatcher = StandardTestDispatcher() private lateinit var fragmentScenario: FragmentScenario private val fingerprintSensor = - FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() var enrollFlow = Default val flowViewModel = FingerprintFlowViewModel(enrollFlow) diff --git a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt index 9d97fbf8f96..4d2865040cb 100644 --- a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt +++ b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt @@ -16,6 +16,11 @@ package com.android.settings.tests.screenshot.biometrics.fingerprint import android.content.res.Configuration +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.view.Surface import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider @@ -39,9 +44,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo import com.android.settings.testutils2.FakeFingerprintManagerInteractor -import com.android.systemui.biometrics.shared.model.FingerprintSensor -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -56,7 +59,19 @@ import platform.test.screenshot.matchers.PixelPerfectMatcher class Injector(step: FingerprintNavigationStep.UiStep) { var enrollFlow = Default - var fingerprintSensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.REAR) + var fingerprintSensor = + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_REAR, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + var accessibilityInteractor = object : AccessibilityInteractor { override val isAccessibilityEnabled: Flow = flowOf(true) diff --git a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt index f571dad420b..b39f0d18522 100644 --- a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt +++ b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt @@ -16,6 +16,11 @@ package com.android.settings.testutils2 +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState @@ -23,7 +28,7 @@ import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAtt import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData import com.android.systemui.biometrics.shared.model.FingerprintSensor import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf @@ -35,16 +40,20 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { var enrolledFingerprintsInternal: MutableList = mutableListOf() var challengeToGenerate: Pair = Pair(-1L, byteArrayOf()) var authenticateAttempt = FingerprintAuthAttemptModel.Success(1) - var enrollStateViewModel: List = - listOf(FingerEnrollState.EnrollProgress(5, 5)) + var enrollStateViewModel: List = listOf(FingerEnrollState.EnrollProgress(5, 5)) var sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5, - FingerprintSensorType.POWER_BUTTON - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() override suspend fun authenticate(): FingerprintAuthAttemptModel { return authenticateAttempt @@ -68,7 +77,7 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { override suspend fun enroll( hardwareAuthToken: ByteArray?, - enrollReason: EnrollReason + enrollReason: EnrollReason, ): Flow = flowOf(*enrollStateViewModel.toTypedArray()) override suspend fun removeFingerprint(fp: FingerprintData): Boolean { @@ -84,5 +93,4 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { override suspend fun hasSideFps(): Boolean { return sensorProp.sensorType == FingerprintSensorType.POWER_BUTTON } - } diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt index 2b4bff77bc7..58d18f69db0 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt @@ -18,18 +18,23 @@ package com.android.settings.fingerprint2.domain.interactor import android.content.Context import android.content.Intent +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties import android.hardware.fingerprint.Fingerprint import android.hardware.fingerprint.FingerprintEnrollOptions import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintManager.CryptoObject import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.CancellationSignal import android.os.Handler import androidx.test.core.app.ApplicationProvider import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository -import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.model.Default import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason @@ -38,8 +43,7 @@ import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAtt import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData import com.android.settings.password.ChooseLockSettingsHelper import com.android.systemui.biometrics.shared.model.FingerprintSensor -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.Flow @@ -85,7 +89,18 @@ class FingerprintManagerInteractorTest { @Before fun setup() { - val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON) + val sensor = + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() val fingerprintSensorRepository = object : FingerprintSensorRepository { override val fingerprintSensor: Flow = flowOf(sensor) @@ -135,7 +150,7 @@ class FingerprintManagerInteractorTest { listOf( Fingerprint("Finger 1,", 2, 3L), Fingerprint("Finger 2,", 3, 3L), - Fingerprint("Finger 3,", 4, 3L) + Fingerprint("Finger 3,", 4, 3L), ) val fingerprintList2: List = fingerprintList1.plus( @@ -160,7 +175,7 @@ class FingerprintManagerInteractorTest { gateKeeperPasswordProvider.requestGatekeeperHat( any(Intent::class.java), anyLong(), - anyInt() + anyInt(), ) ) .thenReturn(byteArray) @@ -223,7 +238,7 @@ class FingerprintManagerInteractorTest { removalCallback.value.onRemovalError( fingerprintToRemove, 100, - "Oh no, we couldn't find that one" + "Oh no, we couldn't find that one", ) runCurrent() @@ -260,7 +275,7 @@ class FingerprintManagerInteractorTest { any(CancellationSignal::class.java), capture(authCallback), nullable(Handler::class.java), - anyInt() + anyInt(), ) authCallback.value.onAuthenticationSucceeded( FingerprintManager.AuthenticationResult(null, fingerprint, 1, false) @@ -287,7 +302,7 @@ class FingerprintManagerInteractorTest { any(CancellationSignal::class.java), capture(authCallback), nullable(Handler::class.java), - anyInt() + anyInt(), ) authCallback.value.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "Lockout!!") diff --git a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt index 829716e0e2d..5fcd772cdcc 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt @@ -18,6 +18,11 @@ package com.android.settings.fingerprint2.enrollment.viewmodel import android.content.Context import android.content.res.Configuration +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.view.Surface import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.test.core.app.ApplicationProvider @@ -33,9 +38,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.testutils2.FakeFingerprintManagerInteractor -import com.android.systemui.biometrics.shared.model.FingerprintSensor -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -94,7 +97,19 @@ class FingerprintEnrollFindSensorViewModelV2Test { ) .create(FingerprintGatekeeperViewModel::class.java) - val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON) + val sensor = + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) navigationViewModel = FingerprintNavigationViewModel( @@ -159,12 +174,17 @@ class FingerprintEnrollFindSensorViewModelV2Test { fun udfpsLottieInfo() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5, - FingerprintSensorType.UDFPS_OPTICAL, - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() var udfpsLottieInfo: Boolean? = null val job = launch { underTest.udfpsLottieInfo.collect { udfpsLottieInfo = it } } @@ -218,7 +238,17 @@ class FingerprintEnrollFindSensorViewModelV2Test { fun rfpsAnimation() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor(0 /* sensorId */, SensorStrength.STRONG, 5, FingerprintSensorType.REAR) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_REAR, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() var showRfpsAnimation: Boolean? = null val job = launch { underTest.showRfpsAnimation.collect { showRfpsAnimation = it } } @@ -232,12 +262,17 @@ class FingerprintEnrollFindSensorViewModelV2Test { fun showPrimaryButton_ifUdfps() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5, - FingerprintSensorType.UDFPS_OPTICAL, - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() var showPrimaryButton: Boolean? = null val job = launch { underTest.showPrimaryButton.collect { showPrimaryButton = it } } diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt index 696e4fa6bbb..ad025cfb1c3 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt @@ -16,6 +16,11 @@ package com.android.settings.fingerprint2.ui.enrollment.viewmodel +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.android.settings.biometrics.fingerprint2.lib.model.Default import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel @@ -26,6 +31,7 @@ import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.systemui.biometrics.shared.model.FingerprintSensor import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher @@ -68,8 +74,18 @@ class FingerprintEnrollConfirmationViewModelTest { @Test fun testCanEnrollFingerprints() = testScope.runTest { - fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor(0 /* sensorId */, SensorStrength.STRONG, 5, FingerprintSensorType.REAR) + fakeFingerprintManagerInteractor.sensorProp = FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf() fakeFingerprintManagerInteractor.enrollableFingerprints = 5 diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt index 4678da16f40..5a304330a16 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt @@ -16,6 +16,11 @@ package com.android.settings.fingerprint2.ui.enrollment.viewmodel +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.android.settings.biometrics.fingerprint2.lib.model.Default import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel @@ -26,11 +31,8 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo -import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState import com.android.settings.testutils2.FakeFingerprintManagerInteractor -import com.android.systemui.biometrics.shared.model.FingerprintSensor -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -72,7 +74,18 @@ class FingerprintEnrollEnrollingViewModelTest { fakeFingerprintManagerInteractor, ) .create(FingerprintGatekeeperViewModel::class.java) - val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON) + val sensor = + FingerprintSensorPropertiesInternal( + 1 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) navigationViewModel = diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt index 6577c950bb0..1618e16d904 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt @@ -16,6 +16,11 @@ package com.android.settings.fingerprint2.ui.settings +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData @@ -23,9 +28,7 @@ import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.Finger import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.PreferenceViewModel import com.android.settings.testutils2.FakeFingerprintManagerInteractor -import com.android.systemui.biometrics.shared.model.FingerprintSensor -import com.android.systemui.biometrics.shared.model.FingerprintSensorType -import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest @@ -96,12 +99,18 @@ class FingerprintSettingsViewModelTest { fun authenticate_DoesNotRun_ifOptical() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5 /* maxEnrollmentsPerUser */, - FingerprintSensorType.UDFPS_OPTICAL, - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(FingerprintData("a", 1, 3L)) @@ -132,12 +141,18 @@ class FingerprintSettingsViewModelTest { fun authenticate_DoesNotRun_ifUltrasonic() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5 /* maxEnrollmentsPerUser */, - FingerprintSensorType.UDFPS_ULTRASONIC, - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(FingerprintData("a", 1, 3L)) @@ -166,12 +181,18 @@ class FingerprintSettingsViewModelTest { fun authenticate_DoesRun_ifNotUdfps() = testScope.runTest { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5 /* maxEnrollmentsPerUser */, - FingerprintSensorType.POWER_BUTTON - ) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(FingerprintData("a", 1, 3L)) val success = FingerprintAuthAttemptModel.Success(1) @@ -324,8 +345,7 @@ class FingerprintSettingsViewModelTest { runCurrent() assertThat(authAttempt).isEqualTo(success) - fakeFingerprintManagerInteractor.authenticateAttempt = - FingerprintAuthAttemptModel.Success(10) + fakeFingerprintManagerInteractor.authenticateAttempt = FingerprintAuthAttemptModel.Success(10) underTest.shouldAuthenticate(false) advanceTimeBy(400) runCurrent() @@ -372,14 +392,19 @@ class FingerprintSettingsViewModelTest { private fun setupAuth(): MutableList { fakeFingerprintManagerInteractor.sensorProp = - FingerprintSensor( - 0 /* sensorId */, - SensorStrength.STRONG, - 5 /* maxEnrollmentsPerUser */, - FingerprintSensorType.POWER_BUTTON - ) - val fingerprints = - mutableListOf(FingerprintData("a", 1, 3L), FingerprintData("b", 2, 5L)) + FingerprintSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf(), + FingerprintSensorProperties.TYPE_POWER_BUTTON, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf(SensorLocationInternal.DEFAULT), + ) + .toFingerprintSensor() + + val fingerprints = mutableListOf(FingerprintData("a", 1, 3L), FingerprintData("b", 2, 5L)) fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = fingerprints val success = FingerprintAuthAttemptModel.Success(1) fakeFingerprintManagerInteractor.authenticateAttempt = success From 2b093ade89bc426a7d7ce61550b684ad9d6e9847 Mon Sep 17 00:00:00 2001 From: Chelsea Hao Date: Mon, 8 Apr 2024 06:27:24 +0000 Subject: [PATCH 02/14] Auto on string update. Change-Id: Ifbf090004b37762943128e71849667d7e9b05210 Flag: NA Bug: 332982362 --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 660cd96c7ea..2c4c6724bfa 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1828,11 +1828,11 @@ When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices - When Bluetooth is on, your device can communicate with other nearby Bluetooth devices. Features like Quick Share, Find My Device, and device location use Bluetooth. + When Bluetooth is on, your device can communicate with other nearby Bluetooth devices. Features like Quick Share and Find My Device use Bluetooth. When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices.\n\nTo improve device experience, apps and services can still scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services. You can change this in Bluetooth scanning settings. - When Bluetooth is on, your device can communicate with other nearby Bluetooth devices. Features like Quick Share, Find My Device, and device location use Bluetooth.\n\nApps and services can still scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services. You can change this in Bluetooth scanning settings. + When Bluetooth is on, your device can communicate with other nearby Bluetooth devices. Features like Quick Share and Find My Device use Bluetooth.\n\nApps and services can still scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services. You can change this in Bluetooth scanning settings. Change From b67133310accf4e034864cfeb3d2b8d97e4f7161 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 10 Apr 2024 17:47:07 +0800 Subject: [PATCH 03/14] Move nfc_detection_point.png to res/drawable From res/drawable-nodpi, for easier overlay. Bug: 333631061 Test: visual - on NFC Change-Id: I5b83a399d6ba10644843c816fa369efef869a006 --- .../nfc_detection_point.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename res/{drawable-nodpi => drawable}/nfc_detection_point.png (100%) diff --git a/res/drawable-nodpi/nfc_detection_point.png b/res/drawable/nfc_detection_point.png similarity index 100% rename from res/drawable-nodpi/nfc_detection_point.png rename to res/drawable/nfc_detection_point.png From e9a2953fa27a8a44d742f604db5d269648ea58c2 Mon Sep 17 00:00:00 2001 From: David Liu Date: Wed, 10 Apr 2024 18:31:05 +0000 Subject: [PATCH 04/14] Support top level Notifications for the search. Fix: 328150708 Test: manual test Change-Id: I0dedff5ab82123c0164a03726e74e75335f55415 --- res/xml/configure_notification_settings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index 4703a1464a3..d9fccc4a04d 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -16,7 +16,8 @@ + android:title="@string/configure_notification_settings" + android:key="configure_notification_settings"> Date: Wed, 10 Apr 2024 19:27:55 +0000 Subject: [PATCH 05/14] [Flag cleanup] remove separate_accessibility_vibration_settings_fragments This bug fix associated with this flag is low risk. The flag has been soaked in the Trunkfood full for 30 days and tested by 1000+ users. Based on the flag cleanup policy, we can clean up the flag. Bug: 289967175 Flag: EXEMPT flag cleanup Test: Run the Settings app and can still see the vibration & haptics screen Change-Id: I39890a33f04b53565461ae2c6c4e63b94f205e6d --- .../VibrationIntensitySettingsFragment.java | 7 +- .../VibrationPreferenceController.java | 4 +- .../accessibility/VibrationSettings.java | 67 ++----------------- ...ibrationIntensitySettingsFragmentTest.java | 10 +-- .../VibrationPreferenceControllerTest.java | 13 +--- .../accessibility/VibrationSettingsTest.java | 11 +-- 6 files changed, 12 insertions(+), 100 deletions(-) diff --git a/src/com/android/settings/accessibility/VibrationIntensitySettingsFragment.java b/src/com/android/settings/accessibility/VibrationIntensitySettingsFragment.java index 41e81983d10..1d24ec9e2de 100644 --- a/src/com/android/settings/accessibility/VibrationIntensitySettingsFragment.java +++ b/src/com/android/settings/accessibility/VibrationIntensitySettingsFragment.java @@ -30,7 +30,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.flags.Flags; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; @@ -65,11 +64,7 @@ public class VibrationIntensitySettingsFragment extends DashboardFragment { final int supportedIntensityLevels = context.getResources().getInteger( R.integer.config_vibration_supported_intensity_levels); final boolean hasVibrator = context.getSystemService(Vibrator.class).hasVibrator(); - if (Flags.separateAccessibilityVibrationSettingsFragments()) { - return hasVibrator && supportedIntensityLevels > 1; - } else { - return false; - } + return hasVibrator && supportedIntensityLevels > 1; } @Override diff --git a/src/com/android/settings/accessibility/VibrationPreferenceController.java b/src/com/android/settings/accessibility/VibrationPreferenceController.java index d4302490b9e..092ff6945d1 100644 --- a/src/com/android/settings/accessibility/VibrationPreferenceController.java +++ b/src/com/android/settings/accessibility/VibrationPreferenceController.java @@ -29,7 +29,6 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; -import com.android.settings.flags.Flags; /** Controller for "Vibration & haptics" settings page. */ public class VibrationPreferenceController extends BasePreferenceController { @@ -66,8 +65,7 @@ public class VibrationPreferenceController extends BasePreferenceController { @Override public boolean handlePreferenceTreeClick(Preference preference) { - if (Flags.separateAccessibilityVibrationSettingsFragments() - && TextUtils.equals(preference.getKey(), getPreferenceKey())) { + if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { if (mContext.getResources().getInteger( R.integer.config_vibration_supported_intensity_levels) > 1) { launchVibrationSettingsFragment(VibrationIntensitySettingsFragment.class); diff --git a/src/com/android/settings/accessibility/VibrationSettings.java b/src/com/android/settings/accessibility/VibrationSettings.java index 4b36dde642b..48393d9394c 100644 --- a/src/com/android/settings/accessibility/VibrationSettings.java +++ b/src/com/android/settings/accessibility/VibrationSettings.java @@ -18,44 +18,23 @@ package com.android.settings.accessibility; import android.app.settings.SettingsEnums; import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; import android.os.Vibrator; -import android.provider.SearchIndexableResource; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; import androidx.annotation.VisibleForTesting; -import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.flags.Flags; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; -import java.util.ArrayList; -import java.util.List; - -/** Accessibility settings for the vibration. */ +/** + * Accessibility settings for the vibration. + */ @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class VibrationSettings extends DashboardFragment { private static final String TAG = "VibrationSettings"; - private static int getVibrationXmlResourceId(Context context) { - if (Flags.separateAccessibilityVibrationSettingsFragments()) { - return R.xml.accessibility_vibration_settings; - } - final int supportedIntensities = context.getResources().getInteger( - R.integer.config_vibration_supported_intensity_levels); - return supportedIntensities > 1 - ? R.xml.accessibility_vibration_intensity_settings - : R.xml.accessibility_vibration_settings; - - } - @Override public int getMetricsCategory() { return SettingsEnums.ACCESSIBILITY_VIBRATION; @@ -68,7 +47,7 @@ public class VibrationSettings extends DashboardFragment { @Override protected int getPreferenceScreenResId() { - return getVibrationXmlResourceId(getContext()); + return R.xml.accessibility_vibration_settings; } @Override @@ -76,53 +55,19 @@ public class VibrationSettings extends DashboardFragment { return TAG; } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - if (Flags.separateAccessibilityVibrationSettingsFragments()) { - return super.onCreateView(inflater, container, savedInstanceState); - } - final View view = super.onCreateView(inflater, container, savedInstanceState); - final RecyclerView rv = getListView(); - final Resources res = view.getResources(); - final int supportedIntensities = res.getInteger( - R.integer.config_vibration_supported_intensity_levels); - if (rv != null && supportedIntensities > 1) { - final int bottom_padding = res.getDimensionPixelSize( - com.android.settingslib.widget.theme.R.dimen.settingslib_listPreferredItemPaddingEnd); - rv.setPaddingRelative(rv.getPaddingStart(), rv.getPaddingTop(), rv.getPaddingEnd(), - rv.getPaddingBottom() + bottom_padding); - } - return view; - } - @VisibleForTesting static boolean isPageSearchEnabled(Context context) { final int supportedIntensityLevels = context.getResources().getInteger( R.integer.config_vibration_supported_intensity_levels); final boolean hasVibrator = context.getSystemService(Vibrator.class).hasVibrator(); - if (Flags.separateAccessibilityVibrationSettingsFragments()) { - return hasVibrator && supportedIntensityLevels == 1; - } else { - return hasVibrator; - } + return hasVibrator && supportedIntensityLevels == 1; } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { + new BaseSearchIndexProvider(R.xml.accessibility_vibration_settings) { @Override protected boolean isPageSearchEnabled(Context context) { return VibrationSettings.isPageSearchEnabled(context); } - - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - final List resourceData = new ArrayList<>(); - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = getVibrationXmlResourceId(context); - resourceData.add(sir); - return resourceData; - } }; } diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensitySettingsFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensitySettingsFragmentTest.java index 045c9dbcc63..da020c4f5df 100644 --- a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensitySettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensitySettingsFragmentTest.java @@ -17,35 +17,27 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.res.Resources; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.flags.Flags; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; /** Tests for {@link VibrationIntensitySettingsFragment}. */ @RunWith(RobolectricTestRunner.class) -@RequiresFlagsEnabled(Flags.FLAG_SEPARATE_ACCESSIBILITY_VIBRATION_SETTINGS_FRAGMENTS) public class VibrationIntensitySettingsFragmentTest { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private Context mContext; private Resources mResources; private VibrationIntensitySettingsFragment mFragment; diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java index cf33173e664..59ed48638d0 100644 --- a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java @@ -18,7 +18,9 @@ package com.android.settings.accessibility; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -29,9 +31,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.os.Vibrator; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import androidx.preference.Preference; @@ -39,10 +38,8 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.flags.Flags; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -51,10 +48,6 @@ import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class VibrationPreferenceControllerTest { - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String PREFERENCE_KEY = "preference_key"; private static final int OFF = 0; private static final int ON = 1; @@ -130,7 +123,6 @@ public class VibrationPreferenceControllerTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_SEPARATE_ACCESSIBILITY_VIBRATION_SETTINGS_FRAGMENTS) public void handlePreferenceTreeClick_oneIntensityLevel_opensVibrationSettings() { when(mResources.getInteger(R.integer.config_vibration_supported_intensity_levels)) .thenReturn(1); @@ -143,7 +135,6 @@ public class VibrationPreferenceControllerTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_SEPARATE_ACCESSIBILITY_VIBRATION_SETTINGS_FRAGMENTS) public void handlePreferenceTreeClick_multipleIntensityLevels_opensVibrationIntensity() { when(mResources.getInteger(R.integer.config_vibration_supported_intensity_levels)) .thenReturn(2); diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationSettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationSettingsTest.java index f5ea39e5824..d4ff662c3a2 100644 --- a/tests/robotests/src/com/android/settings/accessibility/VibrationSettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/VibrationSettingsTest.java @@ -17,35 +17,26 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.res.Resources; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.flags.Flags; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; /** Tests for {@link VibrationSettings} fragment. */ @RunWith(RobolectricTestRunner.class) -@RequiresFlagsEnabled(Flags.FLAG_SEPARATE_ACCESSIBILITY_VIBRATION_SETTINGS_FRAGMENTS) public class VibrationSettingsTest { - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private Context mContext; private Resources mResources; private VibrationSettings mFragment; From eab9765e526e97b16e20e2ee954998a104508a13 Mon Sep 17 00:00:00 2001 From: Charlotte Lu Date: Thu, 11 Apr 2024 18:36:23 +0800 Subject: [PATCH 06/14] [WIFI-Enterprise] Change the summary for Certificate Details. Test: Visual Test Fix: 333850992 Change-Id: If2d8743f788a0732267ac6576f77bea41b4e2e84 --- .../CertificateDetailsPreferenceController.kt | 60 +++++++++++++++---- ...tificateDetailsPreferenceControllerTest.kt | 37 +++++++++--- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceController.kt b/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceController.kt index 8e1fa23fdb8..80e41e2fbd3 100644 --- a/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceController.kt +++ b/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceController.kt @@ -37,6 +37,9 @@ import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.wifi.flags.Flags import com.android.wifitrackerlib.WifiEntry +import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_CERTIFICATE_PINNING +import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA +import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE import java.security.KeyStore import java.security.cert.X509Certificate @@ -44,15 +47,13 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St ComposePreferenceController(context, preferenceKey) { private lateinit var wifiEntry: WifiEntry - lateinit var certificateAliases: String - lateinit var certX509: X509Certificate fun setWifiEntry(entry: WifiEntry) { wifiEntry = entry } override fun getAvailabilityStatus(): Int { - return if (Flags.androidVWifiApi() && getCertX509(wifiEntry)) AVAILABLE + return if (Flags.androidVWifiApi() && isCertificateDetailsAvailable(wifiEntry)) AVAILABLE else CONDITIONALLY_UNAVAILABLE } @@ -64,26 +65,52 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St @Composable fun CertificateDetails() { val context = LocalContext.current + + val validationMethod = wifiEntry.certificateInfo!!.validationMethod + val certificateDetailsSummary = when (validationMethod) { + CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE -> + stringResource(R.string.wifi_certificate_summary_system) + + CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA -> { + val aliasesSize = wifiEntry.certificateInfo?.caCertificateAliases?.size + if (aliasesSize == 1) stringResource(R.string.one_cacrt) + else + String.format( + stringResource(R.string.wifi_certificate_summary_Certificates), + aliasesSize + ) + } + + else -> stringResource(R.string.wifi_certificate_summary_pinning) + } + Preference(object : PreferenceModel { override val title = stringResource(com.android.internal.R.string.ssl_certificate) - override val summary = { certificateAliases } - override val onClick: () -> Unit = { createCertificateDetailsDialog(context, certX509) } + override val summary = { certificateDetailsSummary } + override val onClick: () -> Unit = { + if (validationMethod == CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA) + getCertX509(wifiEntry)?.let { + createCertificateDetailsDialog( + context, + it + ) + } + } }) } - private fun getCertX509(wifiEntry: WifiEntry): Boolean { - certificateAliases = - wifiEntry.wifiConfiguration?.enterpriseConfig?.caCertificateAliases?.get(0) - ?: return false + private fun getCertX509(wifiEntry: WifiEntry): X509Certificate? { + val certificateAliases = + wifiEntry.certificateInfo?.caCertificateAliases?.get(0) + ?: return null return try { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(AndroidKeyStoreLoadStoreParameter(KeyProperties.NAMESPACE_WIFI)) val cert = keyStore.getCertificate(certificateAliases) - certX509 = KeyChain.toCertificate(cert.encoded) - true + KeyChain.toCertificate(cert.encoded) } catch (e: Exception) { Log.e(TAG, "Failed to open Android Keystore.", e) - false + null } } @@ -124,6 +151,15 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false) } + private fun isCertificateDetailsAvailable(wifiEntry: WifiEntry): Boolean { + val validationMethod = wifiEntry.certificateInfo?.validationMethod + return validationMethod in listOf( + CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE, + CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA, + CERTIFICATE_VALIDATION_METHOD_USING_CERTIFICATE_PINNING + ) + } + companion object { const val TAG = "CertificateDetailsPreferenceController" } diff --git a/tests/spa_unit/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceControllerTest.kt index 149937496ff..d0119dfcc05 100644 --- a/tests/spa_unit/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceControllerTest.kt +++ b/tests/spa_unit/src/com/android/settings/wifi/details2/CertificateDetailsPreferenceControllerTest.kt @@ -17,6 +17,7 @@ package com.android.settings.wifi.details2 import android.content.Context +import android.platform.test.annotations.RequiresFlagsEnabled import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.test.assertIsDisplayed @@ -24,13 +25,15 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import java.security.cert.X509Certificate +import com.android.settings.R +import com.android.wifitrackerlib.WifiEntry import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.doNothing +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.whenever @@ -40,21 +43,26 @@ class CertificateDetailsPreferenceControllerTest { @get:Rule val composeTestRule = createComposeRule() - private val mockCertX509 = mock {} - private val context: Context = spy(ApplicationProvider.getApplicationContext()) { doNothing().whenever(mock).startActivity(any()) } - private val controller = CertificateDetailsPreferenceController(context, TEST_KEY) + private val mockCertificateInfo = mock { + it.validationMethod = + WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA + it.caCertificateAliases = arrayOf(MOCK_CA) + } + private val mockWifiEntry = + mock { on { certificateInfo } doReturn mockCertificateInfo } + @Before fun setUp() { - controller.certificateAliases = MOCK_CA - controller.certX509 = mockCertX509 + controller.setWifiEntry(mockWifiEntry) } @Test + @RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API) fun title_isDisplayed() { composeTestRule.setContent { CompositionLocalProvider(LocalContext provides context) { @@ -62,8 +70,21 @@ class CertificateDetailsPreferenceControllerTest { } } - composeTestRule.onNodeWithText(context.getString(com.android.internal.R.string.ssl_certificate)) - .assertIsDisplayed() + composeTestRule.onNodeWithText( + context.getString(com.android.internal.R.string.ssl_certificate) + ).assertIsDisplayed() + } + + @Test + @RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API) + fun one_caCertificate_summary() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.Content() + } + } + + composeTestRule.onNodeWithText(context.getString(R.string.one_cacrt)).assertIsDisplayed() } private companion object { From a7603d2b434e2907bdb1b246bcf22298bd4f91d6 Mon Sep 17 00:00:00 2001 From: josephpv Date: Fri, 22 Mar 2024 19:25:57 +0000 Subject: [PATCH 07/14] Handle startProfile failure during creation of private space This includes to verify return value of startProfile to check if profile is started successfully. If startProfile failed for any reason then delete the created profile and return false for createPrivateProfile(). Bug: 313926659 Test: atest PrivateSpaceMaintainerTest Change-Id: I493cb3a41cef8bdc1be42fe328c4f7bd04944b94 --- .../privatespace/PrivateSpaceMaintainer.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index e219c078bce..6d07305e375 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -112,11 +112,10 @@ public class PrivateSpaceMaintainer { registerBroadcastReceiver(); - try { - //TODO(b/313926659): To check and handle failure of startProfile - mActivityManager.startProfile(mUserHandle); - } catch (IllegalArgumentException e) { - Log.e(TAG, "Unexpected that " + mUserHandle.getIdentifier() + " is not a profile"); + if (!startProfile()) { + // TODO(b/333884792): Add test to mock when startProfile fails. + Log.e(TAG, "profile not started, created profile is deleted"); + deletePrivateSpace(); return false; } @@ -314,6 +313,16 @@ public class PrivateSpaceMaintainer { return false; } + @GuardedBy("this") + private boolean startProfile() { + try { + return mActivityManager.startProfile(mUserHandle); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unexpected that " + mUserHandle.getIdentifier() + " is not a profile"); + } + return false; + } + @GuardedBy("this") private void resetPrivateSpaceSettings() { setHidePrivateSpaceEntryPointSetting(HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL); From cace44f497ba9f3fae23ad93865914f1e311fdd6 Mon Sep 17 00:00:00 2001 From: Manish Singh Date: Tue, 9 Apr 2024 15:41:26 +0000 Subject: [PATCH 08/14] Fix location services for all profiles Bug: 330538899 Bug: 333507072 Test: atest LocationInjectedServicesPreferenceControllerTest Test: manual Change-Id: Ia42e59b73b9b7c84ecb89082e968b801e1fd1302 --- res/xml/location_services_private_profile.xml | 22 +++++ ...ProfileSelectLocationServicesFragment.java | 3 +- ...jectedServiceBasePreferenceController.java | 25 +++++- ...ForPrivateProfilePreferenceController.java | 66 ++++++++++++++ ...edServicesForWorkPreferenceController.java | 4 +- .../LocationServicesForPrivateProfile.java | 48 ++++++++++ ...ectedServicesPreferenceControllerTest.java | 88 ++++++++++++++++++- 7 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 res/xml/location_services_private_profile.xml create mode 100644 src/com/android/settings/location/LocationInjectedServicesForPrivateProfilePreferenceController.java create mode 100644 src/com/android/settings/location/LocationServicesForPrivateProfile.java diff --git a/res/xml/location_services_private_profile.xml b/res/xml/location_services_private_profile.xml new file mode 100644 index 00000000000..d739e15542b --- /dev/null +++ b/res/xml/location_services_private_profile.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationServicesFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationServicesFragment.java index 8e48c7bcaa5..ddcc27f16be 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationServicesFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectLocationServicesFragment.java @@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.location.LocationServices; +import com.android.settings.location.LocationServicesForPrivateProfile; import com.android.settings.location.LocationServicesForWork; /** @@ -34,7 +35,7 @@ public class ProfileSelectLocationServicesFragment extends ProfileSelectFragment null /* bundle */, LocationServices::new, LocationServicesForWork::new, - LocationServices::new); + LocationServicesForPrivateProfile::new); } @Override diff --git a/src/com/android/settings/location/LocationInjectedServiceBasePreferenceController.java b/src/com/android/settings/location/LocationInjectedServiceBasePreferenceController.java index 5ee83ddaef4..bab3316432c 100644 --- a/src/com/android/settings/location/LocationInjectedServiceBasePreferenceController.java +++ b/src/com/android/settings/location/LocationInjectedServiceBasePreferenceController.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.location.SettingInjectorService; import android.os.UserHandle; +import android.util.ArraySet; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -32,6 +33,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settingslib.core.lifecycle.LifecycleObserver; import java.util.List; @@ -110,13 +112,28 @@ public abstract class LocationInjectedServiceBasePreferenceController } protected Map> getLocationServices() { + ArraySet userHandles = new ArraySet<>(); + userHandles.add(UserHandle.of(UserHandle.myUserId())); + // If location access is locked down by device policy then we only show injected settings // for the primary profile. - final int profileUserId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId()); + final int managedProfileId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId()); + if (managedProfileId != UserHandle.USER_NULL + && mLocationEnabler.getShareLocationEnforcedAdmin(managedProfileId) == null) { + userHandles.add(UserHandle.of(managedProfileId)); + } + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enablePrivateSpaceFeatures() + && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) { + final UserHandle privateProfile = Utils.getProfileOfType(mUserManager, + ProfileSelectFragment.ProfileType.PRIVATE); + if (privateProfile != null && mLocationEnabler + .getShareLocationEnforcedAdmin(privateProfile.getIdentifier()) == null) { + userHandles.add(privateProfile); + } + } return mInjector.getInjectedSettings(mFragment.getPreferenceManager().getContext(), - (profileUserId != UserHandle.USER_NULL - && mLocationEnabler.getShareLocationEnforcedAdmin(profileUserId) != null) - ? UserHandle.myUserId() : UserHandle.USER_CURRENT); + userHandles); } } diff --git a/src/com/android/settings/location/LocationInjectedServicesForPrivateProfilePreferenceController.java b/src/com/android/settings/location/LocationInjectedServicesForPrivateProfilePreferenceController.java new file mode 100644 index 00000000000..7266b2043ae --- /dev/null +++ b/src/com/android/settings/location/LocationInjectedServicesForPrivateProfilePreferenceController.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.location; + +import android.content.Context; +import android.os.UserHandle; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.Utils; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; +import com.android.settings.widget.RestrictedAppPreference; + +import java.util.List; +import java.util.Map; + +/** + * Retrieve the Location Services used in private profile user. + */ +public class LocationInjectedServicesForPrivateProfilePreferenceController extends + LocationInjectedServiceBasePreferenceController { + public LocationInjectedServicesForPrivateProfilePreferenceController( + Context context, String key) { + super(context, key); + } + + @Override + protected void injectLocationServices(PreferenceScreen screen) { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures() + || !android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) { + return; + } + final UserHandle privateProfile = Utils.getProfileOfType(mUserManager, + ProfileSelectFragment.ProfileType.PRIVATE); + if (privateProfile == null) { + return; + } + final Map> prefs = getLocationServices(); + for (Map.Entry> entry : prefs.entrySet()) { + for (Preference pref : entry.getValue()) { + if (pref instanceof RestrictedAppPreference) { + ((RestrictedAppPreference) pref).checkRestrictionAndSetDisabled(); + } + } + if (entry.getKey() == privateProfile.getIdentifier()) { + LocationSettings.addPreferencesSorted(entry.getValue(), screen); + } + } + } +} diff --git a/src/com/android/settings/location/LocationInjectedServicesForWorkPreferenceController.java b/src/com/android/settings/location/LocationInjectedServicesForWorkPreferenceController.java index a8a13b3ca76..f9a4def5c6f 100644 --- a/src/com/android/settings/location/LocationInjectedServicesForWorkPreferenceController.java +++ b/src/com/android/settings/location/LocationInjectedServicesForWorkPreferenceController.java @@ -22,6 +22,7 @@ import android.os.UserHandle; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import com.android.settings.Utils; import com.android.settings.widget.RestrictedAppPreference; import java.util.List; @@ -40,6 +41,7 @@ public class LocationInjectedServicesForWorkPreferenceController extends @Override protected void injectLocationServices(PreferenceScreen screen) { + final int managedProfileId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId()); final Map> prefs = getLocationServices(); for (Map.Entry> entry : prefs.entrySet()) { for (Preference pref : entry.getValue()) { @@ -47,7 +49,7 @@ public class LocationInjectedServicesForWorkPreferenceController extends ((RestrictedAppPreference) pref).checkRestrictionAndSetDisabled(); } } - if (entry.getKey() != UserHandle.myUserId()) { + if (entry.getKey() == managedProfileId) { LocationSettings.addPreferencesSorted(entry.getValue(), screen); } } diff --git a/src/com/android/settings/location/LocationServicesForPrivateProfile.java b/src/com/android/settings/location/LocationServicesForPrivateProfile.java new file mode 100644 index 00000000000..0c8ee6f5fa4 --- /dev/null +++ b/src/com/android/settings/location/LocationServicesForPrivateProfile.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.location; + +import android.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; + +public class LocationServicesForPrivateProfile extends DashboardFragment { + private static final String TAG = "LocationServicesForPrivateProfile"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.LOCATION_SERVICES_FOR_PRIVATE_PROFILE; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.location_services_private_profile; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(LocationInjectedServicesForPrivateProfilePreferenceController.class).init(this); + } +} diff --git a/tests/robotests/src/com/android/settings/location/LocationInjectedServicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationInjectedServicesPreferenceControllerTest.java index 43b9839a801..375e1520096 100644 --- a/tests/robotests/src/com/android/settings/location/LocationInjectedServicesPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/location/LocationInjectedServicesPreferenceControllerTest.java @@ -31,8 +31,10 @@ import android.content.Context; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.util.ArrayMap; +import android.util.ArraySet; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; @@ -50,6 +52,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -65,6 +68,8 @@ import java.util.Map; public class LocationInjectedServicesPreferenceControllerTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final String KEY_LOCATION_SERVICES = "location_service"; @@ -140,8 +145,13 @@ public class LocationInjectedServicesPreferenceControllerTest { when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName); mController.displayPreference(mScreen); + + ArgumentCaptor> profilesArgumentCaptor = + ArgumentCaptor.forClass(ArraySet.class); verify(mSettingsInjector).getInjectedSettings( - any(Context.class), eq(UserHandle.myUserId())); + any(Context.class), profilesArgumentCaptor.capture()); + assertThat(profilesArgumentCaptor.getValue()) + .doesNotContain(UserHandle.of(fakeWorkProfileId)); } @Test @@ -149,6 +159,9 @@ public class LocationInjectedServicesPreferenceControllerTest { final int fakeWorkProfileId = 123; ShadowUserManager.getShadow().setProfileIdsWithDisabled( new int[]{UserHandle.myUserId(), fakeWorkProfileId}); + ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); + ShadowUserManager.getShadow().addProfile(new UserInfo(fakeWorkProfileId, "", + UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_PROFILE)); // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return null. // Empty enforcing users. @@ -159,8 +172,77 @@ public class LocationInjectedServicesPreferenceControllerTest { enforcingUsers); mController.displayPreference(mScreen); + + ArgumentCaptor> profilesArgumentCaptor = + ArgumentCaptor.forClass(ArraySet.class); verify(mSettingsInjector).getInjectedSettings( - any(Context.class), eq(UserHandle.USER_CURRENT)); + any(Context.class), profilesArgumentCaptor.capture()); + assertThat(profilesArgumentCaptor.getValue()).contains(UserHandle.of(fakeWorkProfileId)); + } + + @Test + public void privateProfileDisallowShareLocationOn_getParentUserLocationServicesOnly() { + mSetFlagsRule.enableFlags( + android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES, + android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE); + final int fakePrivateProfileId = 123; + ShadowUserManager.getShadow().setProfileIdsWithDisabled( + new int[]{UserHandle.myUserId(), fakePrivateProfileId}); + ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); + ShadowUserManager.getShadow().setPrivateProfile(fakePrivateProfileId, "private", 0); + ShadowUserManager.getShadow().addUserProfile(UserHandle.of(fakePrivateProfileId)); + + // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return non-null. + final List enforcingUsers = new ArrayList<>(); + enforcingUsers.add(new UserManager.EnforcingUser(fakePrivateProfileId, + UserManager.RESTRICTION_SOURCE_DEVICE_OWNER)); + final ComponentName componentName = new ComponentName("test", "test"); + // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null. + ShadowUserManager.getShadow().setUserRestrictionSources( + UserManager.DISALLOW_SHARE_LOCATION, + UserHandle.of(fakePrivateProfileId), + enforcingUsers); + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName); + + mController.displayPreference(mScreen); + + ArgumentCaptor> profilesArgumentCaptor = + ArgumentCaptor.forClass(ArraySet.class); + verify(mSettingsInjector).getInjectedSettings( + any(Context.class), profilesArgumentCaptor.capture()); + assertThat(profilesArgumentCaptor.getValue()) + .doesNotContain(UserHandle.of(fakePrivateProfileId)); + } + + @Test + public void privateProfileDisallowShareLocationOff_getAllUserLocationServices() { + mSetFlagsRule.enableFlags( + android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES, + android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE); + final int fakePrivateProfileId = 123; + ShadowUserManager.getShadow().setProfileIdsWithDisabled( + new int[]{UserHandle.myUserId(), fakePrivateProfileId}); + ShadowUserManager.getShadow().addProfile(new UserInfo(UserHandle.myUserId(), "", 0)); + ShadowUserManager.getShadow().setPrivateProfile(fakePrivateProfileId, "private", 0); + ShadowUserManager.getShadow().addUserProfile(UserHandle.of(fakePrivateProfileId)); + + // Mock RestrictedLockUtils.checkIfRestrictionEnforced and let it return null. + // Empty enforcing users. + final List enforcingUsers = new ArrayList<>(); + ShadowUserManager.getShadow().setUserRestrictionSources( + UserManager.DISALLOW_SHARE_LOCATION, + UserHandle.of(fakePrivateProfileId), + enforcingUsers); + + mController.displayPreference(mScreen); + + ArgumentCaptor> profilesArgumentCaptor = + ArgumentCaptor.forClass(ArraySet.class); + verify(mSettingsInjector).getInjectedSettings( + any(Context.class), profilesArgumentCaptor.capture()); + assertThat(profilesArgumentCaptor.getValue()).contains(UserHandle.of(fakePrivateProfileId)); } @Test @@ -180,7 +262,7 @@ public class LocationInjectedServicesPreferenceControllerTest { final Map> map = new ArrayMap<>(); map.put(UserHandle.myUserId(), preferences); doReturn(map).when(mSettingsInjector) - .getInjectedSettings(any(Context.class), anyInt()); + .getInjectedSettings(any(Context.class), any(ArraySet.class)); ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{UserHandle.myUserId()}); final int userId = UserHandle.myUserId(); From 2fc40e8be7dba9c5fb54217195aeb34a2faba56e Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Wed, 10 Apr 2024 13:38:54 -0700 Subject: [PATCH 09/14] Make sure policy transparency is applied in all cases There are some cases where policy transparency is not correctly showing up (e.g. on the main setting screen for the primary provider). This makes sure policy transparency is fully applied to the end user. Test: manual on device Bug: 333597574 Change-Id: I8d6a4c60e40bd2e639127777efdb04f1035c24bc --- .../credentials/DefaultCombinedPicker.java | 47 ++++++++++++------- .../DefaultCombinedPreferenceController.java | 16 ++++++- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java index ff3b5c74f2b..6fdcf675e9f 100644 --- a/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java +++ b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java @@ -41,8 +41,8 @@ import android.text.Html; import android.text.TextUtils; import android.util.Log; -import androidx.annotation.Nullable; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.preference.Preference; @@ -125,12 +125,12 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { protected CharSequence getPositiveButtonText() { final Bundle bundle = getArguments(); if (TextUtils.isEmpty(bundle.getString(EXTRA_KEY))) { - return getContext().getString( - R.string.credman_confirmation_turn_off_positive_button); + return getContext() + .getString(R.string.credman_confirmation_turn_off_positive_button); } - return getContext().getString( - R.string.credman_confirmation_change_provider_positive_button); + return getContext() + .getString(R.string.credman_confirmation_change_provider_positive_button); } } @@ -259,21 +259,21 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { return mCredentialManager; } - private List getAllProviders() { + private List getAllProviders(int userId) { final Context context = getContext(); final List autofillProviders = - AutofillServiceInfo.getAvailableServices(context, getUser()); + AutofillServiceInfo.getAvailableServices(context, userId); final CredentialManager service = getCredentialProviderService(); final List credManProviders = new ArrayList<>(); if (service != null) { credManProviders.addAll( service.getCredentialProviderServices( - getUser(), + userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN)); } - final String selectedAutofillProvider = getSelectedAutofillProvider(context, getUser()); + final String selectedAutofillProvider = getSelectedAutofillProvider(context, userId); return CombinedProviderInfo.buildMergedList( autofillProviders, credManProviders, selectedAutofillProvider); } @@ -285,7 +285,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { protected List getCandidates() { final Context context = getContext(); - final List allProviders = getAllProviders(); + final int userId = getUser(); + final List allProviders = getAllProviders(userId); final List candidates = new ArrayList<>(); for (CombinedProviderInfo cpi : allProviders) { @@ -295,10 +296,10 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { if (brandingService != null) { candidates.add( new CredentialManagerDefaultAppInfo( - context, mPm, getUser(), brandingService, cpi)); + context, mPm, userId, brandingService, cpi)); } else if (appInfo != null) { candidates.add( - new CredentialManagerDefaultAppInfo(context, mPm, getUser(), appInfo, cpi)); + new CredentialManagerDefaultAppInfo(context, mPm, userId, appInfo, cpi)); } } @@ -361,9 +362,23 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { @Override protected String getDefaultKey() { - final CombinedProviderInfo topProvider = - CombinedProviderInfo.getTopProvider(getAllProviders()); - return topProvider == null ? "" : topProvider.getApplicationInfo().packageName; + final int userId = getUser(); + final @Nullable CombinedProviderInfo topProvider = + CombinedProviderInfo.getTopProvider(getAllProviders(userId)); + + if (topProvider != null) { + // Apply device admin restrictions to top provider. + if (topProvider.getDeviceAdminRestrictions(getContext(), userId) != null) { + return ""; + } + + ApplicationInfo appInfo = topProvider.getApplicationInfo(); + if (appInfo != null) { + return appInfo.packageName; + } + } + + return ""; } @Override @@ -392,7 +407,7 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment { @Override protected boolean setDefaultKey(String key) { // Get the list of providers and see if any match the key (package name). - final List allProviders = getAllProviders(); + final List allProviders = getAllProviders(getUser()); CombinedProviderInfo matchedProvider = null; for (CombinedProviderInfo cpi : allProviders) { if (cpi.getApplicationInfo().packageName.equals(key)) { diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java index e24e226db7a..fccd969bece 100644 --- a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java +++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java @@ -92,12 +92,14 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon @Override public void updateState(@NonNull Preference preference) { final CombinedProviderInfo topProvider = getTopProvider(); + final int userId = getUser(); + if (topProvider != null && mContext != null) { updatePreferenceForProvider( preference, topProvider.getAppName(mContext), topProvider.getSettingsSubtitle(), - topProvider.getAppIcon(mContext, getUser()), + topProvider.getAppIcon(mContext, userId), topProvider.getPackageName(), topProvider.getSettingsActivity()); } else { @@ -149,7 +151,17 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon } private @Nullable CombinedProviderInfo getTopProvider() { - return CombinedProviderInfo.getTopProvider(getAllProviders(getUser())); + final int userId = getUser(); + final @Nullable CombinedProviderInfo topProvider = + CombinedProviderInfo.getTopProvider(getAllProviders(userId)); + + // Apply device admin restrictions to top provider. + if (topProvider != null + && topProvider.getDeviceAdminRestrictions(mContext, userId) != null) { + return null; + } + + return topProvider; } @Override From 0a87a1685ed440a389595f62f5d6eab35c57caaa Mon Sep 17 00:00:00 2001 From: Charlotte Lu Date: Thu, 11 Apr 2024 19:51:25 +0800 Subject: [PATCH 10/14] [WIFI-Enterprise] Add Server name field. Test: Unit Test Fix: 333855426 Change-Id: Idfcb5f4efd36257188b04e2be7c7dc1127681b06 --- res/xml/wifi_network_details_fragment2.xml | 3 + .../details/WifiNetworkDetailsFragment.java | 3 + .../ServerNamePreferenceController.kt | 56 +++++++++++ .../ServerNamePreferenceControllerTest.kt | 92 +++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 src/com/android/settings/wifi/details2/ServerNamePreferenceController.kt create mode 100644 tests/spa_unit/src/com/android/settings/wifi/details2/ServerNamePreferenceControllerTest.kt diff --git a/res/xml/wifi_network_details_fragment2.xml b/res/xml/wifi_network_details_fragment2.xml index eacff88bdd9..518b65d8401 100644 --- a/res/xml/wifi_network_details_fragment2.xml +++ b/res/xml/wifi_network_details_fragment2.xml @@ -126,6 +126,9 @@ + { + it.domain = DOMAIN + } + + private val mockWifiEntry = + mock { on { certificateInfo } doReturn mockCertificateInfo } + + @Before + fun setUp() { + controller.setWifiEntry(mockWifiEntry) + } + + @Test + @RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API) + fun title_isDisplayed() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.Content() + } + } + + composeTestRule.onNodeWithText(context.getString(R.string.server_name_title)) + .assertIsDisplayed() + } + + @Test + @RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API) + fun summary_isDisplayed() { + composeTestRule.setContent { + CompositionLocalProvider(LocalContext provides context) { + controller.Content() + } + } + + composeTestRule.onNodeWithText(DOMAIN).assertIsDisplayed() + } + + private companion object { + const val TEST_KEY = "test_key" + const val DOMAIN = "domain" + } +} \ No newline at end of file From afdf23192162aed4cf3fbca1f73c73690ff94779 Mon Sep 17 00:00:00 2001 From: Pajace Chen Date: Fri, 12 Apr 2024 05:14:36 +0000 Subject: [PATCH 11/14] Fix failed test case in BatteryInfoTest Test: http://ab/I66000010265031461 Bug: 333857349 Change-Id: I213b4cab305a1484684f2f85294d71531bb8a048 --- .../settings/fuelgauge/BatteryInfoTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java index 7c455f805fd..d5887e6224a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java @@ -538,7 +538,7 @@ public class BatteryInfoTest { createIntentForGetBatteryInfoTest( ChargingType.WIRED, ChargingSpeed.FAST, /* batteryLevel= */ 56); var expectedStatusLabel = "Fast charging"; - var expectedRemainingLabel = "Full by 1:30 PM"; + var expectedRemainingLabel = "Full by "; var expectedChargeLabel = "56% - " + expectedStatusLabel + " - " + expectedRemainingLabel; var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); @@ -559,7 +559,7 @@ public class BatteryInfoTest { createIntentForGetBatteryInfoTest( ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 12); var expectedStatusLabel = "Charging"; - var expectedRemainingLabel = "Fully charged by 2:00 PM"; + var expectedRemainingLabel = "Fully charged by "; var expectedChargeLabel = "12% - " + expectedRemainingLabel; var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); @@ -580,7 +580,7 @@ public class BatteryInfoTest { createIntentForGetBatteryInfoTest( ChargingType.WIRED, ChargingSpeed.SLOW, /* batteryLevel= */ 18); var expectedStatusLabel = "Charging"; - var expectedRemainingLabel = "Fully charged by 3:00 PM"; + var expectedRemainingLabel = "Fully charged by"; var expectedChargeLabel = "18% - " + expectedRemainingLabel; var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); @@ -601,7 +601,7 @@ public class BatteryInfoTest { createIntentForGetBatteryInfoTest( ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 45); var expectedStatusLabel = "Charging"; - var expectedRemainingLabel = "Fully charged by 4:00 PM"; + var expectedRemainingLabel = "Fully charged by"; var expectedChargeLabel = "45% - " + expectedRemainingLabel; var currentTimeMillis = Instant.parse("2024-04-01T15:00:00Z").toEpochMilli(); @@ -622,7 +622,7 @@ public class BatteryInfoTest { createIntentForGetBatteryInfoTest( ChargingType.DOCKED, ChargingSpeed.REGULAR, /* batteryLevel= */ 66); var expectedStatusLabel = "Charging"; - var expectedRemainingLabel = "Fully charged by 2:00 PM"; + var expectedRemainingLabel = "Fully charged by"; var expectedChargeLabel = "66% - " + expectedRemainingLabel; var currentTimeMillis = Instant.parse("2021-02-09T13:00:00.00Z").toEpochMilli(); @@ -693,10 +693,10 @@ public class BatteryInfoTest { .isEqualTo(expectedStatusLabel); assertWithMessage("remainingLabel is incorrect") .that(info.remainingLabel.toString()) - .isEqualTo(expectedRemainingLabel); + .contains(expectedRemainingLabel); assertWithMessage("chargeLabel is incorrect") .that(info.chargeLabel.toString()) - .isEqualTo(expectedChargeLabel); + .contains(expectedChargeLabel); } private static Intent createBatteryIntent(int plugged, int level, int status) { From 428aaacefaff0c9f105637d54cc103a520c62933 Mon Sep 17 00:00:00 2001 From: songferngwang Date: Tue, 12 Mar 2024 18:13:13 +0000 Subject: [PATCH 12/14] Fix the settings crash When the user select mobile network settings item with subid=-1 in the search list, then some of objects are not initialized. Bug: 325956182 Test: atest AutoSelectPreferenceControllerTest atest MobileNetworkPhoneNumberPreferenceControllerTest atest MobileNetworkSpnPreferenceControllerTest atest MobileNetworkImeiPreferenceControllerTest atest WifiCallingPreferenceControllerTest Change-Id: I17c24b6f542392f018c65b689862f9735fad4b9f (cherry picked from commit e0b5de28aebff47bb8a9f5fe531a80e66aeca8fa) --- .../telephony/MobileNetworkEidPreferenceController.kt | 7 +++++++ .../telephony/MobileNetworkImeiPreferenceController.kt | 7 +++++++ .../MobileNetworkPhoneNumberPreferenceController.kt | 8 ++++++++ .../telephony/MobileNetworkSpnPreferenceController.kt | 10 ++++++++++ .../telephony/WifiCallingPreferenceController.kt | 8 ++++++++ .../telephony/gsm/AutoSelectPreferenceController.kt | 3 ++- 6 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/network/telephony/MobileNetworkEidPreferenceController.kt b/src/com/android/settings/network/telephony/MobileNetworkEidPreferenceController.kt index 907bab1217c..1e635a587fe 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkEidPreferenceController.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkEidPreferenceController.kt @@ -84,6 +84,13 @@ open class MobileNetworkEidPreferenceController(context: Context, key: String) : } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if (!this::lazyViewModel.isInitialized) { + Log.e( + this.javaClass.simpleName, + "lateinit property lazyViewModel has not been initialized" + ) + return + } preference.isVisible = false val viewModel by lazyViewModel diff --git a/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt b/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt index 8ec313b0483..e1346819f7d 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt @@ -78,6 +78,13 @@ class MobileNetworkImeiPreferenceController(context: Context, key: String) : } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if (!this::lazyViewModel.isInitialized) { + Log.e( + this.javaClass.simpleName, + "lateinit property lazyViewModel has not been initialized" + ) + return + } val viewModel by lazyViewModel val coroutineScope = viewLifecycleOwner.lifecycleScope diff --git a/src/com/android/settings/network/telephony/MobileNetworkPhoneNumberPreferenceController.kt b/src/com/android/settings/network/telephony/MobileNetworkPhoneNumberPreferenceController.kt index 65a4b7e6dce..10a8b53e5d4 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkPhoneNumberPreferenceController.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkPhoneNumberPreferenceController.kt @@ -19,6 +19,7 @@ package com.android.settings.network.telephony import android.content.Context import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager +import android.util.Log import androidx.annotation.VisibleForTesting import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels @@ -66,6 +67,13 @@ class MobileNetworkPhoneNumberPreferenceController(context: Context, key: String } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if (!this::lazyViewModel.isInitialized) { + Log.e( + this.javaClass.simpleName, + "lateinit property lazyViewModel has not been initialized" + ) + return + } val viewModel by lazyViewModel val coroutineScope = viewLifecycleOwner.lifecycleScope diff --git a/src/com/android/settings/network/telephony/MobileNetworkSpnPreferenceController.kt b/src/com/android/settings/network/telephony/MobileNetworkSpnPreferenceController.kt index ac055b02f06..4736eb7df83 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSpnPreferenceController.kt +++ b/src/com/android/settings/network/telephony/MobileNetworkSpnPreferenceController.kt @@ -19,6 +19,7 @@ package com.android.settings.network.telephony import android.content.Context import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager +import android.util.Log import androidx.annotation.VisibleForTesting import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels @@ -26,6 +27,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.preference.Preference import androidx.preference.PreferenceScreen import com.android.settings.flags.Flags +import com.android.settings.network.SimOnboardingActivity import com.android.settings.network.SubscriptionInfoListViewModel import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle @@ -57,6 +59,14 @@ class MobileNetworkSpnPreferenceController(context: Context, key: String) : } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if (!this::lazyViewModel.isInitialized) { + Log.e( + this.javaClass.simpleName, + "lateinit property lazyViewModel has not been initialized" + ) + return + } + val viewModel by lazyViewModel viewModel.subscriptionInfoListFlow diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt index 0ee1d87cd62..f184092821e 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.kt @@ -22,6 +22,7 @@ import android.telecom.TelecomManager import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.telephony.ims.ImsMmTelManager +import android.util.Log import androidx.lifecycle.LifecycleOwner import androidx.preference.Preference import androidx.preference.PreferenceScreen @@ -76,6 +77,13 @@ open class WifiCallingPreferenceController @JvmOverloads constructor( } override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) { + if(mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID){ + Log.e( + this.javaClass.simpleName, + "mSubId is INVALID_SUBSCRIPTION_ID" + ) + return + } wifiCallingRepositoryFactory(mSubId).wifiCallingReadyFlow() .collectLatestWithLifecycle(viewLifecycleOwner) { isReady -> preference.isVisible = isReady diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt index d709574997a..67a23563727 100644 --- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt +++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt @@ -23,6 +23,7 @@ import android.os.PersistableBundle import android.provider.Settings import android.telephony.CarrierConfigManager import android.telephony.ServiceState +import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import androidx.annotation.VisibleForTesting import androidx.compose.runtime.Composable @@ -80,7 +81,7 @@ class AutoSelectPreferenceController @JvmOverloads constructor( @VisibleForTesting var progressDialog: ProgressDialog? = null - private var subId by notNull() + private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID /** * Initialization based on given subscription id. From 5e6240746646dabf353d91e65753861074ae8194 Mon Sep 17 00:00:00 2001 From: josephpv Date: Fri, 12 Apr 2024 11:48:48 +0000 Subject: [PATCH 13/14] Add mocks for LockPatternUtils.isSecure() method in setup This change adds mocking for LockPatternUtils.isSecure method in the tests where SecurityFeatureProvider is referred in setup as per the comment in b/323649600#comment7 The tests are passing locally even without this. Bug: 333504640 Test: atest com.android.settings.privatespace Change-Id: I7d9c3a8356dbf25cf09530ffb53712b3ab887160 --- .../privatespace/FaceFingerprintUnlockControllerTest.java | 1 + .../settings/privatespace/PrivateSpaceLockControllerTest.java | 1 + .../android/settings/privatespace/UseOneLockControllerTest.java | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java index f6242ef868d..bdeede874fc 100644 --- a/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/FaceFingerprintUnlockControllerTest.java @@ -66,6 +66,7 @@ public class FaceFingerprintUnlockControllerTest { final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); when(featureFactory.securityFeatureProvider.getLockPatternUtils(mContext)) .thenReturn(mLockPatternUtils); + doReturn(true).when(mLockPatternUtils).isSecure(anyInt()); mFaceFingerprintUnlockController = new FaceFingerprintUnlockController(mContext, mLifecycle); diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java index c203a3cd72f..08f86182b56 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceLockControllerTest.java @@ -72,6 +72,7 @@ public class PrivateSpaceLockControllerTest { final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); when(featureFactory.securityFeatureProvider.getLockPatternUtils(mContext)) .thenReturn(mLockPatternUtils); + doReturn(true).when(mLockPatternUtils).isSecure(anyInt()); mPrivateSpaceLockController = new PrivateSpaceLockController(mContext, mSettingsPreferenceFragment); diff --git a/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java b/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java index d029552ee0a..027904e6e64 100644 --- a/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/UseOneLockControllerTest.java @@ -68,6 +68,7 @@ public class UseOneLockControllerTest { final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); when(featureFactory.securityFeatureProvider.getLockPatternUtils(mContext)) .thenReturn(mLockPatternUtils); + doReturn(true).when(mLockPatternUtils).isSecure(anyInt()); mUseOneLockController = new UseOneLockController(mContext, preferenceKey); } From d562080b753b4dfae96fc9c0b6fc13de0ed42c2b Mon Sep 17 00:00:00 2001 From: josephpv Date: Fri, 12 Apr 2024 12:53:51 +0000 Subject: [PATCH 14/14] Update string and button choice in PS lock setup screen Screenshot : go/ss/93jhuNKsPPzDvzy.png Recording link : b/334013507#comment5 Bug: 334013507 Test: Manual Change-Id: I03e1e5297c69f1d5154a45481f54d4207f454bd4 --- res/values/strings.xml | 4 ++-- .../privatespace/PrivateSpaceSetLockFragment.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 0a38aa1b234..0842a5d77cb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1339,9 +1339,9 @@ Try Again - Use screen lock to unlock private space? + Choose a new lock for private space? - You can unlock your private space the same way you unlock your device, or choose a different lock + You can set a new lock just for private space, or use the same lock you use to unlock your device Use screen lock diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java index 286f860ba52..830b45e2796 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -63,16 +63,16 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class); mixin.setPrimaryButton( new FooterButton.Builder(getContext()) - .setText(R.string.private_space_use_screenlock_label) - .setListener(onClickUse()) + .setText(R.string.private_space_set_lock_label) + .setListener(onClickNewLock()) .setButtonType(FooterButton.ButtonType.NEXT) .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) .build()); mixin.setSecondaryButton( new FooterButton.Builder(getContext()) - .setText(R.string.private_space_set_lock_label) - .setListener(onClickNewLock()) - .setButtonType(FooterButton.ButtonType.NEXT) + .setText(R.string.private_space_use_screenlock_label) + .setListener(onClickUse()) + .setButtonType(FooterButton.ButtonType.SKIP) .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary) .build()); OnBackPressedCallback callback =