diff options
4 files changed, 157 insertions, 48 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt index 5a9f7752277e..c9f645dddd8d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.PackageManager import com.android.systemui.R @@ -27,10 +28,14 @@ import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.settings.UserTracker import dagger.Lazy import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.withContext @SysUISingleton class CameraQuickAffordanceConfig @@ -39,6 +44,9 @@ constructor( @Application private val context: Context, private val packageManager: PackageManager, private val cameraGestureHelper: Lazy<CameraGestureHelper>, + private val userTracker: UserTracker, + private val devicePolicyManager: DevicePolicyManager, + @Background private val backgroundDispatcher: CoroutineDispatcher, ) : KeyguardQuickAffordanceConfig { override val key: String @@ -79,7 +87,12 @@ constructor( return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } - private fun isLaunchable(): Boolean { - return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) + private suspend fun isLaunchable(): Boolean { + return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) && + withContext(backgroundDispatcher) { + !devicePolicyManager.getCameraDisabled(null, userTracker.userId) && + devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId) and + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA == 0 + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt index d9ec3b1c2f87..6f821a2b5228 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent import com.android.systemui.ActivityIntentHelper @@ -29,10 +30,13 @@ import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.settings.UserTracker import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.withContext @SysUISingleton class VideoCameraQuickAffordanceConfig @@ -42,6 +46,8 @@ constructor( private val cameraIntents: CameraIntentsWrapper, private val activityIntentHelper: ActivityIntentHelper, private val userTracker: UserTracker, + private val devicePolicyManager: DevicePolicyManager, + @Background private val backgroundDispatcher: CoroutineDispatcher, ) : KeyguardQuickAffordanceConfig { private val intent: Intent by lazy { @@ -63,8 +69,8 @@ constructor( get() = R.drawable.ic_videocam override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> - get() = - flowOf( + get() = flow { + emit( if (isLaunchable()) { KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = @@ -77,6 +83,7 @@ constructor( KeyguardQuickAffordanceConfig.LockScreenState.Hidden } ) + } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { return if (isLaunchable()) { @@ -95,11 +102,14 @@ constructor( ) } - private fun isLaunchable(): Boolean { + private suspend fun isLaunchable(): Boolean { return activityIntentHelper.getTargetActivityInfo( intent, userTracker.userId, true, - ) != null + ) != null && + withContext(backgroundDispatcher) { + !devicePolicyManager.getCameraDisabled(null, userTracker.userId) + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt index db18ba61c578..5bb8367432fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt @@ -18,15 +18,19 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.PackageManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.camera.CameraGestureHelper +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before @@ -44,21 +48,28 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var cameraGestureHelper: CameraGestureHelper @Mock private lateinit var context: Context @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var devicePolicyManager: DevicePolicyManager private lateinit var underTest: CameraQuickAffordanceConfig + private lateinit var testScope: TestScope @Before fun setUp() { MockitoAnnotations.initMocks(this) - setLaunchable(true) + setLaunchable() + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) underTest = CameraQuickAffordanceConfig( context, packageManager, - ) { - cameraGestureHelper - } + { cameraGestureHelper }, + userTracker, + devicePolicyManager, + testDispatcher, + ) } @Test @@ -73,23 +84,57 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() { } @Test - fun `getPickerScreenState - default when launchable`() = runTest { - setLaunchable(true) + fun `getPickerScreenState - default when launchable`() = + testScope.runTest { + setLaunchable(true) - Truth.assertThat(underTest.getPickerScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) - } + Truth.assertThat(underTest.getPickerScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) + } @Test - fun `getPickerScreenState - unavailable when not launchable`() = runTest { - setLaunchable(false) + fun `getPickerScreenState - unavailable when camera app not installed`() = + testScope.runTest { + setLaunchable(isCameraAppInstalled = false) - Truth.assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) - } + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByDeviceAdmin = true) + + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when secure camera disabled by admin`() = + testScope.runTest { + setLaunchable(isSecureCameraDisabledByDeviceAdmin = true) + + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } - private fun setLaunchable(isLaunchable: Boolean) { + private fun setLaunchable( + isCameraAppInstalled: Boolean = true, + isCameraDisabledByDeviceAdmin: Boolean = false, + isSecureCameraDisabledByDeviceAdmin: Boolean = false, + ) { whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) - .thenReturn(isLaunchable) + .thenReturn(isCameraAppInstalled) + whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId)) + .thenReturn(isCameraDisabledByDeviceAdmin) + whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)) + .thenReturn( + if (isSecureCameraDisabledByDeviceAdmin) { + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA + } else { + 0 + } + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt index 5bd86bd0f49b..f1b9c5f0fff8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.data.quickaffordance +import android.app.admin.DevicePolicyManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.ActivityIntentHelper @@ -24,11 +25,14 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.camera.CameraIntentsWrapper import com.android.systemui.coroutines.collectLastValue import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -44,59 +48,94 @@ import org.mockito.MockitoAnnotations class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var activityIntentHelper: ActivityIntentHelper + @Mock private lateinit var devicePolicyManager: DevicePolicyManager private lateinit var underTest: VideoCameraQuickAffordanceConfig + private lateinit var userTracker: UserTracker + private lateinit var testScope: TestScope @Before fun setUp() { MockitoAnnotations.initMocks(this) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + userTracker = FakeUserTracker() underTest = VideoCameraQuickAffordanceConfig( context = context, cameraIntents = CameraIntentsWrapper(context), activityIntentHelper = activityIntentHelper, - userTracker = FakeUserTracker(), + userTracker = userTracker, + devicePolicyManager = devicePolicyManager, + backgroundDispatcher = testDispatcher, ) } @Test - fun `lockScreenState - visible when launchable`() = runTest { - setLaunchable(true) + fun `lockScreenState - visible when launchable`() = + testScope.runTest { + setLaunchable() - val lockScreenState = collectLastValue(underTest.lockScreenState) + val lockScreenState = collectLastValue(underTest.lockScreenState) - assertThat(lockScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) - } + assertThat(lockScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) + } @Test - fun `lockScreenState - hidden when not launchable`() = runTest { - setLaunchable(false) + fun `lockScreenState - hidden when app not installed on device`() = + testScope.runTest { + setLaunchable(isVideoCameraAppInstalled = false) - val lockScreenState = collectLastValue(underTest.lockScreenState) + val lockScreenState = collectLastValue(underTest.lockScreenState) - assertThat(lockScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) - } + assertThat(lockScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } @Test - fun `getPickerScreenState - default when launchable`() = runTest { - setLaunchable(true) + fun `lockScreenState - hidden when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByAdmin = true) - assertThat(underTest.getPickerScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) - } + val lockScreenState = collectLastValue(underTest.lockScreenState) + + assertThat(lockScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } @Test - fun `getPickerScreenState - unavailable when not launchable`() = runTest { - setLaunchable(false) + fun `getPickerScreenState - default when launchable`() = + testScope.runTest { + setLaunchable() - assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) - } + assertThat(underTest.getPickerScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) + } - private fun setLaunchable(isLaunchable: Boolean) { + @Test + fun `getPickerScreenState - unavailable when app not installed on device`() = + testScope.runTest { + setLaunchable(isVideoCameraAppInstalled = false) + + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByAdmin = true) + + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + private fun setLaunchable( + isVideoCameraAppInstalled: Boolean = true, + isCameraDisabledByAdmin: Boolean = false, + ) { whenever( activityIntentHelper.getTargetActivityInfo( any(), @@ -105,11 +144,13 @@ class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { ) ) .thenReturn( - if (isLaunchable) { + if (isVideoCameraAppInstalled) { mock() } else { null } ) + whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId)) + .thenReturn(isCameraDisabledByAdmin) } } |