diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index ca1ab9bbfebc8..315972cde76b0 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -42,6 +42,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.ActivityThread; +import android.app.admin.DevicePolicyManagerInternal; import android.app.assist.ActivityId; import android.content.ComponentName; import android.content.ContentCaptureOptions; @@ -94,10 +95,12 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.infra.GlobalWhitelistState; +import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; +import com.android.server.contentprotection.ContentProtectionConsentManager; import com.android.server.contentprotection.ContentProtectionPackageManager; import com.android.server.contentprotection.RemoteContentProtectionService; import com.android.server.infra.AbstractMasterSystemService; @@ -216,6 +219,8 @@ public class ContentCaptureManagerService extends @Nullable private final ContentProtectionBlocklistManager mContentProtectionBlocklistManager; + @Nullable private final ContentProtectionConsentManager mContentProtectionConsentManager; + public ContentCaptureManagerService(@NonNull Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, com.android.internal.R.string.config_defaultContentCaptureService), @@ -260,12 +265,15 @@ public class ContentCaptureManagerService extends mContentProtectionBlocklistManager = createContentProtectionBlocklistManager(); mContentProtectionBlocklistManager.updateBlocklist( mDevCfgContentProtectionAppsBlocklistSize); + mContentProtectionConsentManager = createContentProtectionConsentManager(); } else { mContentProtectionBlocklistManager = null; + mContentProtectionConsentManager = null; } } else { mContentProtectionServiceComponentName = null; mContentProtectionBlocklistManager = null; + mContentProtectionConsentManager = null; } } @@ -802,6 +810,17 @@ public class ContentCaptureManagerService extends new ContentProtectionPackageManager(getContext())); } + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @NonNull + protected ContentProtectionConsentManager createContentProtectionConsentManager() { + // Same handler as used by AbstractMasterSystemService + return new ContentProtectionConsentManager( + BackgroundThread.getHandler(), + getContext().getContentResolver(), + LocalServices.getService(DevicePolicyManagerInternal.class)); + } + @Nullable private ComponentName getContentProtectionServiceComponentName() { String flatComponentName = getContentProtectionServiceFlatComponentName(); @@ -1213,7 +1232,7 @@ public class ContentCaptureManagerService extends isContentCaptureReceiverEnabled = isContentCaptureReceiverEnabled(userId, packageName); isContentProtectionReceiverEnabled = - isContentProtectionReceiverEnabled(packageName); + isContentProtectionReceiverEnabled(userId, packageName); if (!isContentCaptureReceiverEnabled) { // Full package is not allowlisted: check individual components next @@ -1284,13 +1303,13 @@ public class ContentCaptureManagerService extends @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) { return isContentCaptureReceiverEnabled(userId, packageName) - || isContentProtectionReceiverEnabled(packageName); + || isContentProtectionReceiverEnabled(userId, packageName); } @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) { return super.isWhitelisted(userId, componentName) - || isContentProtectionReceiverEnabled(componentName.getPackageName()); + || isContentProtectionReceiverEnabled(userId, componentName.getPackageName()); } private boolean isContentCaptureReceiverEnabled( @@ -1298,9 +1317,11 @@ public class ContentCaptureManagerService extends return super.isWhitelisted(userId, packageName); } - private boolean isContentProtectionReceiverEnabled(@NonNull String packageName) { + private boolean isContentProtectionReceiverEnabled( + @UserIdInt int userId, @NonNull String packageName) { if (mContentProtectionServiceComponentName == null - || mContentProtectionBlocklistManager == null) { + || mContentProtectionBlocklistManager == null + || mContentProtectionConsentManager == null) { return false; } synchronized (mLock) { @@ -1308,7 +1329,8 @@ public class ContentCaptureManagerService extends return false; } } - return mContentProtectionBlocklistManager.isAllowed(packageName); + return mContentProtectionConsentManager.isConsentGranted(userId) + && mContentProtectionBlocklistManager.isAllowed(packageName); } } diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java new file mode 100644 index 0000000000000..2eb758cd5a130 --- /dev/null +++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java @@ -0,0 +1,109 @@ +/* + * 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.server.contentprotection; + +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.app.admin.DevicePolicyManagerInternal; +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Manages consent for content protection. + * + * @hide + */ +public class ContentProtectionConsentManager { + + private static final String TAG = "ContentProtectionConsentManager"; + + private static final String KEY_PACKAGE_VERIFIER_USER_CONSENT = "package_verifier_user_consent"; + + @NonNull private final ContentResolver mContentResolver; + + @NonNull private final DevicePolicyManagerInternal mDevicePolicyManagerInternal; + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @NonNull + public final ContentObserver mContentObserver; + + private volatile boolean mCachedPackageVerifierConsent; + + public ContentProtectionConsentManager( + @NonNull Handler handler, + @NonNull ContentResolver contentResolver, + @NonNull DevicePolicyManagerInternal devicePolicyManagerInternal) { + mContentResolver = contentResolver; + mDevicePolicyManagerInternal = devicePolicyManagerInternal; + mContentObserver = new SettingsObserver(handler); + + contentResolver.registerContentObserver( + Settings.Global.getUriFor(KEY_PACKAGE_VERIFIER_USER_CONSENT), + /* notifyForDescendants= */ false, + mContentObserver, + UserHandle.USER_ALL); + mCachedPackageVerifierConsent = isPackageVerifierConsentGranted(); + } + + /** + * Returns true if all the consents are granted + */ + public boolean isConsentGranted(@UserIdInt int userId) { + return mCachedPackageVerifierConsent && !isUserOrganizationManaged(userId); + } + + private boolean isPackageVerifierConsentGranted() { + // Not always cached internally + return Settings.Global.getInt( + mContentResolver, KEY_PACKAGE_VERIFIER_USER_CONSENT, /* def= */ 0) + >= 1; + } + + private boolean isUserOrganizationManaged(@UserIdInt int userId) { + // Cached internally + return mDevicePolicyManagerInternal.isUserOrganizationManaged(userId); + } + + private final class SettingsObserver extends ContentObserver { + + SettingsObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) { + final String property = uri.getLastPathSegment(); + if (property == null) { + return; + } + switch (property) { + case KEY_PACKAGE_VERIFIER_USER_CONSENT: + mCachedPackageVerifierConsent = isPackageVerifierConsentGranted(); + return; + default: + Slog.w(TAG, "Ignoring unexpected property: " + property); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java index e4571194b37d9..e7777f75b6df7 100644 --- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java @@ -42,6 +42,7 @@ import androidx.test.filters.SmallTest; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; +import com.android.server.contentprotection.ContentProtectionConsentManager; import com.android.server.contentprotection.RemoteContentProtectionService; import com.android.server.pm.UserManagerInternal; @@ -91,6 +92,8 @@ public class ContentCaptureManagerServiceTest { @Mock private RemoteContentProtectionService mMockRemoteContentProtectionService; + @Mock private ContentProtectionConsentManager mMockContentProtectionConsentManager; + private boolean mDevCfgEnableContentProtectionReceiver; private int mContentProtectionBlocklistManagersCreated; @@ -99,6 +102,8 @@ public class ContentCaptureManagerServiceTest { private int mRemoteContentProtectionServicesCreated; + private int mContentProtectionConsentManagersCreated; + private String mConfigDefaultContentProtectionService = COMPONENT_NAME.flattenToString(); private boolean mContentProtectionServiceInfoConstructorShouldThrow; @@ -114,43 +119,51 @@ public class ContentCaptureManagerServiceTest { } @Test - public void constructor_contentProtection_flagDisabled_noBlocklistManager() { + public void constructor_contentProtection_flagDisabled_noManagers() { assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0); + assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); + verifyZeroInteractions(mMockContentProtectionConsentManager); } @Test - public void constructor_contentProtection_componentNameNull_noBlocklistManager() { + public void constructor_contentProtection_componentNameNull_noManagers() { mConfigDefaultContentProtectionService = null; mContentCaptureManagerService = new TestContentCaptureManagerService(); assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0); + assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); + verifyZeroInteractions(mMockContentProtectionConsentManager); } @Test - public void constructor_contentProtection_componentNameBlank_noBlocklistManager() { + public void constructor_contentProtection_componentNameBlank_noManagers() { mConfigDefaultContentProtectionService = " "; mContentCaptureManagerService = new TestContentCaptureManagerService(); assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0); + assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); + verifyZeroInteractions(mMockContentProtectionConsentManager); } @Test - public void constructor_contentProtection_enabled_createsBlocklistManager() { + public void constructor_contentProtection_enabled_createsManagers() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1); + assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1); assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0); verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt()); + verifyZeroInteractions(mMockContentProtectionConsentManager); } @Test @@ -175,11 +188,13 @@ public class ContentCaptureManagerServiceTest { USER_ID, PACKAGE_NAME); assertThat(actual).isNull(); - verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); + verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID); + verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void getOptions_contentCaptureDisabled_contentProtectionEnabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -211,11 +226,13 @@ public class ContentCaptureManagerServiceTest { assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isFalse(); assertThat(actual.whitelistedComponents).isNull(); - verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); + verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID); + verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void getOptions_contentCaptureEnabled_contentProtectionEnabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -233,8 +250,23 @@ public class ContentCaptureManagerServiceTest { assertThat(actual.whitelistedComponents).isNull(); } + @Test + public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionNotGranted() { + mDevCfgEnableContentProtectionReceiver = true; + mContentCaptureManagerService = new TestContentCaptureManagerService(); + + boolean actual = + mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( + USER_ID, PACKAGE_NAME); + + assertThat(actual).isFalse(); + verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID); + verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); + } + @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -248,6 +280,7 @@ public class ContentCaptureManagerServiceTest { @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -271,11 +304,27 @@ public class ContentCaptureManagerServiceTest { USER_ID, PACKAGE_NAME); assertThat(actual).isTrue(); + verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt()); + verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); + } + + @Test + public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionNotGranted() { + mDevCfgEnableContentProtectionReceiver = true; + mContentCaptureManagerService = new TestContentCaptureManagerService(); + + boolean actual = + mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( + USER_ID, COMPONENT_NAME); + + assertThat(actual).isFalse(); + verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -289,6 +338,7 @@ public class ContentCaptureManagerServiceTest { @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() { + when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true); when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); @@ -312,16 +362,18 @@ public class ContentCaptureManagerServiceTest { USER_ID, COMPONENT_NAME); assertThat(actual).isTrue(); + verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt()); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test - public void isContentProtectionReceiverEnabled_withoutBlocklistManager() { + public void isContentProtectionReceiverEnabled_withoutManagers() { boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); + verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt()); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @@ -336,6 +388,7 @@ public class ContentCaptureManagerServiceTest { USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); + verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt()); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @@ -423,5 +476,11 @@ public class ContentCaptureManagerServiceTest { mRemoteContentProtectionServicesCreated++; return mMockRemoteContentProtectionService; } + + @Override + protected ContentProtectionConsentManager createContentProtectionConsentManager() { + mContentProtectionConsentManagersCreated++; + return mMockContentProtectionConsentManager; + } } } diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java new file mode 100644 index 0000000000000..0e80bfdae2917 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java @@ -0,0 +1,172 @@ +/* + * 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.server.contentprotection; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManagerInternal; +import android.content.ContentResolver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.provider.Settings; +import android.testing.TestableContentResolver; +import android.testing.TestableContext; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Test for {@link ContentProtectionConsentManager}. + * + *
Run with: {@code atest + * FrameworksServicesTests:com.android.server.contentprotection.ContentProtectionConsentManagerTest} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ContentProtectionConsentManagerTest { + + private static final String KEY_PACKAGE_VERIFIER_USER_CONSENT = "package_verifier_user_consent"; + + private static final Uri URI_PACKAGE_VERIFIER_USER_CONSENT = + Settings.Global.getUriFor(KEY_PACKAGE_VERIFIER_USER_CONSENT); + + private static final int VALUE_TRUE = 1; + + private static final int VALUE_FALSE = -1; + + private static final int VALUE_DEFAULT = 0; + + private static final int TEST_USER_ID = 1234; + + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Rule + public final TestableContext mTestableContext = + new TestableContext(ApplicationProvider.getApplicationContext()); + + private final TestableContentResolver mTestableContentResolver = + mTestableContext.getContentResolver(); + + @Mock private ContentResolver mMockContentResolver; + + @Mock private DevicePolicyManagerInternal mMockDevicePolicyManagerInternal; + + @Test + public void constructor_registersContentObserver() { + ContentProtectionConsentManager manager = + createContentProtectionConsentManager(mMockContentResolver); + + assertThat(manager.mContentObserver).isNotNull(); + verify(mMockContentResolver) + .registerContentObserver( + URI_PACKAGE_VERIFIER_USER_CONSENT, + /* notifyForDescendants= */ false, + manager.mContentObserver, + UserHandle.USER_ALL); + } + + @Test + public void isConsentGranted_packageVerifierNotGranted() { + ContentProtectionConsentManager manager = + createContentProtectionConsentManager(VALUE_FALSE); + + boolean actual = manager.isConsentGranted(TEST_USER_ID); + + assertThat(actual).isFalse(); + verifyZeroInteractions(mMockDevicePolicyManagerInternal); + } + + @Test + public void isConsentGranted_packageVerifierGranted_userNotManaged() { + ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE); + + boolean actual = manager.isConsentGranted(TEST_USER_ID); + + assertThat(actual).isTrue(); + verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID); + } + + @Test + public void isConsentGranted_packageVerifierGranted_userManaged() { + when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID)) + .thenReturn(true); + ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE); + + boolean actual = manager.isConsentGranted(TEST_USER_ID); + + assertThat(actual).isFalse(); + } + + @Test + public void isConsentGranted_packageVerifierDefault() { + ContentProtectionConsentManager manager = + createContentProtectionConsentManager(VALUE_DEFAULT); + + boolean actual = manager.isConsentGranted(TEST_USER_ID); + + assertThat(actual).isFalse(); + verifyZeroInteractions(mMockDevicePolicyManagerInternal); + } + + @Test + public void contentObserver() throws Exception { + ContentProtectionConsentManager manager = createContentProtectionConsentManager(VALUE_TRUE); + boolean firstActual = manager.isConsentGranted(TEST_USER_ID); + + Settings.Global.putInt( + mTestableContentResolver, KEY_PACKAGE_VERIFIER_USER_CONSENT, VALUE_FALSE); + // Observer has to be called manually, mTestableContentResolver is not propagating + manager.mContentObserver.onChange( + /* selfChange= */ false, URI_PACKAGE_VERIFIER_USER_CONSENT, TEST_USER_ID); + boolean secondActual = manager.isConsentGranted(TEST_USER_ID); + + assertThat(firstActual).isTrue(); + assertThat(secondActual).isFalse(); + verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID); + } + + private ContentProtectionConsentManager createContentProtectionConsentManager( + ContentResolver contentResolver) { + return new ContentProtectionConsentManager( + new Handler(Looper.getMainLooper()), + contentResolver, + mMockDevicePolicyManagerInternal); + } + + private ContentProtectionConsentManager createContentProtectionConsentManager( + int valuePackageVerifierUserConsent) { + Settings.Global.putInt( + mTestableContentResolver, + KEY_PACKAGE_VERIFIER_USER_CONSENT, + valuePackageVerifierUserConsent); + return createContentProtectionConsentManager(mTestableContentResolver); + } +}