Merge "Camera quick affordance respects device policy." into tm-qpr-dev

This commit is contained in:
Ale Nijamkin
2023-02-14 18:31:09 +00:00
committed by Android (Google) Code Review
4 changed files with 157 additions and 48 deletions

View File

@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager import android.app.StatusBarManager
import android.app.admin.DevicePolicyManager
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import com.android.systemui.R 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.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker
import dagger.Lazy import dagger.Lazy
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.withContext
@SysUISingleton @SysUISingleton
class CameraQuickAffordanceConfig class CameraQuickAffordanceConfig
@@ -39,6 +44,9 @@ constructor(
@Application private val context: Context, @Application private val context: Context,
private val packageManager: PackageManager, private val packageManager: PackageManager,
private val cameraGestureHelper: Lazy<CameraGestureHelper>, private val cameraGestureHelper: Lazy<CameraGestureHelper>,
private val userTracker: UserTracker,
private val devicePolicyManager: DevicePolicyManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig { ) : KeyguardQuickAffordanceConfig {
override val key: String override val key: String
@@ -79,7 +87,12 @@ constructor(
return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
} }
private fun isLaunchable(): Boolean { private suspend fun isLaunchable(): Boolean {
return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) 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
}
} }
} }

View File

@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager import android.app.StatusBarManager
import android.app.admin.DevicePolicyManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.android.systemui.ActivityIntentHelper 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.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.withContext
@SysUISingleton @SysUISingleton
class VideoCameraQuickAffordanceConfig class VideoCameraQuickAffordanceConfig
@@ -42,6 +46,8 @@ constructor(
private val cameraIntents: CameraIntentsWrapper, private val cameraIntents: CameraIntentsWrapper,
private val activityIntentHelper: ActivityIntentHelper, private val activityIntentHelper: ActivityIntentHelper,
private val userTracker: UserTracker, private val userTracker: UserTracker,
private val devicePolicyManager: DevicePolicyManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig { ) : KeyguardQuickAffordanceConfig {
private val intent: Intent by lazy { private val intent: Intent by lazy {
@@ -63,8 +69,8 @@ constructor(
get() = R.drawable.ic_videocam get() = R.drawable.ic_videocam
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
get() = get() = flow {
flowOf( emit(
if (isLaunchable()) { if (isLaunchable()) {
KeyguardQuickAffordanceConfig.LockScreenState.Visible( KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = icon =
@@ -77,6 +83,7 @@ constructor(
KeyguardQuickAffordanceConfig.LockScreenState.Hidden KeyguardQuickAffordanceConfig.LockScreenState.Hidden
} }
) )
}
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return if (isLaunchable()) { return if (isLaunchable()) {
@@ -95,11 +102,14 @@ constructor(
) )
} }
private fun isLaunchable(): Boolean { private suspend fun isLaunchable(): Boolean {
return activityIntentHelper.getTargetActivityInfo( return activityIntentHelper.getTargetActivityInfo(
intent, intent,
userTracker.userId, userTracker.userId,
true, true,
) != null ) != null &&
withContext(backgroundDispatcher) {
!devicePolicyManager.getCameraDisabled(null, userTracker.userId)
}
} }
} }

View File

@@ -18,15 +18,19 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager import android.app.StatusBarManager
import android.app.admin.DevicePolicyManager
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.CameraGestureHelper import com.android.systemui.camera.CameraGestureHelper
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
@@ -44,21 +48,28 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() {
@Mock private lateinit var cameraGestureHelper: CameraGestureHelper @Mock private lateinit var cameraGestureHelper: CameraGestureHelper
@Mock private lateinit var context: Context @Mock private lateinit var context: Context
@Mock private lateinit var packageManager: PackageManager @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 underTest: CameraQuickAffordanceConfig
private lateinit var testScope: TestScope
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
setLaunchable(true) setLaunchable()
val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
underTest = underTest =
CameraQuickAffordanceConfig( CameraQuickAffordanceConfig(
context, context,
packageManager, packageManager,
) { { cameraGestureHelper },
cameraGestureHelper userTracker,
} devicePolicyManager,
testDispatcher,
)
} }
@Test @Test
@@ -73,7 +84,8 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() {
} }
@Test @Test
fun `getPickerScreenState - default when launchable`() = runTest { fun `getPickerScreenState - default when launchable`() =
testScope.runTest {
setLaunchable(true) setLaunchable(true)
Truth.assertThat(underTest.getPickerScreenState()) Truth.assertThat(underTest.getPickerScreenState())
@@ -81,15 +93,48 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() {
} }
@Test @Test
fun `getPickerScreenState - unavailable when not launchable`() = runTest { fun `getPickerScreenState - unavailable when camera app not installed`() =
setLaunchable(false) testScope.runTest {
setLaunchable(isCameraAppInstalled = false)
Truth.assertThat(underTest.getPickerScreenState()) Truth.assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
} }
private fun setLaunchable(isLaunchable: Boolean) { @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(
isCameraAppInstalled: Boolean = true,
isCameraDisabledByDeviceAdmin: Boolean = false,
isSecureCameraDisabledByDeviceAdmin: Boolean = false,
) {
whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) 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
}
)
} }
} }

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance package com.android.systemui.keyguard.data.quickaffordance
import android.app.admin.DevicePolicyManager
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.ActivityIntentHelper import com.android.systemui.ActivityIntentHelper
@@ -24,11 +25,14 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.CameraIntentsWrapper import com.android.systemui.camera.CameraIntentsWrapper
import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.settings.FakeUserTracker 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.any
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -44,25 +48,34 @@ import org.mockito.MockitoAnnotations
class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
@Mock private lateinit var activityIntentHelper: ActivityIntentHelper @Mock private lateinit var activityIntentHelper: ActivityIntentHelper
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: VideoCameraQuickAffordanceConfig private lateinit var underTest: VideoCameraQuickAffordanceConfig
private lateinit var userTracker: UserTracker
private lateinit var testScope: TestScope
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
userTracker = FakeUserTracker()
underTest = underTest =
VideoCameraQuickAffordanceConfig( VideoCameraQuickAffordanceConfig(
context = context, context = context,
cameraIntents = CameraIntentsWrapper(context), cameraIntents = CameraIntentsWrapper(context),
activityIntentHelper = activityIntentHelper, activityIntentHelper = activityIntentHelper,
userTracker = FakeUserTracker(), userTracker = userTracker,
devicePolicyManager = devicePolicyManager,
backgroundDispatcher = testDispatcher,
) )
} }
@Test @Test
fun `lockScreenState - visible when launchable`() = runTest { fun `lockScreenState - visible when launchable`() =
setLaunchable(true) testScope.runTest {
setLaunchable()
val lockScreenState = collectLastValue(underTest.lockScreenState) val lockScreenState = collectLastValue(underTest.lockScreenState)
@@ -71,8 +84,9 @@ class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
} }
@Test @Test
fun `lockScreenState - hidden when not launchable`() = runTest { fun `lockScreenState - hidden when app not installed on device`() =
setLaunchable(false) testScope.runTest {
setLaunchable(isVideoCameraAppInstalled = false)
val lockScreenState = collectLastValue(underTest.lockScreenState) val lockScreenState = collectLastValue(underTest.lockScreenState)
@@ -81,22 +95,47 @@ class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
} }
@Test @Test
fun `getPickerScreenState - default when launchable`() = runTest { fun `lockScreenState - hidden when camera disabled by admin`() =
setLaunchable(true) testScope.runTest {
setLaunchable(isCameraDisabledByAdmin = true)
val lockScreenState = collectLastValue(underTest.lockScreenState)
assertThat(lockScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
}
@Test
fun `getPickerScreenState - default when launchable`() =
testScope.runTest {
setLaunchable()
assertThat(underTest.getPickerScreenState()) assertThat(underTest.getPickerScreenState())
.isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
} }
@Test @Test
fun `getPickerScreenState - unavailable when not launchable`() = runTest { fun `getPickerScreenState - unavailable when app not installed on device`() =
setLaunchable(false) testScope.runTest {
setLaunchable(isVideoCameraAppInstalled = false)
assertThat(underTest.getPickerScreenState()) assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
} }
private fun setLaunchable(isLaunchable: Boolean) { @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( whenever(
activityIntentHelper.getTargetActivityInfo( activityIntentHelper.getTargetActivityInfo(
any(), any(),
@@ -105,11 +144,13 @@ class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
) )
) )
.thenReturn( .thenReturn(
if (isLaunchable) { if (isVideoCameraAppInstalled) {
mock() mock()
} else { } else {
null null
} }
) )
whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId))
.thenReturn(isCameraDisabledByAdmin)
} }
} }