diff options
6 files changed, 980 insertions, 21 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 1edb837f3ca9..e665d832a568 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -34,8 +34,8 @@ import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnail import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider -import com.android.systemui.settings.UserTracker -import com.android.systemui.shared.system.ActivityManagerWrapper +import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule +import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile import com.android.systemui.statusbar.phone.ConfigurationControllerImpl import com.android.systemui.statusbar.policy.ConfigurationController import dagger.Binds @@ -54,13 +54,12 @@ import kotlinx.coroutines.SupervisorJob @Qualifier @Retention(AnnotationRetention.BINARY) annotation class HostUserHandle -@Qualifier @Retention(AnnotationRetention.BINARY) annotation class PersonalProfile - -@Qualifier @Retention(AnnotationRetention.BINARY) annotation class WorkProfile - @Retention(AnnotationRetention.RUNTIME) @Scope annotation class MediaProjectionAppSelectorScope -@Module(subcomponents = [MediaProjectionAppSelectorComponent::class]) +@Module( + subcomponents = [MediaProjectionAppSelectorComponent::class], + includes = [MediaProjectionDevicePolicyModule::class] +) interface MediaProjectionModule { @Binds @IntoMap @@ -110,20 +109,6 @@ interface MediaProjectionAppSelectorModule { ): ConfigurationController = ConfigurationControllerImpl(activity) @Provides - @PersonalProfile - @MediaProjectionAppSelectorScope - fun personalUserHandle(activityManagerWrapper: ActivityManagerWrapper): UserHandle { - // Current foreground user is the 'personal' profile - return UserHandle.of(activityManagerWrapper.currentUserId) - } - - @Provides - @WorkProfile - @MediaProjectionAppSelectorScope - fun workProfileUserHandle(userTracker: UserTracker): UserHandle? = - userTracker.userProfiles.find { it.isManagedProfile }?.userHandle - - @Provides @HostUserHandle @MediaProjectionAppSelectorScope fun hostUserHandle(activity: MediaProjectionAppSelectorActivity): UserHandle { diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt new file mode 100644 index 000000000000..829b0ddbe3a8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 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.systemui.mediaprojection.appselector + +import android.content.Context +import android.os.UserHandle +import com.android.internal.R as AndroidR +import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState +import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider +import com.android.internal.app.ResolverListAdapter +import com.android.systemui.R +import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile +import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver +import javax.inject.Inject + +@MediaProjectionAppSelectorScope +class MediaProjectionBlockerEmptyStateProvider +@Inject +constructor( + @HostUserHandle private val hostAppHandle: UserHandle, + @PersonalProfile private val personalProfileHandle: UserHandle, + private val policyResolver: ScreenCaptureDevicePolicyResolver, + private val context: Context +) : EmptyStateProvider { + + override fun getEmptyState(resolverListAdapter: ResolverListAdapter): EmptyState? { + val screenCaptureAllowed = + policyResolver.isScreenCaptureAllowed( + targetAppUserHandle = resolverListAdapter.userHandle, + hostAppUserHandle = hostAppHandle + ) + + val isHostAppInPersonalProfile = hostAppHandle == personalProfileHandle + + val subtitle = + if (isHostAppInPersonalProfile) { + AndroidR.string.resolver_cant_share_with_personal_apps_explanation + } else { + AndroidR.string.resolver_cant_share_with_work_apps_explanation + } + + if (!screenCaptureAllowed) { + return object : EmptyState { + override fun getSubtitle(): String = context.resources.getString(subtitle) + override fun getTitle(): String = + context.resources.getString( + R.string.screen_capturing_disabled_by_policy_dialog_title + ) + override fun onEmptyStateShown() { + // TODO(b/237397740) report analytics + } + override fun shouldSkipDataRebuild(): Boolean = true + } + } + return null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/MediaProjectionDevicePolicyModule.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/MediaProjectionDevicePolicyModule.kt new file mode 100644 index 000000000000..13b71a727dd9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/MediaProjectionDevicePolicyModule.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 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.systemui.mediaprojection.devicepolicy + +import android.os.UserHandle +import com.android.systemui.settings.UserTracker +import com.android.systemui.shared.system.ActivityManagerWrapper +import dagger.Module +import dagger.Provides +import javax.inject.Qualifier + +@Qualifier @Retention(AnnotationRetention.BINARY) annotation class WorkProfile + +@Qualifier @Retention(AnnotationRetention.BINARY) annotation class PersonalProfile + +/** Module for media projection device policy related dependencies */ +@Module +class MediaProjectionDevicePolicyModule { + @Provides + @PersonalProfile + fun personalUserHandle(activityManagerWrapper: ActivityManagerWrapper): UserHandle { + // Current foreground user is the 'personal' profile + return UserHandle.of(activityManagerWrapper.currentUserId) + } + + @Provides + @WorkProfile + fun workProfileUserHandle(userTracker: UserTracker): UserHandle? = + userTracker.userProfiles.find { it.isManagedProfile }?.userHandle +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt new file mode 100644 index 000000000000..6bd33e7e5c97 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 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.systemui.mediaprojection.devicepolicy + +import android.app.admin.DevicePolicyManager +import android.os.UserHandle +import android.os.UserManager +import javax.inject.Inject + +/** + * Utility class to resolve if screen capture allowed for a particular target app/host app pair. It + * caches the state of the policies, so you need to create a new instance of this class if you want + * to react to updated policies state. + */ +class ScreenCaptureDevicePolicyResolver +@Inject +constructor( + private val devicePolicyManager: DevicePolicyManager, + private val userManager: UserManager, + @PersonalProfile private val personalProfileUserHandle: UserHandle, + @WorkProfile private val workProfileUserHandle: UserHandle? +) { + + /** + * Returns true if [hostAppUserHandle] is allowed to perform screen capture of + * [targetAppUserHandle] + */ + fun isScreenCaptureAllowed( + targetAppUserHandle: UserHandle, + hostAppUserHandle: UserHandle, + ): Boolean { + if (hostAppUserHandle.isWorkProfile() && workProfileScreenCaptureDisabled) { + // Disable screen capturing as host apps should not capture the screen + return false + } + + if (!hostAppUserHandle.isWorkProfile() && personalProfileScreenCaptureDisabled) { + // Disable screen capturing as personal apps should not capture the screen + return false + } + + if (targetAppUserHandle.isWorkProfile()) { + // Work profile target + if (workProfileScreenCaptureDisabled) { + // Do not allow sharing work profile apps as work profile capturing is disabled + return false + } + } else { + // Personal profile target + if (hostAppUserHandle.isWorkProfile() && disallowSharingIntoManagedProfile) { + // Do not allow sharing of personal apps into work profile apps + return false + } + + if (personalProfileScreenCaptureDisabled) { + // Disable screen capturing as personal apps should not be captured + return false + } + } + + return true + } + + /** + * Returns true if [hostAppUserHandle] is NOT allowed to capture an app from any profile, + * could be useful to finish the screen capture flow as soon as possible when the screen + * could not be captured at all. + */ + fun isScreenCaptureCompletelyDisabled(hostAppUserHandle: UserHandle): Boolean { + val isWorkAppsCaptureDisabled = + if (workProfileUserHandle != null) { + !isScreenCaptureAllowed( + targetAppUserHandle = workProfileUserHandle, + hostAppUserHandle = hostAppUserHandle + ) + } else true + + val isPersonalAppsCaptureDisabled = + !isScreenCaptureAllowed( + targetAppUserHandle = personalProfileUserHandle, + hostAppUserHandle = hostAppUserHandle + ) + + return isWorkAppsCaptureDisabled && isPersonalAppsCaptureDisabled + } + + private val personalProfileScreenCaptureDisabled: Boolean by lazy { + devicePolicyManager.getScreenCaptureDisabled( + /* admin */ null, + personalProfileUserHandle.identifier + ) + } + + private val workProfileScreenCaptureDisabled: Boolean by lazy { + workProfileUserHandle?.let { + devicePolicyManager.getScreenCaptureDisabled(/* admin */ null, it.identifier) + } + ?: false + } + + private val disallowSharingIntoManagedProfile: Boolean by lazy { + workProfileUserHandle?.let { + userManager.hasUserRestrictionForUser( + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, + it + ) + } + ?: false + } + + private fun UserHandle?.isWorkProfile(): Boolean = this == workProfileUserHandle +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDisabledDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDisabledDialog.kt new file mode 100644 index 000000000000..a6b3da04ad80 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDisabledDialog.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 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.systemui.mediaprojection.devicepolicy + +import android.content.Context +import com.android.systemui.R +import com.android.systemui.statusbar.phone.SystemUIDialog + +/** Dialog that shows that screen capture is disabled on this device. */ +class ScreenCaptureDisabledDialog(context: Context) : SystemUIDialog(context) { + + init { + setTitle(context.getString(R.string.screen_capturing_disabled_by_policy_dialog_title)) + setMessage( + context.getString(R.string.screen_capturing_disabled_by_policy_dialog_description) + ) + setIcon(R.drawable.ic_cast) + setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> cancel() } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt new file mode 100644 index 000000000000..e8b6f9bd3478 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2023 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.systemui.mediaprojection.devicepolicy + +import android.app.admin.DevicePolicyManager +import android.os.UserHandle +import android.os.UserManager +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters +import org.mockito.ArgumentMatchers.any + +abstract class BaseScreenCaptureDevicePolicyResolverTest(private val precondition: Preconditions) : + SysuiTestCase() { + + abstract class Preconditions( + val personalScreenCaptureDisabled: Boolean, + val workScreenCaptureDisabled: Boolean, + val disallowShareIntoManagedProfile: Boolean + ) + + protected val devicePolicyManager: DevicePolicyManager = mock() + protected val userManager: UserManager = mock() + + protected val personalUserHandle: UserHandle = UserHandle.of(123) + protected val workUserHandle: UserHandle = UserHandle.of(456) + + protected val policyResolver = + ScreenCaptureDevicePolicyResolver( + devicePolicyManager, + userManager, + personalUserHandle, + workUserHandle + ) + + @Before + fun setUp() { + setUpPolicies() + } + + private fun setUpPolicies() { + whenever( + devicePolicyManager.getScreenCaptureDisabled( + any(), + eq(personalUserHandle.identifier) + ) + ) + .thenReturn(precondition.personalScreenCaptureDisabled) + + whenever(devicePolicyManager.getScreenCaptureDisabled(any(), eq(workUserHandle.identifier))) + .thenReturn(precondition.workScreenCaptureDisabled) + + whenever( + userManager.hasUserRestrictionForUser( + eq(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE), + eq(workUserHandle) + ) + ) + .thenReturn(precondition.disallowShareIntoManagedProfile) + } +} + +@RunWith(Parameterized::class) +@SmallTest +class IsAllowedScreenCaptureDevicePolicyResolverTest( + private val test: IsScreenCaptureAllowedTestCase +) : BaseScreenCaptureDevicePolicyResolverTest(test.given) { + + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun getParams() = + listOf( + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false, + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true, + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false, + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true, + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = true, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureAllowed = false, + ), + IsScreenCaptureAllowedTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + isTargetInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureAllowed = false, + ), + ) + } + + class Preconditions( + personalScreenCaptureDisabled: Boolean, + workScreenCaptureDisabled: Boolean, + disallowShareIntoManagedProfile: Boolean, + val isHostInWorkProfile: Boolean, + val isTargetInWorkProfile: Boolean, + ) : + BaseScreenCaptureDevicePolicyResolverTest.Preconditions( + personalScreenCaptureDisabled, + workScreenCaptureDisabled, + disallowShareIntoManagedProfile + ) + + data class IsScreenCaptureAllowedTestCase( + val given: Preconditions, + val expectedScreenCaptureAllowed: Boolean + ) { + override fun toString(): String = + "isScreenCaptureAllowed: " + + "host[${if (given.isHostInWorkProfile) "work" else "personal"} profile], " + + "target[${if (given.isTargetInWorkProfile) "work" else "personal"} profile], " + + "personal screen capture disabled = ${given.personalScreenCaptureDisabled}, " + + "work screen capture disabled = ${given.workScreenCaptureDisabled}, " + + "disallow share into managed profile = ${given.disallowShareIntoManagedProfile}, " + + "expected screen capture allowed = $expectedScreenCaptureAllowed" + } + + @Test + fun test() { + val targetAppUserHandle = + if (test.given.isTargetInWorkProfile) workUserHandle else personalUserHandle + val hostAppUserHandle = + if (test.given.isHostInWorkProfile) workUserHandle else personalUserHandle + + val screenCaptureAllowed = + policyResolver.isScreenCaptureAllowed(targetAppUserHandle, hostAppUserHandle) + + assertWithMessage("Screen capture policy resolved incorrectly") + .that(screenCaptureAllowed) + .isEqualTo(test.expectedScreenCaptureAllowed) + } +} + +@RunWith(Parameterized::class) +@SmallTest +class IsCompletelyNotAllowedScreenCaptureDevicePolicyResolverTest( + private val test: IsScreenCaptureCompletelyDisabledTestCase +) : BaseScreenCaptureDevicePolicyResolverTest(test.given) { + + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun getParams() = + listOf( + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = false, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = false, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = false, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = false, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = false + ), + expectedScreenCaptureCompletelyDisabled = true, + ), + IsScreenCaptureCompletelyDisabledTestCase( + given = + Preconditions( + isHostInWorkProfile = true, + personalScreenCaptureDisabled = true, + workScreenCaptureDisabled = true, + disallowShareIntoManagedProfile = true + ), + expectedScreenCaptureCompletelyDisabled = true, + ) + ) + } + + class Preconditions( + personalScreenCaptureDisabled: Boolean, + workScreenCaptureDisabled: Boolean, + disallowShareIntoManagedProfile: Boolean, + val isHostInWorkProfile: Boolean, + ) : + BaseScreenCaptureDevicePolicyResolverTest.Preconditions( + personalScreenCaptureDisabled, + workScreenCaptureDisabled, + disallowShareIntoManagedProfile + ) + + data class IsScreenCaptureCompletelyDisabledTestCase( + val given: Preconditions, + val expectedScreenCaptureCompletelyDisabled: Boolean + ) { + override fun toString(): String = + "isScreenCaptureCompletelyDisabled: " + + "host[${if (given.isHostInWorkProfile) "work" else "personal"} profile], " + + "personal screen capture disabled = ${given.personalScreenCaptureDisabled}, " + + "work screen capture disabled = ${given.workScreenCaptureDisabled}, " + + "disallow share into managed profile = ${given.disallowShareIntoManagedProfile}, " + + "expected screen capture completely disabled = $expectedScreenCaptureCompletelyDisabled" + } + + @Test + fun test() { + val hostAppUserHandle = + if (test.given.isHostInWorkProfile) workUserHandle else personalUserHandle + + val completelyDisabled = policyResolver.isScreenCaptureCompletelyDisabled(hostAppUserHandle) + + assertWithMessage("Screen capture policy resolved incorrectly") + .that(completelyDisabled) + .isEqualTo(test.expectedScreenCaptureCompletelyDisabled) + } +} |