/*
 * Copyright (C) 2015 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.devicepolicy;

import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
import static android.app.Notification.EXTRA_TITLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_OPEN;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
import static android.net.InetAddresses.parseNumericAddress;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;

import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
import static com.android.server.testutils.TestUtils.assertExpectException;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.testng.Assert.assertThrows;

import static java.util.Collections.emptyList;

import android.Manifest.permission;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerLiteInternal;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.PasswordMetrics;
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.WifiSsidPolicy;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.StringParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.usb.UsbManager;
import android.net.ProfileNetworkPreference;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IpcDataCache;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.KeyChain;
import android.security.keystore.AttestationUtils;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.test.MoreAsserts;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;

import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;

import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsListener;
import com.android.server.pm.RestrictionsSet;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserRestrictionsUtils;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
import org.mockito.stubbing.Answer;

import java.io.File;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Tests for DevicePolicyManager( and DevicePolicyManagerService).
 *
 * <p>Run this test with:
 *
 * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.DevicePolicyManagerTest}
 *
 */
@SmallTest
@Presubmit
public class DevicePolicyManagerTest extends DpmTestBase {

    private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();

    private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
            permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
            permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
    public static final String NOT_DEVICE_OWNER_MSG = "does not own the device";
    public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile";
    public static final String NOT_ORG_OWNED_PROFILE_OWNER_MSG =
            "not the profile owner on organization-owned device";
    public static final String INVALID_CALLING_IDENTITY_MSG = "Calling identity is not authorized";
    public static final String ONGOING_CALL_MSG = "ongoing call on the device";

    // TODO replace all instances of this with explicit {@link #mServiceContext}.
    @Deprecated
    private DpmMockContext mContext;

    private DpmMockContext mServiceContext;
    private DpmMockContext mAdmin1Context;
    public DevicePolicyManager dpm;
    public DevicePolicyManager parentDpm;
    public DevicePolicyManagerServiceTestable dpms;

    private boolean mIsAutomotive;

    /*
     * The CA cert below is the content of cacert.pem as generated by:
     *
     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
     */
    private static final String TEST_CA =
            "-----BEGIN CERTIFICATE-----\n" +
            "MIIDXTCCAkWgAwIBAgIJAK9Tl/F9V8kSMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n" +
            "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n" +
            "aWRnaXRzIFB0eSBMdGQwHhcNMTUwMzA2MTczMjExWhcNMjUwMzAzMTczMjExWjBF\n" +
            "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n" +
            "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
            "CgKCAQEAvItOutsE75WBTgTyNAHt4JXQ3JoseaGqcC3WQij6vhrleWi5KJ0jh1/M\n" +
            "Rpry7Fajtwwb4t8VZa0NuM2h2YALv52w1xivql88zce/HU1y7XzbXhxis9o6SCI+\n" +
            "oVQSbPeXRgBPppFzBEh3ZqYTVhAqw451XhwdA4Aqs3wts7ddjwlUzyMdU44osCUg\n" +
            "kVg7lfPf9sTm5IoHVcfLSCWH5n6Nr9sH3o2ksyTwxuOAvsN11F/a0mmUoPciYPp+\n" +
            "q7DzQzdi7akRG601DZ4YVOwo6UITGvDyuAAdxl5isovUXqe6Jmz2/myTSpAKxGFs\n" +
            "jk9oRoG6WXWB1kni490GIPjJ1OceyQIDAQABo1AwTjAdBgNVHQ4EFgQUH1QIlPKL\n" +
            "p2OQ/AoLOjKvBW4zK3AwHwYDVR0jBBgwFoAUH1QIlPKLp2OQ/AoLOjKvBW4zK3Aw\n" +
            "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcMi4voMMJHeQLjtq8Oky\n" +
            "Azpyk8moDwgCd4llcGj7izOkIIFqq/lyqKdtykVKUWz2bSHO5cLrtaOCiBWVlaCV\n" +
            "DYAnnVLM8aqaA6hJDIfaGs4zmwz0dY8hVMFCuCBiLWuPfiYtbEmjHGSmpQTG6Qxn\n" +
            "ZJlaK5CZyt5pgh5EdNdvQmDEbKGmu0wpCq9qjZImwdyAul1t/B0DrsWApZMgZpeI\n" +
            "d2od0VBrCICB1K4p+C51D93xyQiva7xQcCne+TAnGNy9+gjQ/MyR8MRpwRLv5ikD\n" +
            "u0anJCN8pXo6IMglfMAsoton1J6o5/ae5uhC6caQU8bNUsCK570gpNfjkzo6rbP0\n" +
            "wQ==\n" +
            "-----END CERTIFICATE-----\n";

    // Constants for testing setManagedProfileMaximumTimeOff:
    // Profile maximum time off value
    private static final long PROFILE_OFF_TIMEOUT = TimeUnit.DAYS.toMillis(5);
    // Synthetic time at the beginning of test.
    private static final long PROFILE_OFF_START = 1;
    // Time when warning notification should be posted,
    private static final long PROFILE_OFF_WARNING_TIME =
            PROFILE_OFF_START + PROFILE_OFF_TIMEOUT - TimeUnit.DAYS.toMillis(1);
    // Time when the apps should be suspended
    private static final long PROFILE_OFF_DEADLINE = PROFILE_OFF_START + PROFILE_OFF_TIMEOUT;
    // Notification title and text for setManagedProfileMaximumTimeOff tests:
    private static final String PROFILE_OFF_SUSPENSION_TITLE = "suspension_title";
    private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text";
    private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text";
    private static final String FLAG_ENABLE_WORK_PROFILE_TELEPHONY =
            "enable_work_profile_telephony";

    @Before
    public void setUp() throws Exception {

        // Disable caches in this test process. This must happen early, since some of the
        // following initialization steps invalidate caches.
        IpcDataCache.disableForTestMode();

        mContext = getContext();
        mServiceContext = mContext;
        mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().userManagerInternal.getUserIds()).thenReturn(new int[]{0});
        when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                .thenReturn(true);
        doReturn(Collections.singletonList(new ResolveInfo()))
                .when(getServices().packageManager).queryBroadcastReceiversAsUser(
                        any(Intent.class),
                        anyInt(),
                        any(UserHandle.class));

        // Make createContextAsUser to work.
        mContext.packageName = "com.android.frameworks.servicestests";
        getServices().addPackageContext(UserHandle.of(0), mContext);
        getServices().addPackageContext(UserHandle.of(CALLER_USER_HANDLE), mContext);

        // By default, pretend all users are running and unlocked.
        when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);

        initializeDpms();

        Mockito.reset(getServices().usageStatsManagerInternal);
        Mockito.reset(getServices().networkPolicyManagerInternal);
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID);

        mAdmin1Context = new DpmMockContext(getServices(), mRealTestContext);
        mAdmin1Context.packageName = admin1.getPackageName();
        mAdmin1Context.applicationInfo = new ApplicationInfo();
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;

        setUpUserManager();

        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);

        mIsAutomotive = mContext.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);

        final String TEST_STRING = "{count, plural,\n"
                + "        =1    {Test for exactly 1 cert out of 4}\n"
                + "        other {Test for exactly # certs out of 4}\n"
                + "}";
        doReturn(TEST_STRING)
                .when(mContext.resources)
                .getString(R.string.ssl_ca_cert_warning);
    }

    private TransferOwnershipMetadataManager getMockTransferMetadataManager() {
        return dpms.mTransferOwnershipMetadataManager;
    }

    @After
    public void tearDown() throws Exception {
        flushTasks(dpms);
        getMockTransferMetadataManager().deleteMetadataFile();
    }

    private void initializeDpms() {
        // Need clearCallingIdentity() to pass permission checks.
        final long ident = mContext.binder.clearCallingIdentity();

        dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
        dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
        dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);

        dpm = new DevicePolicyManagerTestable(mContext, dpms);

        parentDpm = new DevicePolicyManagerTestable(mServiceContext, dpms,
                /* parentInstance= */true);

        mContext.binder.restoreCallingIdentity(ident);
    }

    private void setUpUserManager() {
        // Emulate UserManager.set/getApplicationRestriction().
        final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();

        // UM.setApplicationRestrictions() will save to appRestrictions.
        doAnswer((Answer<Void>) invocation -> {
            String pkg = (String) invocation.getArguments()[0];
            Bundle bundle = (Bundle) invocation.getArguments()[1];
            UserHandle user = (UserHandle) invocation.getArguments()[2];

            appRestrictions.put(Pair.create(pkg, user), bundle);

            return null;
        }).when(getServices().userManager).setApplicationRestrictions(
                anyString(), nullable(Bundle.class), any(UserHandle.class));

        // UM.getApplicationRestrictions() will read from appRestrictions.
        doAnswer((Answer<Bundle>) invocation -> {
            String pkg = (String) invocation.getArguments()[0];
            UserHandle user = (UserHandle) invocation.getArguments()[1];

            return appRestrictions.get(Pair.create(pkg, user));
        }).when(getServices().userManager).getApplicationRestrictions(
                anyString(), any(UserHandle.class));

        // Emulate UserManager.setUserRestriction/getUserRestrictions
        final Map<UserHandle, Bundle> userRestrictions = new HashMap<>();

        doAnswer((Answer<Void>) invocation -> {
            String key = (String) invocation.getArguments()[0];
            boolean value = (Boolean) invocation.getArguments()[1];
            UserHandle user = (UserHandle) invocation.getArguments()[2];
            Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle());
            userBundle.putBoolean(key, value);

            userRestrictions.put(user, userBundle);
            return null;
        }).when(getServices().userManager).setUserRestriction(
                anyString(), anyBoolean(), any(UserHandle.class));

        doAnswer((Answer<Boolean>) invocation -> {
            String key = (String) invocation.getArguments()[0];
            UserHandle user = (UserHandle) invocation.getArguments()[1];
            Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle());
            return userBundle.getBoolean(key);
        }).when(getServices().userManager).hasUserRestriction(
                anyString(), any(UserHandle.class));

        // Add the first secondary user.
        getServices().addUser(CALLER_USER_HANDLE, 0, UserManager.USER_TYPE_FULL_SECONDARY);
    }

    private void setAsProfileOwner(ComponentName admin) {
        final long ident = mServiceContext.binder.clearCallingIdentity();

        mServiceContext.binder.callingUid =
                UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
        runAsCaller(mServiceContext, dpms, dpm -> {
            // PO needs to be a DA.
            dpm.setActiveAdmin(admin, /*replace=*/ false);
            // Fire!
            assertThat(dpm.setProfileOwner(admin, CALLER_USER_HANDLE)).isTrue();
            // Check
            assertThat(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)).isEqualTo(admin);
        });

        mServiceContext.binder.restoreCallingIdentity(ident);
    }

    @Test
    public void testHasNoFeature() throws Exception {
        when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                .thenReturn(false);

        new DevicePolicyManagerServiceTestable(getServices(), mContext);

        // If the device has no DPMS feature, it shouldn't register the local service.
        assertThat(LocalServices.getService(DevicePolicyManagerInternal.class)).isNull();

        // But should still register the lite one
        assertThat(LocalServices.getService(DevicePolicyManagerLiteInternal.class)).isNotNull();
    }

    @Test
    public void testLoadAdminData() throws Exception {
        // Device owner in SYSTEM_USER
        setDeviceOwner();
        // Profile owner in CALLER_USER_HANDLE
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
        setAsProfileOwner(admin2);
        // Active admin in CALLER_USER_HANDLE
        final int ANOTHER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 1306);
        setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
        dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false, CALLER_USER_HANDLE);
        assertThat(dpm.isAdminActiveAsUser(adminAnotherPackage, CALLER_USER_HANDLE)).isTrue();

        initializeDpms();

        // Verify
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkApps(admin1.getPackageName()),
                eq(UserHandle.USER_SYSTEM));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkApps(admin2.getPackageName(),
                        adminAnotherPackage.getPackageName()),
                eq(CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
        verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
    }

    @Test
    public void testLoadAdminData_noAdmins() throws Exception {
        final int ANOTHER_USER_ID = 15;
        getServices().addUser(ANOTHER_USER_ID, 0, "");

        initializeDpms();

        // Verify
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, ANOTHER_USER_ID);
        verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
        verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
    }

    /**
     * Caller doesn't have proper permissions.
     */
    @Test
    public void testSetActiveAdmin_SecurityException() {
        // 1. Failure cases.

        // Caller doesn't have MANAGE_DEVICE_ADMINS.
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setActiveAdmin(admin1, false));

        // Caller has MANAGE_DEVICE_ADMINS, but for different user.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setActiveAdmin(admin1, false, CALLER_USER_HANDLE + 1));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setActiveAdmin}
     * with replace=false and replace=true
     * {@link DevicePolicyManager#isAdminActive}
     * {@link DevicePolicyManager#isAdminActiveAsUser}
     * {@link DevicePolicyManager#getActiveAdmins}
     * {@link DevicePolicyManager#getActiveAdminsAsUser}
     */
    @Test
    public void testSetActiveAdmin() throws Exception {
        // 1. Make sure the caller has proper permissions.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // 2. Call the API.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        // 3. Verify internal calls.

        // Check if the boradcast is sent.
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));

        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
                eq(admin1.getPackageName()),
                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
                eq(PackageManager.DONT_KILL_APP),
                eq(CALLER_USER_HANDLE),
                anyString());

        verify(getServices().usageStatsManagerInternal).onActiveAdminAdded(
                admin1.getPackageName(), CALLER_USER_HANDLE);

        // TODO Verify other calls too.

        // Make sure it's active admin1.
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isAdminActive(admin2)).isFalse();
        assertThat(dpm.isAdminActive(admin3)).isFalse();

        // But not admin1 for a different user.

        // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
        // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");

        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE + 1)).isFalse();
        assertThat(dpm.isAdminActiveAsUser(admin2, CALLER_USER_HANDLE + 1)).isFalse();

        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");

        // Next, add one more admin.
        // Before doing so, update the application info, now it's enabled.
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID,
                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);

        dpm.setActiveAdmin(admin2, /* replace =*/ false);

        // Now we have two admins.
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isAdminActive(admin2)).isTrue();
        assertThat(dpm.isAdminActive(admin3)).isFalse();

        // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
        // again.  (times(1) because it was previously called for admin1)
        verify(getServices().ipackageManager, times(1)).setApplicationEnabledSetting(
                eq(admin1.getPackageName()),
                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
                eq(PackageManager.DONT_KILL_APP),
                eq(CALLER_USER_HANDLE),
                anyString());

        // times(2) because it was previously called for admin1 which is in the same package
        // as admin2.
        verify(getServices().usageStatsManagerInternal, times(2)).onActiveAdminAdded(
                admin2.getPackageName(), CALLER_USER_HANDLE);

        // 4. Add the same admin1 again without replace, which should throw.
        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                () -> dpm.setActiveAdmin(admin1, /* replace =*/ false));

        // 5. Add the same admin1 again with replace, which should succeed.
        dpm.setActiveAdmin(admin1, /* replace =*/ true);

        // TODO make sure it's replaced.

        // 6. Test getActiveAdmins()
        List<ComponentName> admins = dpm.getActiveAdmins();
        assertThat(admins.size()).isEqualTo(2);
        assertThat(admins.get(0)).isEqualTo(admin1);
        assertThat(admins.get(1)).isEqualTo(admin2);

        // There shouldn't be any callback to UsageStatsManagerInternal when the admin is being
        // replaced
        verifyNoMoreInteractions(getServices().usageStatsManagerInternal);

        // Another user has no admins.
        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");

        assertThat(DpmTestUtils.getListSizeAllowingNull(
        dpm.getActiveAdminsAsUser(CALLER_USER_HANDLE + 1))).isEqualTo(0);

        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
    }

    @Test
    public void testSetActiveAdmin_multiUsers() throws Exception {

        final int ANOTHER_USER_ID = 100;
        final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456);

        getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user.

        // Set up pacakge manager for the other user.
        setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);

        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
        dpm.setActiveAdmin(admin2, /* replace =*/ false);


        mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isAdminActive(admin2)).isFalse();

        mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
        assertThat(dpm.isAdminActive(admin1)).isFalse();
        assertThat(dpm.isAdminActive(admin2)).isTrue();
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setActiveAdmin}
     * with replace=false
     */
    @Test
    public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
        // 1. Make sure the caller has proper permissions.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        // Add the same admin1 again without replace, which should throw.
        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                () -> dpm.setActiveAdmin(admin1, /* replace =*/ false));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with
     * BIND_DEVICE_ADMIN.
     */
    @Test
    public void testSetActiveAdmin_permissionCheck() throws Exception {
        // 1. Make sure the caller has proper permissions.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        assertExpectException(IllegalArgumentException.class,
                /* messageRegex= */ permission.BIND_DEVICE_ADMIN,
                () -> dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false));
        assertThat(dpm.isAdminActive(adminNoPerm)).isFalse();

        // Change the target API level to MNC.  Now it can be set as DA.
        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null,
                VERSION_CODES.M);
        dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
        assertThat(dpm.isAdminActive(adminNoPerm)).isTrue();

        // TODO Test the "load from the file" case where DA will still be loaded even without
        // BIND_DEVICE_ADMIN and target API is N.
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#removeActiveAdmin}
     */
    @Test
    public void testRemoveActiveAdmin_SecurityException() {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin1)).isTrue();

        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // Directly call the DPMS method with a different userid, which should fail.
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE + 1));

        // Try to remove active admin with a different caller userid should fail too, without
        // having MANAGE_DEVICE_ADMINS.
        mContext.callerPermissions.clear();

        // Change the caller, and call into DPMS directly with a different user-id.

        mContext.binder.callingUid = 1234567;
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE));
    }

    /**
     * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked
     * (because we can't send the remove broadcast).
     */
    @Test
    public void testRemoveActiveAdmin_userNotRunningOrLocked() {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        // Add admin.

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin1)).isTrue();

        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // 1. User not unlocked.
        setUserUnlocked(CALLER_USER_HANDLE, false);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "User must be running and unlocked",
                () -> dpm.removeActiveAdmin(admin1));

        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps(
                null, CALLER_USER_HANDLE);

        // 2. User unlocked.
        setUserUnlocked(CALLER_USER_HANDLE, true);

        dpm.removeActiveAdmin(admin1);
        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#removeActiveAdmin}
     */
    @Test
    public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);

        // Add admin1.

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // Different user, but should work, because caller has proper permissions.
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Change the caller, and call into DPMS directly with a different user-id.
        mContext.binder.callingUid = 1234567;

        dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE);
        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);

        // TODO DO Still can't be removed in this case.
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#removeActiveAdmin}
     */
    @Test
    public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin1.

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // Broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));

        // Remove.  No permissions, but same user, so it'll work.
        mContext.callerPermissions.clear();
        dpm.removeActiveAdmin(admin1);

        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                isNull(String.class),
                eq(AppOpsManager.OP_NONE),
                any(Bundle.class),
                any(BroadcastReceiver.class),
                eq(dpms.mHandler),
                eq(Activity.RESULT_OK),
                isNull(String.class),
                isNull(Bundle.class));

        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));

        // TODO Check other internal calls.
    }

    @Test
    public void testRemoveActiveAdmin_multipleAdminsInUser() {
        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin1.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // Add admin2.
        dpm.setActiveAdmin(admin2, /* replace =*/ false);

        assertThat(dpm.isAdminActive(admin2)).isTrue();
        assertThat(dpm.isRemovingAdmin(admin2, CALLER_USER_HANDLE)).isFalse();

        // Broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));

        // Remove.  No permissions, but same user, so it'll work.
        mContext.callerPermissions.clear();
        dpm.removeActiveAdmin(admin1);

        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                isNull(String.class),
                eq(AppOpsManager.OP_NONE),
                any(Bundle.class),
                any(BroadcastReceiver.class),
                eq(dpms.mHandler),
                eq(Activity.RESULT_OK),
                isNull(String.class),
                isNull(Bundle.class));

        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkApps(admin2.getPackageName()),
                eq(CALLER_USER_HANDLE));

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
     */
    @Test
    public void testForceRemoveActiveAdmin_nonShellCaller() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.
        setupPackageInPackageManager(admin1.getPackageName(),
                /* userId= */ CALLER_USER_HANDLE,
                /* appId= */ 10138,
                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        // Calling from a non-shell uid should fail with a SecurityException
        mContext.binder.callingUid = 123456;
        assertExpectException(SecurityException.class,
                /* messageRegex = */ null,
                () -> dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
     */
    @Test
    public void testForceRemoveActiveAdmin_nonShellCallerWithPermission() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.
        setupPackageInPackageManager(admin1.getPackageName(),
                /* userId= */ CALLER_USER_HANDLE,
                /* appId= */ 10138,
                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        mContext.binder.callingUid = 123456;
        mContext.callerPermissions.add(
                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);

        mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        // Verify
        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
     */
    @Test
    public void testForceRemoveActiveAdmin_ShellCaller() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.
        setupPackageInPackageManager(admin1.getPackageName(),
                /* userId= */ CALLER_USER_HANDLE,
                /* appId= */ 10138,
                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        mContext.binder.callingUid = Process.SHELL_UID;
        dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);

        mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        // Verify
        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);
    }

    /**
     * Test for: {@link DevicePolicyManager#setPasswordHistoryLength(ComponentName, int)}
     *
     * Validates that when the password history length is set, it is persisted after rebooting
     */
    @Test
    public void testSaveAndLoadPasswordHistoryLength_persistedAfterReboot() throws Exception {
        int passwordHistoryLength = 2;

        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Install admin1 on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Set admin1 to active admin and device owner
        dpm.setActiveAdmin(admin1, false);
        dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM);

        // Save password history length
        dpm.setPasswordHistoryLength(admin1, passwordHistoryLength);

        assertThat(passwordHistoryLength).isEqualTo(dpm.getPasswordHistoryLength(admin1));

        initializeDpms();
        reset(mContext.spiedContext);

        // Password history length should persist after rebooted
        assertThat(passwordHistoryLength).isEqualTo(dpm.getPasswordHistoryLength(admin1));
    }

    /**
     * Test for: {@link DevicePolicyManager#reportPasswordChanged}
     *
     * Validates that when the password for a user changes, the notification broadcast intent
     * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in
     * addition to ones in the original user.
     */
    @Test
    public void testSetActivePasswordState_sendToProfiles() throws Exception {
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        final int MANAGED_PROFILE_USER_ID = 78;
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = admin1.getPackageName();

        // Add a managed profile belonging to the system user.
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Change the parent user's password.
        dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD),
                UserHandle.USER_SYSTEM);

        // The managed profile owner should receive this broadcast.
        final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
        intent.setComponent(admin1);
        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM));

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID),
                eq(null),
                any(Bundle.class));
    }

    /**
     * Test for: @{link DevicePolicyManager#reportPasswordChanged}
     *
     * Validates that when the password for a managed profile changes, the notification broadcast
     * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not
     * its parent.
     */
    @Test
    public void testSetActivePasswordState_notSentToParent() throws Exception {
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        final int MANAGED_PROFILE_USER_ID = 78;
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);

        // Configure system as having separate profile challenge.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = admin1.getPackageName();
        doReturn(true).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);

        // Add a managed profile belonging to the system user.
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Change the profile's password.
        dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD),
                MANAGED_PROFILE_USER_ID);

        // Both the device owner and the managed profile owner should receive this broadcast.
        final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
        intent.setComponent(admin1);
        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(MANAGED_PROFILE_USER_ID));

        verify(mContext.spiedContext, never()).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM),
                eq(null),
                any(Bundle.class));
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID),
                eq(null),
                any(Bundle.class));
    }

    /**
     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
     */
    @Test
    public void testSetDeviceOwner() throws Exception {
        setDeviceOwner();

        // Try to set a profile owner on the same user, which should fail.
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "already has a device owner",
                () -> dpm.setProfileOwner(admin2, UserHandle.USER_SYSTEM));

        // DO admin can't be deactivated.
        dpm.removeActiveAdmin(admin1);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        // TODO Test getDeviceOwnerName() too. To do so, we need to change
        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
    }

    private void setDeviceOwner() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // In this test, change the caller user to "system".
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure admin1 is installed on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Check various get APIs.
        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);

        // DO needs to be an DA.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        // Fire!
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        // getDeviceOwnerComponent should return the admin1 component.
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);

        // Check various get APIs.
        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);

        // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Verify internal calls.
        verify(getServices().userManager, times(1)).setUserRestriction(
                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
                eq(true), eq(UserHandle.SYSTEM));

        verify(getServices().userManager, times(1)).setUserRestriction(
                eq(UserManager.DISALLOW_ADD_CLONE_PROFILE),
                eq(true), eq(UserHandle.SYSTEM));

        verify(getServices().userManager, times(1)).setUserRestriction(
                eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE),
                eq(true), eq(UserHandle.SYSTEM));

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));

        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
    }

    // TODO(b/174859111): move to automotive-only section
    private void setDeviceOwner_headlessSystemUser() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);

        when(getServices().iactivityManager.getCurrentUser()).thenReturn(
                new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "caller",  /* flags=*/ 0));
        // Check various get APIs.
        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);

        final long ident = mServiceContext.binder.clearCallingIdentity();

        mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);

        // Set device owner
        runAsCaller(mServiceContext, dpms, dpm -> {
            // DO needs to be a DA
            dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
            // DO should be set on headless system user
            assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
            // PO should be set on calling user.
            assertThat(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)).isEqualTo(admin1);
        });

        mServiceContext.binder.restoreCallingIdentity(ident);

        // Check various get APIs.
        checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);

        // Add MANAGE_USERS or test purpose.
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        // getDeviceOwnerComponent should *NOT* return the admin1 component for calling user.
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isNull();
        // Device owner should be set on system user.
        assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);

        // Set calling user to be system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Device owner component should be admin1
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);

        // Verify internal calls.
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
    }

    private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
        final int origCallingUser = mContext.binder.callingUid;
        final List origPermissions = new ArrayList(mContext.callerPermissions);
        mContext.callerPermissions.clear();

        mContext.callerPermissions.add(permission.MANAGE_USERS);

        mContext.binder.callingUid = Process.SYSTEM_UID;

        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
        if (hasDeviceOwner) {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
        } else {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        if (hasDeviceOwner) {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
        } else {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        // Still with MANAGE_USERS.
        assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
        assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);

        if (hasDeviceOwner) {
            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
        } else {
            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
        }

        mContext.binder.callingUid = Process.SYSTEM_UID;
        mContext.callerPermissions.remove(permission.MANAGE_USERS);
        // System can still call "OnAnyUser" without MANAGE_USERS.
        if (hasDeviceOwner) {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
        } else {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);

            assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null);
            assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        // Still no MANAGE_USERS.
        if (hasDeviceOwner) {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);
        } else {
            assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
            assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
            assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);
        }

        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerComponentOnAnyUser);
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerUserId);
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerNameOnAnyUser);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        // Still no MANAGE_USERS.
        assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse();
        assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse();
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null);

        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerComponentOnAnyUser);
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerUserId);
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                dpm::getDeviceOwnerNameOnAnyUser);

        // Restore.
        mContext.binder.callingUid = origCallingUser;
        mContext.callerPermissions.addAll(origPermissions);
    }


    /**
     * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
     */
    @Test
    public void testSetDeviceOwner_noSuchPackage() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Call from a process on the system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        assertExpectException(IllegalArgumentException.class,
                /* messageRegex= */ "Invalid component",
                () -> dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"),
                        UserHandle.USER_SYSTEM));
    }

    @Test
    public void testSetDeviceOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetDeviceOwner().
        // Package doesn't exist and caller is not system
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Calling identity is not authorized",
                () -> dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM));

        // Package exists, but caller is not system
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Calling identity is not authorized",
                () -> dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM));
    }

    @Test
    @Ignore("b/277916462")
    public void testClearDeviceOwner() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Set admin1 as a DA to the secondary user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        // Set admin 1 as the DO to the system user.

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
        when(getServices().userManager.hasUserRestriction(eq(UserManager.DISALLOW_ADD_USER),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM))).thenReturn(true);

        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM)).isFalse();

        // Set up other mocks.
        when(getServices().userManager.getUserRestrictions()).thenReturn(new Bundle());

        // Now call clear.
        getServices().addTestPackageUid(admin1.getPackageName(),
                DpmMockContext.CALLER_SYSTEM_USER_UID);

        // But first pretend the user is locked.  Then it should fail.
        when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(false);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "User must be running and unlocked",
                () -> dpm.clearDeviceOwnerApp(admin1.getPackageName()));

        when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);
        dpm.clearDeviceOwnerApp(admin1.getPackageName());

        // Now DO shouldn't be set.
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isNull();

        verify(getServices().userManager).setUserRestriction(eq(UserManager.DISALLOW_ADD_USER),
                eq(false),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));

        verify(getServices().userManager)
                .setUserRestriction(eq(UserManager.DISALLOW_ADD_CLONE_PROFILE), eq(false),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));

        verify(getServices().userManager)
                .setUserRestriction(eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE), eq(false),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));

        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));

        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, UserHandle.USER_SYSTEM);

        assertThat(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM)).isFalse();

        // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner
        // and once for clearing it.
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
        // TODO Check other calls.
    }

    @Test
    public void testDeviceOwnerBackupActivateDeactivate() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        // Set admin1 as a DA to the secondary user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                eq(UserHandle.USER_SYSTEM), eq(false));

        dpm.clearDeviceOwnerApp(admin1.getPackageName());

        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                eq(UserHandle.USER_SYSTEM), eq(true));
    }

    @Test
    public void testProfileOwnerBackupActivateDeactivate() throws Exception {
        setAsProfileOwner(admin1);

        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                eq(CALLER_USER_HANDLE), eq(false));

        dpm.clearProfileOwner(admin1);

        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                eq(CALLER_USER_HANDLE), eq(true));
    }

    @Test
    public void testClearDeviceOwner_fromDifferentUser() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Set admin1 as a DA to the secondary user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);

        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        // Set admin 1 as the DO to the system user.

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);

        // Now call clear from the secondary user, which should throw.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        // Now call clear.
        getServices().addTestPackageUid(admin1.getPackageName(), DpmMockContext.CALLER_UID);
        assertExpectException(SecurityException.class,
                /* messageRegex =*/ "clearDeviceOwner can only be called by the device owner",
                () -> dpm.clearDeviceOwnerApp(admin1.getPackageName()));

        // DO shouldn't be removed.
        assertThat(dpm.isDeviceManaged()).isTrue();
    }

    /**
     * Test for: {@link DevicePolicyManager#clearDeviceOwnerApp(String)}
     *
     * Validates that when the device owner is removed, the reset password token is cleared
     */
    @Test
    @Ignore("b/277916462")
    public void testClearDeviceOwner_clearResetPasswordToken() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Install admin1 on system user
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Set admin1 to active admin and device owner
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM);

        // Add reset password token
        final long handle = 12000;
        final byte[] token = new byte[32];
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // Assert reset password token is active
        when(getServices().lockPatternUtils.isEscrowTokenActive(eq(handle),
                eq(UserHandle.USER_SYSTEM)))
                .thenReturn(true);
        assertThat(dpm.isResetPasswordTokenActive(admin1)).isTrue();

        // Remove the device owner
        dpm.clearDeviceOwnerApp(admin1.getPackageName());

        // Verify password reset password token was removed
        verify(getServices().lockPatternUtils).removeEscrowToken(eq(handle),
                eq(UserHandle.USER_SYSTEM));
    }

    @Test
    public void testSetProfileOwner() throws Exception {
        setAsProfileOwner(admin1);

        // PO admin can't be deactivated.
        dpm.removeActiveAdmin(admin1);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        // Try setting DO on the same user, which should fail.
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        runAsCaller(mServiceContext, dpms, dpm -> {
            dpm.setActiveAdmin(admin2, /* refreshing= */ true, CALLER_USER_HANDLE);
            assertExpectException(IllegalStateException.class,
                    /* messageRegex= */ "already has a profile owner",
                    () -> dpm.setDeviceOwner(admin2, CALLER_USER_HANDLE));
        });
    }

    @Test
    public void testClearProfileOwner() throws Exception {
        setAsProfileOwner(admin1);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isTrue();
        assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse();

        // First try when the user is locked, which should fail.
        when(getServices().userManager.isUserUnlocked(anyInt()))
                .thenReturn(false);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "User must be running and unlocked",
                () -> dpm.clearProfileOwner(admin1));

        // Clear, really.
        when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);
        dpm.clearProfileOwner(admin1);

        // Check
        assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isFalse();
        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, CALLER_USER_HANDLE);
    }

    @Test
    public void testSetProfileOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetProfileOwner().
        // Package doesn't exist and caller is not system
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Calling identity is not authorized",
                () -> dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM));

        // Package exists, but caller is not system
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Calling identity is not authorized",
                () -> dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM));
    }

    @Test
    public void testGetDeviceOwnerAdminLocked() throws Exception {
        checkDeviceOwnerWithMultipleDeviceAdmins();
    }

    // This method is used primarily for testDeviceOwnerMigration.
    private void checkDeviceOwnerWithMultipleDeviceAdmins() throws Exception {
        // In ths test, we use 3 users (system + 2 secondary users), set some device admins to them,
        // set admin3 on USER_SYSTEM as DO, then call getDeviceOwnerAdminLocked() to
        // make sure it gets the right component from the right user.

        final int ANOTHER_USER_ID = 100;
        final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456);

        getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user.

        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure the admin package is installed to each user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);

        setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);

        // Set active admins to the users.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        dpm.setActiveAdmin(admin3, /* replace =*/ false);

        dpm.setActiveAdmin(admin1, /* replace =*/ false, CALLER_USER_HANDLE);
        dpm.setActiveAdmin(admin2, /* replace =*/ false, CALLER_USER_HANDLE);

        dpm.setActiveAdmin(admin2, /* replace =*/ false, ANOTHER_USER_ID);

        // Set DO on the system user which is only allowed during first boot.
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
        assertThat(dpm.setDeviceOwner(admin3, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)).isEqualTo(admin3);

        // Then check getDeviceOwnerAdminLocked().
        ActiveAdmin deviceOwner = getDeviceOwner();
        assertThat(deviceOwner.info.getComponent()).isEqualTo(admin3);
        assertThat(deviceOwner.getUid()).isEqualTo(DpmMockContext.CALLER_SYSTEM_USER_UID);
    }

    @Test
    public void testSetGetApplicationRestriction() {
        setAsProfileOwner(admin1);
        mContext.packageName = admin1.getPackageName();

        {
            Bundle rest = new Bundle();
            rest.putString("KEY_STRING", "Foo1");
            dpm.setApplicationRestrictions(admin1, "pkg1", rest);
        }

        {
            Bundle rest = new Bundle();
            rest.putString("KEY_STRING", "Foo2");
            dpm.setApplicationRestrictions(admin1, "pkg2", rest);
        }

        {
            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
            assertThat(returned).isNotNull();
            assertThat(returned.size()).isEqualTo(1);
            assertThat("Foo1").isEqualTo(returned.get("KEY_STRING"));
        }

        {
            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
            assertThat(returned).isNotNull();
            assertThat(returned.size()).isEqualTo(1);
            assertThat("Foo2").isEqualTo(returned.get("KEY_STRING"));
        }

        dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
        assertThat(dpm.getApplicationRestrictions(admin1, "pkg2").size()).isEqualTo(0);
    }

    /**
     * Setup a package in the package manager mock for {@link DpmMockContext#CALLER_USER_HANDLE}.
     * Useful for faking installed applications.
     *
     * @param packageName the name of the package to be setup
     * @param appId the application ID to be given to the package
     * @return the UID of the package as known by the mock package manager
     */
    private int setupPackageInPackageManager(final String packageName, final int appId)
            throws Exception {
        return setupPackageInPackageManager(packageName, CALLER_USER_HANDLE, appId,
                ApplicationInfo.FLAG_HAS_CODE);
    }

    /**
     * Setup a package in the package manager mock. Useful for faking installed applications.
     *
     * @param packageName the name of the package to be setup
     * @param userId the user id where the package will be "installed"
     * @param appId the application ID to be given to the package
     * @param flags flags to set in the ApplicationInfo for this package
     * @return the UID of the package as known by the mock package manager
     */
    private int setupPackageInPackageManager(final String packageName, int userId, final int appId,
            int flags) throws Exception {
        final int uid = UserHandle.getUid(userId, appId);
        // Make the PackageManager return the package instead of throwing NameNotFoundException
        final PackageInfo pi = new PackageInfo();
        pi.applicationInfo = new ApplicationInfo();
        pi.applicationInfo.flags = flags;
        doReturn(pi).when(getServices().ipackageManager).getPackageInfo(
                eq(packageName),
                anyLong(),
                eq(userId));
        doReturn(pi.applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
                eq(packageName),
                anyLong(),
                eq(userId));
        doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId);
        // Setup application UID with the PackageManager
        getServices().addTestPackageUid(packageName, uid);
        // Associate packageName to uid
        doReturn(packageName).when(getServices().ipackageManager).getNameForUid(eq(uid));
        doReturn(new String[]{packageName})
                .when(getServices().ipackageManager).getPackagesForUid(eq(uid));
        return uid;
    }

    @Test
    public void testCertificateDisclosure() throws Exception {
        final int userId = CALLER_USER_HANDLE;
        final UserHandle user = UserHandle.of(userId);

        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.applicationInfo = new ApplicationInfo();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

        StringParceledListSlice oneCert = asSlice(new String[] {"1"});
        StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});

        // Given that we have exactly one certificate installed,
        when(getServices().keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert);
        // when that certificate is approved,
        dpms.approveCaCert(oneCert.getList().get(0), userId, true);
        // a notification should not be shown.
        verify(getServices().notificationManager, timeout(1000))
                .cancelAsUser(anyString(), anyInt(), eq(user));

        // Given that we have four certificates installed,
        when(getServices().keyChainConnection.getService().getUserCaAliases())
                .thenReturn(fourCerts);
        // when two of them are approved (one of them approved twice hence no action),
        dpms.approveCaCert(fourCerts.getList().get(0), userId, true);
        dpms.approveCaCert(fourCerts.getList().get(1), userId, true);
        // a notification should be shown saying that there are two certificates left to approve.
        final String TEST_STRING_RESULT = "Test for exactly 2 certs out of 4";
        verify(getServices().notificationManager, timeout(1000))
                .notifyAsUser(anyString(), anyInt(), argThat(hasExtra(EXTRA_TITLE,
                        TEST_STRING_RESULT
                )), eq(user));
    }

    @Test
    public void testRemoveCredentialManagementApp() throws Exception {
        final String packageName = "com.test.cred.mng";
        Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
        intent.setData(Uri.parse("package:" + packageName));
        dpms.mReceiver.setPendingResult(
                new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
                        "resultData",
                        /* resultExtras= */ null,
                        BroadcastReceiver.PendingResult.TYPE_UNREGISTERED,
                        /* ordered= */ true,
                        /* sticky= */ false,
                        /* token= */ null,
                        CALLER_USER_HANDLE,
                        /* flags= */ 0));
        when(getServices().keyChainConnection.getService().hasCredentialManagementApp())
                .thenReturn(true);
        when(getServices().keyChainConnection.getService().getCredentialManagementAppPackageName())
                .thenReturn(packageName);

        dpms.mReceiver.onReceive(mContext, intent);

        flushTasks(dpms);
        verify(getServices().keyChainConnection.getService()).hasCredentialManagementApp();
        verify(getServices().keyChainConnection.getService()).removeCredentialManagementApp();
    }

    /**
     * Simple test for delegate set/get and general delegation. Tests verifying that delegated
     * privileges can acually be exercised by a delegate are not covered here.
     */
    @Test
    @Ignore // temp dsiabled - broken with flags
    public void testDelegation() throws Exception {
        setAsProfileOwner(admin1);

        final int userHandle = CALLER_USER_HANDLE;

        // Given two packages
        final String CERT_DELEGATE = "com.delegate.certs";
        final String RESTRICTIONS_DELEGATE = "com.delegate.apprestrictions";
        final int CERT_DELEGATE_UID = setupPackageInPackageManager(CERT_DELEGATE, 20988);
        final int RESTRICTIONS_DELEGATE_UID = setupPackageInPackageManager(RESTRICTIONS_DELEGATE,
                20989);

        // On delegation
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        dpm.setCertInstallerPackage(admin1, CERT_DELEGATE);
        dpm.setApplicationRestrictionsManagingPackage(admin1, RESTRICTIONS_DELEGATE);

        // DPMS correctly stores and retrieves the delegates
        DevicePolicyData policy = dpms.mUserData.get(userHandle);
        assertThat(policy.mDelegationMap.size()).isEqualTo(2);
        MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE),
            DELEGATION_CERT_INSTALL);
        MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, CERT_DELEGATE),
            DELEGATION_CERT_INSTALL);
        assertThat(dpm.getCertInstallerPackage(admin1)).isEqualTo(CERT_DELEGATE);
        MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(RESTRICTIONS_DELEGATE),
            DELEGATION_APP_RESTRICTIONS);
        MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, RESTRICTIONS_DELEGATE),
            DELEGATION_APP_RESTRICTIONS);
        assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1))
                .isEqualTo(RESTRICTIONS_DELEGATE);

        // On calling install certificate APIs from an unauthorized process
        mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID;
        mContext.packageName = RESTRICTIONS_DELEGATE;

        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.installCaCert(null, null));

        // On calling install certificate APIs from an authorized process
        mContext.binder.callingUid = CERT_DELEGATE_UID;
        mContext.packageName = CERT_DELEGATE;

        // DPMS executes without a SecurityException
        try {
            dpm.installCaCert(null, null);
        } catch (SecurityException unexpected) {
            fail("Threw SecurityException on authorized access");
        } catch (NullPointerException expected) {
        }

        // On removing a delegate
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        dpm.setCertInstallerPackage(admin1, null);

        // DPMS does not allow access to ex-delegate
        mContext.binder.callingUid = CERT_DELEGATE_UID;
        mContext.packageName = CERT_DELEGATE;
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.installCaCert(null, null));

        // But still allows access to other existing delegates
        mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID;
        mContext.packageName = RESTRICTIONS_DELEGATE;
        try {
            dpm.getApplicationRestrictions(null, "pkg");
        } catch (SecurityException expected) {
            fail("Threw SecurityException on authorized access");
        }
    }

    @Test
    @Ignore // Temp disabled - broken with flags
    public void testApplicationRestrictionsManagingApp() throws Exception {
        setAsProfileOwner(admin1);

        final String nonExistAppRestrictionsManagerPackage = "com.google.app.restrictions.manager2";
        final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
        final String nonDelegateExceptionMessageRegex =
                "Caller with uid \\d+ is not com.google.app.restrictions.manager";
        final int appRestrictionsManagerAppId = 20987;
        final int appRestrictionsManagerUid = setupPackageInPackageManager(
                appRestrictionsManagerPackage, appRestrictionsManagerAppId);

        // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
        // delegated that permission yet.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse();
        final Bundle rest = new Bundle();
        rest.putString("KEY_STRING", "Foo1");
        assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG,
                () -> dpm.setApplicationRestrictions(null, "pkg1", rest));

        // Check via the profile owner that no restrictions were set.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        assertThat(dpm.getApplicationRestrictions(admin1, "pkg1").size()).isEqualTo(0);

        // Check the API does not allow setting a non-existent package
        assertExpectException(PackageManager.NameNotFoundException.class,
                /* messageRegex= */ nonExistAppRestrictionsManagerPackage,
                () -> dpm.setApplicationRestrictionsManagingPackage(
                        admin1, nonExistAppRestrictionsManagerPackage));

        // Let appRestrictionsManagerPackage manage app restrictions
        dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
        assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1))
                .isEqualTo(appRestrictionsManagerPackage);

        // Now that package should be able to set and retrieve app restrictions.
        mContext.binder.callingUid = appRestrictionsManagerUid;
        mContext.packageName = appRestrictionsManagerPackage;
        assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isTrue();
        dpm.setApplicationRestrictions(null, "pkg1", rest);
        Bundle returned = dpm.getApplicationRestrictions(null, "pkg1");
        assertThat(returned.size()).isEqualTo(1);
        assertThat(returned.get("KEY_STRING")).isEqualTo("Foo1");

        // The same app running on a separate user shouldn't be able to manage app restrictions.
        mContext.binder.callingUid = UserHandle.getUid(
                UserHandle.USER_SYSTEM, appRestrictionsManagerAppId);
        assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse();
        assertExpectException(SecurityException.class, nonDelegateExceptionMessageRegex,
                () -> dpm.setApplicationRestrictions(null, "pkg1", rest));

        // The DPM is still able to manage app restrictions, even if it allowed another app to do it
        // too.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        assertThat(dpm.getApplicationRestrictions(admin1, "pkg1")).isEqualTo(returned);
        dpm.setApplicationRestrictions(admin1, "pkg1", null);
        assertThat(dpm.getApplicationRestrictions(admin1, "pkg1").size()).isEqualTo(0);

        // Removing the ability for the package to manage app restrictions.
        dpm.setApplicationRestrictionsManagingPackage(admin1, null);
        assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1)).isNull();
        mContext.binder.callingUid = appRestrictionsManagerUid;
        mContext.packageName = appRestrictionsManagerPackage;
        assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse();
        assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG,
                () -> dpm.setApplicationRestrictions(null, "pkg1", null));
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserRestriction_asDo() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // First, set DO.

        // Call from a process on the system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure admin1 is installed on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Call.
        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        assertNoDeviceOwnerRestrictions();
        reset(getServices().userManagerInternal);

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
                        UserManager.DISALLOW_OUTGOING_CALLS),
                eq(true));
        reset(getServices().userManagerInternal);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
                getDeviceOwner().ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
                dpm.getUserRestrictions(admin1)
        );

        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
                        UserManager.DISALLOW_OUTGOING_CALLS),
                eq(true));
        reset(getServices().userManagerInternal);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
                getDeviceOwner().ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
                dpm.getUserRestrictions(admin1)
        );

        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);

        assertNoDeviceOwnerRestrictions();

        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE are PO restrictions, but when
        // DO sets them, the scope is global.
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
        reset(getServices().userManagerInternal);
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);

        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
        reset(getServices().userManagerInternal);

        // More tests.
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
                        UserManager.DISALLOW_ADD_USER),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);

        dpm.setCameraDisabled(admin1, true);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                // DISALLOW_CAMERA will be applied globally.
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_CAMERA),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
        reset(getServices().userManagerInternal);
    }

    private ActiveAdmin getDeviceOwner() {
        ComponentName component = dpms.mOwners.getDeviceOwnerComponent();
        DevicePolicyData policy =
                dpms.getUserData(dpms.mOwners.getDeviceOwnerUserId());
        for (ActiveAdmin admin : policy.mAdminList) {
            if (component.equals(admin.info.getComponent())) {
                return admin;
            }
        }
        return null;
    }

    @Test
    public void testDaDisallowedPolicies_SecurityException() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID, null,
                Build.VERSION_CODES.Q);
        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);


        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        boolean originalCameraDisabled = dpm.getCameraDisabled(admin1);
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setCameraDisabled(admin1, true));
        assertThat(dpm.getCameraDisabled(admin1)).isEqualTo(originalCameraDisabled);

        int originalKeyguardDisabledFeatures = dpm.getKeyguardDisabledFeatures(admin1);
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setKeyguardDisabledFeatures(admin1,
                        DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL));
        assertThat(dpm.getKeyguardDisabledFeatures(admin1))
                .isEqualTo(originalKeyguardDisabledFeatures);

        long originalPasswordExpirationTimeout = dpm.getPasswordExpirationTimeout(admin1);
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setPasswordExpirationTimeout(admin1, 1234));
        assertThat(dpm.getPasswordExpirationTimeout(admin1))
                .isEqualTo(originalPasswordExpirationTimeout);

        if (isDeprecatedPasswordApisSupported()) {
            int originalPasswordQuality = dpm.getPasswordQuality(admin1);
            assertExpectException(SecurityException.class, /* messageRegex= */ null,
                    () -> dpm.setPasswordQuality(admin1,
                            DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
            assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality);
        }
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserRestriction_asPo() {
        setAsProfileOwner(admin1);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE).ensureUserRestrictions()
        );

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
                eq(false));

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                        UserManager.DISALLOW_OUTGOING_CALLS),
                eq(false));

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpm.getUserRestrictions(admin1)
        );

        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
                        UserManager.DISALLOW_OUTGOING_CALLS),
                eq(false));

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpm.getUserRestrictions(admin1)
        );

        dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE), eq(false));

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpm.getUserRestrictions(admin1)
        );

        // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even
        // though when DO sets them they'll be applied globally.
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);

        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
                        UserManager.DISALLOW_ADJUST_VOLUME,
                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
                eq(false));

        dpm.setCameraDisabled(admin1, true);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE,
                        UserManager.DISALLOW_ADJUST_VOLUME,
                        UserManager.DISALLOW_UNMUTE_MICROPHONE,
                        UserManager.DISALLOW_CAMERA),
                eq(false));
        reset(getServices().userManagerInternal);

        // TODO Make sure restrictions are written to the file.
    }

    private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
            Sets.newSet(
                    UserManager.DISALLOW_AIRPLANE_MODE,
                    UserManager.DISALLOW_CONFIG_DATE_TIME,
                    UserManager.DISALLOW_CONFIG_PRIVATE_DNS
            );

    private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS =
            Sets.newSet(
                    UserManager.DISALLOW_CONFIG_BLUETOOTH,
                    UserManager.DISALLOW_CONFIG_LOCATION,
                    UserManager.DISALLOW_CONFIG_WIFI,
                    UserManager.DISALLOW_CONTENT_CAPTURE,
                    UserManager.DISALLOW_CONTENT_SUGGESTIONS,
                    UserManager.DISALLOW_DEBUGGING_FEATURES,
                    UserManager.DISALLOW_SHARE_LOCATION,
                    UserManager.DISALLOW_OUTGOING_CALLS,
                    UserManager.DISALLOW_BLUETOOTH_SHARING,
                    UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
                    UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
                    UserManager.DISALLOW_CONFIG_TETHERING,
                    UserManager.DISALLOW_DATA_ROAMING,
                    UserManager.DISALLOW_SAFE_BOOT,
                    UserManager.DISALLOW_SMS,
                    UserManager.DISALLOW_USB_FILE_TRANSFER,
                    UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
                    UserManager.DISALLOW_UNMUTE_MICROPHONE
            );

    @Test
    @Ignore("b/277916462")
    public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS) {
            addAndRemoveGlobalUserRestrictionOnParentDpm(restriction);
        }
        for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS) {
            addAndRemoveLocalUserRestrictionOnParentDpm(restriction);
        }

        parentDpm.setCameraDisabled(admin1, true);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
                        UserManager.DISALLOW_CAMERA),
                eq(false));
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .getParentActiveAdmin()
                        .getEffectiveRestrictions()
        );

        parentDpm.setCameraDisabled(admin1, false);
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .getParentActiveAdmin()
                        .getEffectiveRestrictions()
        );
        reset(getServices().userManagerInternal);
    }

    private void addAndRemoveGlobalUserRestrictionOnParentDpm(String restriction) {
        parentDpm.addUserRestriction(admin1, restriction);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(restriction),
                MockUtils.checkUserRestrictions(CALLER_USER_HANDLE),
                eq(false));
        parentDpm.clearUserRestriction(admin1, restriction);
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .getParentActiveAdmin()
                        .getEffectiveRestrictions()
        );
    }

    private void addAndRemoveLocalUserRestrictionOnParentDpm(String restriction) {
        parentDpm.addUserRestriction(admin1, restriction);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM, restriction),
                eq(false));
        parentDpm.clearUserRestriction(admin1, restriction);
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(CALLER_USER_HANDLE)
                        .getParentActiveAdmin()
                        .getEffectiveRestrictions()
        );
    }

    @Test
    @Ignore("b/277916462")
    public void testNoDefaultEnabledUserRestrictions() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // First, set DO.

        // Call from a process on the system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure admin1 is installed on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        assertNoDeviceOwnerRestrictions();

        reset(getServices().userManagerInternal);

        // Ensure the DISALLOW_REMOVE_MANAGED_PROFILES restriction doesn't show up as a
        // restriction to the device owner.
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
        assertNoDeviceOwnerRestrictions();
    }

    private void assertNoDeviceOwnerRestrictions() {
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                getDeviceOwner().getEffectiveRestrictions()
        );
    }

    @Test
    public void testSetFactoryResetProtectionPolicyWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn(
                DpmMockContext.CALLER_UID);

        FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                .setFactoryResetProtectionAccounts(new ArrayList<>())
                .setFactoryResetProtectionEnabled(false)
                .build();
        dpm.setFactoryResetProtectionPolicy(admin1, policy);

        FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(admin1);
        assertThat(result).isEqualTo(policy);
        assertPoliciesAreEqual(policy, result);

        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
    }

    @Test
    public void testSetFactoryResetProtectionPolicyFailWithPO() throws Exception {
        setupProfileOwner();

        FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                .setFactoryResetProtectionEnabled(false)
                .build();

        assertExpectException(SecurityException.class, null,
                () -> dpm.setFactoryResetProtectionPolicy(admin1, policy));
    }

    @Test
    public void testSetFactoryResetProtectionPolicyWithPOOfOrganizationOwnedDevice()
            throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn(
                DpmMockContext.CALLER_UID);

        List<String> accounts = new ArrayList<>();
        accounts.add("Account 1");
        accounts.add("Account 2");

        FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                .setFactoryResetProtectionAccounts(accounts)
                .build();

        dpm.setFactoryResetProtectionPolicy(admin1, policy);

        FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(admin1);
        assertThat(result).isEqualTo(policy);
        assertPoliciesAreEqual(policy, result);

        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(null),
                any(Bundle.class));
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE));
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
    }

    @Test
    public void testGetFactoryResetProtectionPolicyWithFrpManagementAgent()
            throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn(
                DpmMockContext.CALLER_UID);

        FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                .setFactoryResetProtectionAccounts(new ArrayList<>())
                .setFactoryResetProtectionEnabled(false)
                .build();

        dpm.setFactoryResetProtectionPolicy(admin1, policy);

        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        dpm.setActiveAdmin(admin1, /*replace=*/ false);
        FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(null);
        assertThat(result).isEqualTo(policy);
        assertPoliciesAreEqual(policy, result);

        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE),
                eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
    }

    private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy,
            FactoryResetProtectionPolicy actualPolicy) {
        assertThat(actualPolicy.isFactoryResetProtectionEnabled()).isEqualTo(
                expectedPolicy.isFactoryResetProtectionEnabled());
        assertAccountsAreEqual(expectedPolicy.getFactoryResetProtectionAccounts(),
                actualPolicy.getFactoryResetProtectionAccounts());
    }

    private void assertAccountsAreEqual(List<String> expectedAccounts,
            List<String> actualAccounts) {
        assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
    }

    @Test
    public void testSetPermittedInputMethodsWithPOOfOrganizationOwnedDevice()
            throws Exception {
        String packageName = "com.google.pkg.one";
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        // Allow all input methods
        parentDpm.setPermittedInputMethods(admin1, null);

        assertThat(parentDpm.getPermittedInputMethods(admin1)).isNull();

        // Allow only system input methods
        parentDpm.setPermittedInputMethods(admin1, new ArrayList<>());

        assertThat(parentDpm.getPermittedInputMethods(admin1)).isEmpty();

        // Don't allow specific third party input methods
        final List<String> inputMethods = Collections.singletonList(packageName);

        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ "Permitted "
                        + "input methods must allow all input methods or only system input methods "
                        + "when called on the parent instance of an organization-owned device",
                () -> parentDpm.setPermittedInputMethods(admin1, inputMethods));
    }

    @Test
    public void testGetProxyParameters() throws Exception {
        assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234), emptyList()))
                .isEqualTo(new Pair<>("192.0.2.1:1234", ""));
        assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234),
                listOf("one.example.com  ", "  two.example.com ")))
                .isEqualTo(new Pair<>("192.0.2.1:1234", "one.example.com,two.example.com"));
        assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234), emptyList()))
                .isEqualTo(new Pair<>("proxy.example.com:1234", ""));
        assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234),
                listOf("excluded.example.com")))
                .isEqualTo(new Pair<>("proxy.example.com:1234", "excluded.example.com"));

        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                inetAddrProxy("192.0.2.1", 0), emptyList()));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("", 1234), emptyList()));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("", 0), emptyList()));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("invalid! hostname", 1234), emptyList()));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("proxy.example.com", 1234), listOf("invalid exclusion")));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("proxy.example.com", -1), emptyList()));
        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
                hostnameProxy("proxy.example.com", 0xFFFF + 1), emptyList()));
    }

    private static Proxy inetAddrProxy(String inetAddr, int port) {
        return new Proxy(
                Proxy.Type.HTTP, new InetSocketAddress(parseNumericAddress(inetAddr), port));
    }

    private static Proxy hostnameProxy(String hostname, int port) {
        return new Proxy(
                Proxy.Type.HTTP, InetSocketAddress.createUnresolved(hostname, port));
    }

    private static List<String> listOf(String... args) {
        return Arrays.asList(args);
    }

    @Test
    public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        dpm.setKeyguardDisabledFeatures(admin1, DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);

        assertThat(dpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
    }

    @Test
    public void testSetKeyguardDisabledFeaturesWithPO() throws Exception {
        setupProfileOwner();

        dpm.setKeyguardDisabledFeatures(admin1, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);

        assertThat(dpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
                DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
    }

    @Test
    public void testSetKeyguardDisabledFeaturesWithPOOfOrganizationOwnedDevice()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        parentDpm.setKeyguardDisabledFeatures(admin1,
                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);

        assertThat(parentDpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetApplicationHiddenWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        mockEmptyPolicyExemptApps();

        String packageName = "com.google.android.test";

        dpm.setApplicationHidden(admin1, packageName, true);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                true, UserHandle.USER_SYSTEM);

        dpm.setApplicationHidden(admin1, packageName, false);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                false, UserHandle.USER_SYSTEM);

        verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
        verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY,
                UserHandle.USER_SYSTEM);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
        final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        mockEmptyPolicyExemptApps();

        String packageName = "com.google.android.test";

        ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
        when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        when(getServices().ipackageManager.getApplicationInfo(packageName,
                PackageManager.MATCH_UNINSTALLED_PACKAGES, UserHandle.USER_SYSTEM)).thenReturn(
                applicationInfo);

        parentDpm.setApplicationHidden(admin1, packageName, true);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                true, UserHandle.USER_SYSTEM);

        parentDpm.setApplicationHidden(admin1, packageName, false);
        verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
                false, UserHandle.USER_SYSTEM);
    }

    @Test
    public void testGetMacAddress() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // In this test, change the caller user to "system".
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure admin1 is installed on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Test 1. Caller doesn't have DO or DA.
        assertExpectException(SecurityException.class, /* messageRegex= */
                "does not exist or is not owned by uid", () -> dpm.getWifiMacAddress(admin1));

        // DO needs to be an DA.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();

        // Test 2. Caller has DA, but not DO.
        assertExpectException(SecurityException.class,
                /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG,
                () -> dpm.getWifiMacAddress(admin1));

        // Test 3. Caller has PO, but not DO.
        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertExpectException(SecurityException.class,
                /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG,
                () -> dpm.getWifiMacAddress(admin1));

        // Remove PO.
        dpm.clearProfileOwner(admin1);
        dpm.setActiveAdmin(admin1, false);
        // Test 4, Caller is DO now.
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        // 4-1.  But WifiManager is not ready.
        assertThat(dpm.getWifiMacAddress(admin1)).isNull();

        // 4-2.  When WifiManager returns an empty array, dpm should also output null.
        when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(new String[0]);
        assertThat(dpm.getWifiMacAddress(admin1)).isNull();

        // 4-3. With a real MAC address.
        final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
        when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
        assertThat(dpm.getWifiMacAddress(admin1)).isEqualTo("11:22:33:44:55:66");
    }

    @Test
    public void testGetMacAddressByOrgOwnedPO() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
        when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
        assertThat(dpm.getWifiMacAddress(admin1)).isEqualTo("11:22:33:44:55:66");
    }

    @Test
    public void testReboot() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        // In this test, change the caller user to "system".
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Make sure admin1 is installed on system user.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);

        // Set admin1 as DA.
        dpm.setActiveAdmin(admin1, false);
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertExpectException(SecurityException.class, /* messageRegex= */
                INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1));

        // Set admin1 as PO.
        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertExpectException(SecurityException.class, /* messageRegex= */
                INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1));

        // Remove PO and add DO.
        dpm.clearProfileOwner(admin1);
        dpm.setActiveAdmin(admin1, false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        // admin1 is DO.
        // Set current call state of device to ringing.
        when(getServices().telephonyManager.getCallState())
                .thenReturn(TelephonyManager.CALL_STATE_RINGING);
        assertExpectException(IllegalStateException.class, /* messageRegex= */ ONGOING_CALL_MSG,
                () -> dpm.reboot(admin1));

        // Set current call state of device to dialing/active.
        when(getServices().telephonyManager.getCallState())
                .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
        assertExpectException(IllegalStateException.class, /* messageRegex= */ ONGOING_CALL_MSG,
                () -> dpm.reboot(admin1));

        // Set current call state of device to idle.
        when(getServices().telephonyManager.getCallState())
                .thenReturn(TelephonyManager.CALL_STATE_IDLE);
        dpm.reboot(admin1);
    }

    @Test
    public void testSetGetSupportText() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        dpm.setActiveAdmin(admin1, true);
        dpm.setActiveAdmin(admin2, true);
        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);

        // Null default support messages.
        {
            assertThat(dpm.getLongSupportMessage(admin1)).isNull();
            assertThat(dpm.getShortSupportMessage(admin1)).isNull();
            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
            assertThat(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull();
            assertThat(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull();
            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
        }

        // Only system can call the per user versions.
        {
            assertExpectException(SecurityException.class, /* messageRegex= */ "message for user",
                    () -> dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE));
            assertExpectException(SecurityException.class, /* messageRegex= */ "message for user",
                    () -> dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE));
        }

        // Can't set message for admin in another uid.
        {
            mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
            assertThrows(SecurityException.class,
                    () -> dpm.setShortSupportMessage(admin1, "Some text"));
            mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        }

        // Set/Get short returns what it sets and other admins text isn't changed.
        {
            final String supportText = "Some text to test with.";
            dpm.setShortSupportMessage(admin1, supportText);
            assertThat(dpm.getShortSupportMessage(admin1)).isEqualTo(supportText);
            assertThat(dpm.getLongSupportMessage(admin1)).isNull();
            assertThat(dpm.getShortSupportMessage(admin2)).isNull();

            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
            assertThat(dpm.getShortSupportMessageForUser(admin1,
            CALLER_USER_HANDLE)).isEqualTo(supportText);
            assertThat(dpm.getShortSupportMessageForUser(admin2, CALLER_USER_HANDLE)).isNull();
            assertThat(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull();
            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;

            dpm.setShortSupportMessage(admin1, null);
            assertThat(dpm.getShortSupportMessage(admin1)).isNull();
        }

        // Set/Get long returns what it sets and other admins text isn't changed.
        {
            final String supportText = "Some text to test with.\nWith more text.";
            dpm.setLongSupportMessage(admin1, supportText);
            assertThat(dpm.getLongSupportMessage(admin1)).isEqualTo(supportText);
            assertThat(dpm.getShortSupportMessage(admin1)).isNull();
            assertThat(dpm.getLongSupportMessage(admin2)).isNull();

            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
            assertThat(dpm.getLongSupportMessageForUser(admin1,
            CALLER_USER_HANDLE)).isEqualTo(supportText);
            assertThat(dpm.getLongSupportMessageForUser(admin2, CALLER_USER_HANDLE)).isNull();
            assertThat(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull();
            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;

            dpm.setLongSupportMessage(admin1, null);
            assertThat(dpm.getLongSupportMessage(admin1)).isNull();
        }
    }

    @Test
    public void testSetGetMeteredDataDisabledPackages() throws Exception {
        setAsProfileOwner(admin1);

        assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEmpty();

        // Setup
        final ArrayList<String> pkgsToRestrict = new ArrayList<>();
        final String package1 = "com.example.one";
        final String package2 = "com.example.two";
        pkgsToRestrict.add(package1);
        pkgsToRestrict.add(package2);
        setupPackageInPackageManager(package1, CALLER_USER_HANDLE, 123, 0);
        setupPackageInPackageManager(package2, CALLER_USER_HANDLE, 456, 0);
        List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);

        // Verify
        assertThat(excludedPkgs).isEmpty();
        assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEqualTo(pkgsToRestrict);
        verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
                MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
                eq(CALLER_USER_HANDLE));

        // Setup
        pkgsToRestrict.remove(package1);
        excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);

        // Verify
        assertThat(excludedPkgs).isEmpty();
        assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEqualTo(pkgsToRestrict);
        verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
                MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
                eq(CALLER_USER_HANDLE));
    }

    @Test
    public void testSetGetMeteredDataDisabledPackages_deviceAdmin() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        dpm.setActiveAdmin(admin1, true);
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);

        assertExpectException(SecurityException.class,  /* messageRegex= */ NOT_PROFILE_OWNER_MSG,
                () -> dpm.setMeteredDataDisabledPackages(admin1, new ArrayList<>()));
        assertExpectException(SecurityException.class,  /* messageRegex= */ NOT_PROFILE_OWNER_MSG,
                () -> dpm.getMeteredDataDisabledPackages(admin1));
    }

    @Test
    public void testIsMeteredDataDisabledForUserPackage() throws Exception {
        setAsProfileOwner(admin1);

        // Setup
        final ArrayList<String> pkgsToRestrict = new ArrayList<>();
        final String package1 = "com.example.one";
        final String package2 = "com.example.two";
        final String package3 = "com.example.three";
        pkgsToRestrict.add(package1);
        pkgsToRestrict.add(package2);
        setupPackageInPackageManager(package1, CALLER_USER_HANDLE, 123, 0);
        setupPackageInPackageManager(package2, CALLER_USER_HANDLE, 456, 0);
        List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);

        // Verify
        assertThat(excludedPkgs).isEmpty();
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertWithMessage("%s should be restricted", package1)
                .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package1, CALLER_USER_HANDLE))
                .isTrue();
        assertWithMessage("%s should be restricted", package2)
                .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package2, CALLER_USER_HANDLE))
                .isTrue();
        assertWithMessage("%s should not be restricted", package3)
                .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package3, CALLER_USER_HANDLE))
                .isFalse();
    }

    @Test
    public void testIsMeteredDataDisabledForUserPackage_nonSystemUidCaller() throws Exception {
        setAsProfileOwner(admin1);
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Only the system can query restricted pkgs",
                () -> dpm.isMeteredDataDisabledPackageForUser(
                        admin1, "com.example.one", CALLER_USER_HANDLE));
        dpm.clearProfileOwner(admin1);

        setDeviceOwner();
        assertExpectException(SecurityException.class,
                /* messageRegex= */ "Only the system can query restricted pkgs",
                () -> dpm.isMeteredDataDisabledPackageForUser(
                        admin1, "com.example.one", CALLER_USER_HANDLE));
        clearDeviceOwner();
    }

    @Test
    @Ignore("b/277916462")
    public void testCreateAdminSupportIntent() throws Exception {
        // Setup device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        // Nonexisting permission returns null
        Intent intent = dpm.createAdminSupportIntent("disallow_nothing");
        assertThat(intent).isNull();

        // Existing permission that is not set returns null
        intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
        assertThat(intent).isNull();

        // Existing permission that is not set by device/profile owner returns null
        when(getServices().userManager.hasUserRestriction(
                eq(UserManager.DISALLOW_ADJUST_VOLUME),
                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
                .thenReturn(true);
        intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
        assertThat(intent).isNull();

        // UM.getUserRestrictionSources() will return a list of size 1 with the caller resource.
        doAnswer((Answer<List<UserManager.EnforcingUser>>) invocation -> Collections.singletonList(
                new UserManager.EnforcingUser(
                        UserHandle.USER_SYSTEM,
                        UserManager.RESTRICTION_SOURCE_DEVICE_OWNER))
        ).when(getServices().userManager).getUserRestrictionSources(
                eq(UserManager.DISALLOW_ADJUST_VOLUME),
                eq(UserHandle.of(UserHandle.USER_SYSTEM)));
        intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
        assertThat(intent).isNotNull();
        assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
        assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1))
                .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID));
        assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION))
                .isEqualTo(UserManager.DISALLOW_ADJUST_VOLUME);

        // Try with POLICY_DISABLE_CAMERA and POLICY_DISABLE_SCREEN_CAPTURE, which are not
        // user restrictions

        // Camera is not disabled
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
        assertThat(intent).isNull();

        // Camera is disabled
        dpm.setCameraDisabled(admin1, true);
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
        assertThat(intent).isNotNull();
        assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION))
                .isEqualTo(DevicePolicyManager.POLICY_DISABLE_CAMERA);

        // Screen capture is not disabled
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
        assertThat(intent).isNull();

        // Screen capture is disabled
        dpm.setScreenCaptureDisabled(admin1, true);
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
        assertThat(intent).isNotNull();
        assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION))
                .isEqualTo(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);

        // Same checks for different user
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        // Camera should be disabled by device owner
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
        assertThat(intent).isNotNull();
        assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION))
                .isEqualTo(DevicePolicyManager.POLICY_DISABLE_CAMERA);
        assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1))
                .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_UID));
        // ScreenCapture should not be disabled by device owner
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
        assertThat(intent).isNull();
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setAffiliationIds}
     * {@link DevicePolicyManager#getAffiliationIds}
     * {@link DevicePolicyManager#isAffiliatedUser}
     */
    @Test
    public void testUserAffiliation() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);

        // Check that the system user is unaffiliated.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        assertThat(dpm.isAffiliatedUser()).isFalse();

        // Set a device owner on the system user. Check that the system user becomes affiliated.
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpm.isAffiliatedUser()).isTrue();
        assertThat(dpm.getAffiliationIds(admin1).isEmpty()).isTrue();

        // Install a profile owner. Check that the test user is unaffiliated.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin2);
        assertThat(dpm.isAffiliatedUser()).isFalse();
        assertThat(dpm.getAffiliationIds(admin2).isEmpty()).isTrue();

        // Have the profile owner specify a set of affiliation ids. Check that the test user remains
        // unaffiliated.
        final Set<String> userAffiliationIds = new ArraySet<>();
        userAffiliationIds.add("red");
        userAffiliationIds.add("green");
        userAffiliationIds.add("blue");
        dpm.setAffiliationIds(admin2, userAffiliationIds);
        MoreAsserts.assertContentsInAnyOrder(dpm.getAffiliationIds(admin2), "red", "green", "blue");
        assertThat(dpm.isAffiliatedUser()).isFalse();

        // Have the device owner specify a set of affiliation ids that do not intersect with those
        // specified by the profile owner. Check that the test user remains unaffiliated.
        final Set<String> deviceAffiliationIds = new ArraySet<>();
        deviceAffiliationIds.add("cyan");
        deviceAffiliationIds.add("yellow");
        deviceAffiliationIds.add("magenta");
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        dpm.setAffiliationIds(admin1, deviceAffiliationIds);
        MoreAsserts.assertContentsInAnyOrder(
            dpm.getAffiliationIds(admin1), "cyan", "yellow", "magenta");
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        assertThat(dpm.isAffiliatedUser()).isFalse();

        // Have the profile owner specify a set of affiliation ids that intersect with those
        // specified by the device owner. Check that the test user becomes affiliated.
        userAffiliationIds.add("yellow");
        dpm.setAffiliationIds(admin2, userAffiliationIds);
        MoreAsserts.assertContentsInAnyOrder(
            dpm.getAffiliationIds(admin2), "red", "green", "blue", "yellow");
        assertThat(dpm.isAffiliatedUser()).isTrue();

        // Clear affiliation ids for the profile owner. The user becomes unaffiliated.
        dpm.setAffiliationIds(admin2, Collections.emptySet());
        assertThat(dpm.getAffiliationIds(admin2).isEmpty()).isTrue();
        assertThat(dpm.isAffiliatedUser()).isFalse();

        // Set affiliation ids again, then clear PO to check that the user becomes unaffiliated
        dpm.setAffiliationIds(admin2, userAffiliationIds);
        assertThat(dpm.isAffiliatedUser()).isTrue();
        dpm.clearProfileOwner(admin2);
        assertThat(dpm.isAffiliatedUser()).isFalse();

        // Check that the system user remains affiliated.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        assertThat(dpm.isAffiliatedUser()).isTrue();

        // Clear the device owner - the user becomes unaffiliated.
        clearDeviceOwner();
        assertThat(dpm.isAffiliatedUser()).isFalse();
    }

    @Test
    public void testGetUserProvisioningState_defaultResult() {
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.getUserProvisioningState())
                .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED);
    }

    @Test
    public void testSetUserProvisioningState_permission() throws Exception {
        setupProfileOwner();

        exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_unprivileged() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
                        CALLER_USER_HANDLE));
    }

    @Test
    public void testSetUserProvisioningState_noManagement() {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "change provisioning state unless a .* owner is set",
                () -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
                        CALLER_USER_HANDLE));
        assertThat(dpm.getUserProvisioningState())
                .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED);
    }

    @Test
    public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative()
            throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
            throws Exception {
        setupProfileOwner();

        exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
                DevicePolicyManager.STATE_USER_PROFILE_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
            throws Exception {
        setupProfileOwner();

        exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
        setupProfileOwner();

        exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
    }

    @Test
    public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
        setupProfileOwner();

        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "Cannot move to user provisioning state",
                () -> exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                        DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
                        DevicePolicyManager.STATE_USER_UNMANAGED));
    }

    @Test
    public void testSetUserProvisioningState_profileFinalized_canTransitionToUserUnmanaged()
            throws Exception {
        setupProfileOwner();

        exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_PROFILE_FINALIZED,
                DevicePolicyManager.STATE_USER_UNMANAGED);
    }

    @Test
    public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
            throws Exception {
        setupProfileOwner();

        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "Cannot move to user provisioning state",
                () -> exerciseUserProvisioningTransitions(CALLER_USER_HANDLE,
                        DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
                        DevicePolicyManager.STATE_USER_SETUP_COMPLETE));
    }

    private void exerciseUserProvisioningTransitions(int userId, int... states) {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.MANAGE_USERS);

        assertThat(dpm.getUserProvisioningState())
                .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED);
        for (int state : states) {
            dpm.setUserProvisioningState(state, userId);
            assertThat(dpm.getUserProvisioningState()).isEqualTo(state);
        }
    }

    private void setupProfileOwner() throws Exception {
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
        dpm.setActiveAdmin(admin1, false);
        assertThat(dpm.setProfileOwner(admin1, CALLER_USER_HANDLE)).isTrue();

        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    private void setupProfileOwnerOnUser0() throws Exception {
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);

        setUpPackageManagerForAdmin(admin1, DpmMockContext.SYSTEM_UID);
        dpm.setActiveAdmin(admin1, false);
        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    private void setupDeviceOwner() throws Exception {
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin1, false);
        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();

        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    @Test
    public void testSetMaximumTimeToLock() {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        dpm.setActiveAdmin(admin2, /* replace =*/ false);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin1, 0);
        verifyScreenTimeoutCall(null, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(false);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin1, 1);
        verifyScreenTimeoutCall(1L, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin2, 10);
        verifyScreenTimeoutCall(null, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(false);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin1, 5);
        verifyScreenTimeoutCall(5L, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin2, 4);
        verifyScreenTimeoutCall(4L, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin1, 0);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin2, Long.MAX_VALUE);
        verifyScreenTimeoutCall(Long.MAX_VALUE, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin2, 10);
        verifyScreenTimeoutCall(10L, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // There's no restriction; should be set to MAX.
        dpm.setMaximumTimeToLock(admin2, 0);
        verifyScreenTimeoutCall(Long.MAX_VALUE, CALLER_USER_HANDLE);
        verifyStayOnWhilePluggedCleared(false);
    }

    @Test
    public void testSupervisionConfig() throws Exception {
        final int uid = UserHandle.getUid(15, 19436);
        addManagedProfile(admin1, uid, admin1);
        mContext.binder.callingUid = uid;

        verifySupervisionConfig(uid, null, null);
        verifySupervisionConfig(uid, "", null);
        verifySupervisionConfig(uid, null, "");
        verifySupervisionConfig(uid, "", "");

        verifySupervisionConfig(uid, admin1.flattenToString(), null);
        verifySupervisionConfig(uid, admin1.flattenToString(), "");

        verifySupervisionConfig(uid, null, admin1.getPackageName());
        verifySupervisionConfig(uid, "", admin1.getPackageName());
    }

    private void verifySupervisionConfig(
            int uid , String configComponentName, String configPackageName) {
        final boolean isAdmin = admin1.flattenToString().equals(configComponentName)
                || admin1.getPackageName().equals(configPackageName);

        final UserHandle user = UserHandle.getUserHandleForUid(uid);
        final DevicePolicyManagerInternal dpmi =
                LocalServices.getService(DevicePolicyManagerInternal.class);

        when(mServiceContext.resources
                .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
                .thenReturn(configComponentName);

        when(mServiceContext.resources
                .getString(R.string.config_systemSupervision))
                .thenReturn(configPackageName);

        if (isAdmin) {
            assertThat(dpmi.isActiveSupervisionApp(uid)).isTrue();
            assertThat(dpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(user))
                        .isEqualTo(admin1);
            assertThat(dpm.isSupervisionComponent(admin1)).isTrue();
        } else {
            assertThat(dpmi.isActiveSupervisionApp(uid)).isFalse();
            assertThat(dpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(user)).isNull();
            assertThat(dpm.isSupervisionComponent(admin1)).isFalse();
        }
    }

    // Test if lock timeout on managed profile is handled correctly depending on whether profile
    // uses separate challenge.
    @Test
    public void testSetMaximumTimeToLockProfile() throws Exception {
        final int PROFILE_USER = 15;
        final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436);
        addManagedProfile(admin1, PROFILE_ADMIN, admin1);
        mContext.binder.callingUid = PROFILE_ADMIN;
        final DevicePolicyManagerInternal dpmi =
                LocalServices.getService(DevicePolicyManagerInternal.class);

        dpm.setMaximumTimeToLock(admin1, 0);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // First add timeout for the profile.
        dpm.setMaximumTimeToLock(admin1, 10);
        verifyScreenTimeoutCall(10L, UserHandle.USER_SYSTEM);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // Add separate challenge
        when(getServices().lockPatternUtils
                .isSeparateProfileChallengeEnabled(eq(PROFILE_USER))).thenReturn(true);
        dpmi.reportSeparateProfileChallengeChanged(PROFILE_USER);

        verifyScreenTimeoutCall(10L, PROFILE_USER);
        verifyScreenTimeoutCall(Long.MAX_VALUE, UserHandle.USER_SYSTEM);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // Remove the timeout.
        dpm.setMaximumTimeToLock(admin1, 0);
        verifyScreenTimeoutCall(Long.MAX_VALUE, PROFILE_USER);
        verifyScreenTimeoutCall(null , UserHandle.USER_SYSTEM);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // Add it back.
        dpm.setMaximumTimeToLock(admin1, 10);
        verifyScreenTimeoutCall(10L, PROFILE_USER);
        verifyScreenTimeoutCall(null, UserHandle.USER_SYSTEM);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // Remove separate challenge.
        reset(getServices().lockPatternUtils);
        when(getServices().lockPatternUtils
                .isSeparateProfileChallengeEnabled(eq(PROFILE_USER))).thenReturn(false);
        dpmi.reportSeparateProfileChallengeChanged(PROFILE_USER);
        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);

        verifyScreenTimeoutCall(Long.MAX_VALUE, PROFILE_USER);
        verifyScreenTimeoutCall(10L , UserHandle.USER_SYSTEM);

        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        // Remove the timeout.
        dpm.setMaximumTimeToLock(admin1, 0);
        verifyScreenTimeoutCall(null, PROFILE_USER);
        verifyScreenTimeoutCall(Long.MAX_VALUE, UserHandle.USER_SYSTEM);
    }

    @Test
    public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
        final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
        final long MIN_PLUS_ONE_MINUTE = MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE;
        final long MAX_MINUS_ONE_MINUTE = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS
                - ONE_MINUTE;

        // verify that the minimum timeout cannot be modified on user builds (system property is
        // not being read)
        getServices().buildMock.isDebuggable = false;

        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
        assertThat(MAX_MINUS_ONE_MINUTE).isEqualTo(dpm.getRequiredStrongAuthTimeout(admin1));
        assertThat(MAX_MINUS_ONE_MINUTE).isEqualTo(dpm.getRequiredStrongAuthTimeout(null));

        verify(getServices().systemProperties, never()).getLong(anyString(), anyLong());

        // restore to the debuggable build state
        getServices().buildMock.isDebuggable = true;

        // reset to default (0 means the admin is not participating, so default should be returned)
        dpm.setRequiredStrongAuthTimeout(admin1, 0);

        // aggregation should be the default if unset by any admin
        assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS)
                .isEqualTo(dpm.getRequiredStrongAuthTimeout(null));

        // admin not participating by default
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0);

        //clamping from the top
        dpm.setRequiredStrongAuthTimeout(admin1,
                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
        assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS)
                .isEqualTo(dpm.getRequiredStrongAuthTimeout(admin1));
        assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS)
                .isEqualTo(dpm.getRequiredStrongAuthTimeout(null));

        // 0 means the admin is not participating, so default should be returned
        dpm.setRequiredStrongAuthTimeout(admin1, 0);
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0);
        assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS)
                .isEqualTo(dpm.getRequiredStrongAuthTimeout(null));

        // clamping from the bottom
        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE);
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1))
                .isEqualTo(MINIMUM_STRONG_AUTH_TIMEOUT_MS);
        assertThat(dpm.getRequiredStrongAuthTimeout(null))
                .isEqualTo(MINIMUM_STRONG_AUTH_TIMEOUT_MS);

        // values within range
        dpm.setRequiredStrongAuthTimeout(admin1, MIN_PLUS_ONE_MINUTE);
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(MIN_PLUS_ONE_MINUTE);
        assertThat(dpm.getRequiredStrongAuthTimeout(null)).isEqualTo(MIN_PLUS_ONE_MINUTE);

        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(MAX_MINUS_ONE_MINUTE);
        assertThat(dpm.getRequiredStrongAuthTimeout(null)).isEqualTo(MAX_MINUS_ONE_MINUTE);

        // reset to default
        dpm.setRequiredStrongAuthTimeout(admin1, 0);
        assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0);
        assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS)
                .isEqualTo(dpm.getRequiredStrongAuthTimeout(null));

        // negative value
        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                () -> dpm.setRequiredStrongAuthTimeout(admin1, -ONE_MINUTE));
    }

    private void verifyScreenTimeoutCall(Long expectedTimeout, int userId) {
        if (expectedTimeout == null) {
            verify(getServices().powerManagerInternal, times(0))
                    .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(userId), anyLong());
        } else {
            verify(getServices().powerManagerInternal, times(1))
                    .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(userId), eq(expectedTimeout));
        }
    }

    private void verifyStayOnWhilePluggedCleared(boolean cleared) {
        // TODO Verify calls to settingsGlobalPutInt.  Tried but somehow mockito threw
        // UnfinishedVerificationException.
    }

    private void setup_DeviceAdminFeatureOff() throws Exception {
        when(getServices().packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
                .thenReturn(false);
        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false);
        initializeDpms();
        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                .thenReturn(true);
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    @Test
    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
        setup_DeviceAdminFeatureOff();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
    }

    @Test
    public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception {
        setup_DeviceAdminFeatureOff();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_DEVICE_ADMIN_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                DevicePolicyManager.STATUS_DEVICE_ADMIN_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_DEVICE_ADMIN_NOT_SUPPORTED);
    }

    private void setup_ManagedProfileFeatureOff() throws Exception {
        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false);
        initializeDpms();
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                .thenReturn(true);
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    @Test
    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
        setup_ManagedProfileFeatureOff();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    }

    @Test
    public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception {
        setup_ManagedProfileFeatureOff();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                DevicePolicyManager.STATUS_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_MANAGED_USERS_NOT_SUPPORTED);
    }

    private void setup_firstBoot_systemUser() throws Exception {
        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
                .thenReturn(true);
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
        when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    /* Tests provisions from system user during first boot. */
    @Test
    public void testIsProvisioningAllowed_firstBoot_systemUser() throws Exception {
        setup_firstBoot_systemUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    }

    @Test
    public void testCheckProvisioningPreCondition_firstBoot_systemUser()
            throws Exception {
        setup_firstBoot_systemUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(false);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                DevicePolicyManager.STATUS_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_OK);

        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_OK);
    }

    private void setup_systemUserSetupComplete_systemUser() throws Exception {
        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
                .thenReturn(true);
        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
        when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    private void setup_withDo_systemUser() throws Exception {
        setDeviceOwner();
        setup_systemUserSetupComplete_systemUser();
        setUpPackageManagerForFakeAdmin(adminAnotherPackage, DpmMockContext.ANOTHER_UID, admin2);
    }

    private void setup_withDo_systemUser_ManagedProfile() throws Exception {
        setup_withDo_systemUser();
        final int MANAGED_PROFILE_USER_ID = 18;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
                false /* we can't remove a managed profile */)).thenReturn(false);
    }

    @Test
    public void testIsProvisioningAllowed_systemUserSetupComplete_systemUser()
            throws Exception {
        setup_systemUserSetupComplete_systemUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                false/* because of completed device setup */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                false/* because of completed device setup */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    }

    @Test
    public void testCheckProvisioningPreCondition_systemUserSetupComplete_systemUser()
            throws Exception {
        setup_systemUserSetupComplete_systemUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_USER_SETUP_COMPLETED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                DevicePolicyManager.STATUS_USER_SETUP_COMPLETED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_OK);
    }

    @Test
    public void testProvisioning_withDo_systemUser() throws Exception {
        setup_withDo_systemUser();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.STATUS_HAS_DEVICE_OWNER);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE,
                DevicePolicyManager.STATUS_HAS_DEVICE_OWNER);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false);

        // COMP mode NOT is allowed.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

        // And other DPCs can NOT provision a managed profile.
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    @Test
    public void testProvisioning_withDo_systemUser_restrictedBySystem()
            throws Exception {
        setup_withDo_systemUser();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        // The DO should not be allowed to initiate provisioning if the restriction is set by
        // another entity.
        when(getServices().userManager.hasUserRestriction(
                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
                .thenReturn(true);
        when(getServices().userManager.getUserRestrictionSource(
                eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
                .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    @Test
    public void testCheckCannotSetProfileOwnerWithDeviceOwner() throws Exception {
        setup_withDo_systemUser();
        final int managedProfileUserId = 18;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 1308);

        final int userId = UserHandle.getUserId(managedProfileAdminUid);
        getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
                UserHandle.USER_SYSTEM);
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
        setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1);
        dpm.setActiveAdmin(admin1, false, userId);
        assertThat(dpm.setProfileOwner(admin1, userId)).isFalse();
        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    @Test
    public void testCheckProvisioningPreCondition_attemptingComp() throws Exception {
        setup_withDo_systemUser_ManagedProfile();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        // We can delete the managed profile to create a new one, so provisioning is allowed.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    @Test
    public void testCheckProvisioningPreCondition_comp_cannot_remove_profile()
            throws Exception {
        setup_withDo_systemUser_ManagedProfile();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        when(getServices().userManager.hasUserRestriction(
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(UserHandle.SYSTEM)))
                .thenReturn(true);
        when(getServices().userManager.getUserRestrictionSource(
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(UserHandle.SYSTEM)))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);

        // We can't remove the profile to create a new one.
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);

        // But the device owner can still do it because it has set the restriction itself.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    }

    // TODO(b/174859111): move to automotive-only section
    private void setup_firstBoot_headlessSystemUserMode() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
                .thenReturn(true);
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
        when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);
    }

    /**
     * TODO(b/174859111): move to automotive-only section
     * Tests provision from secondary user during first boot.
    **/
    @Test
    public void testIsProvisioningAllowed_firstBoot_secondaryUser() throws Exception {
        setup_firstBoot_headlessSystemUserMode();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        // Provisioning device from secondary user should fail in non-headless system user mode.
        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false);

        // Required for ACTION_PROVISION_MANAGED_PROFILE if allowed to add managed profile from
        // secondary user
        when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE, false))
                .thenReturn(true);
        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);

        // Provisioning device from secondary user should be allowed in headless system user mode.
        when(getServices().userManagerForMock.isHeadlessSystemUserMode()).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
    }

    private void setup_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception {
        setDeviceOwner();

        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
            .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
                false)).thenReturn(true);
        setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);

        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
    }

    @Test
    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
            throws Exception {
        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        mContext.packageName = admin1.getPackageName();
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    }

    @Test
    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser()
            throws Exception {
        setup_provisionManagedProfileWithDeviceOwner_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        // COMP mode is NOT allowed.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
    }

    private void setup_provisionManagedProfileOneAlreadyExist_primaryUser() throws Exception {
        setDeviceOwner();

        when(getServices().ipackageManager
                .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
        when(getServices().userManager.hasUserRestriction(
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(UserHandle.of(CALLER_USER_HANDLE))))
                .thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
                false /* we can't remove a managed profile */)).thenReturn(false);
        setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    }

    @Test
    public void testIsProvisioningAllowed_provisionManagedProfile_oneAlreadyExists_primaryUser()
            throws Exception {
        setup_provisionManagedProfileOneAlreadyExist_primaryUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    }

    @Test
    public void testCheckProvisioningPreCondition_provisionManagedProfile_oneAlreadyExists_primaryUser()
            throws Exception {
        setup_provisionManagedProfileOneAlreadyExist_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE);
    }

    @Test
    public void testCheckProvisioningPreCondition_permission() {
        // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.checkProvisioningPrecondition(
                        DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, "some.package"));
    }

    @Test
    public void testForceUpdateUserSetupComplete_permission() {
        // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.forceUpdateUserSetupComplete(UserHandle.USER_SYSTEM));
    }

    @Test
    public void testForceUpdateUserSetupComplete_forcesUpdate() {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        final int userId = UserHandle.getUserId(mContext.binder.callingUid);

        // GIVEN userComplete is false in SettingsProvider
        setUserSetupCompleteForUser(false, userId);

        // GIVEN userComplete is true in DPM
        DevicePolicyData userData = new DevicePolicyData(userId);
        userData.mUserSetupComplete = true;
        dpms.mUserData.put(userId, userData);

        assertThat(dpms.hasUserSetupCompleted()).isTrue();

        dpm.forceUpdateUserSetupComplete(userId);

        // THEN the state in dpms is changed
        assertThat(dpms.hasUserSetupCompleted()).isFalse();
    }

    private void clearDeviceOwner() {
        getServices().addTestPackageUid(admin1.getPackageName(),
                DpmMockContext.CALLER_SYSTEM_USER_UID);

        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        runAsCaller(mAdmin1Context, dpms, dpm -> {
            dpm.clearDeviceOwnerApp(admin1.getPackageName());
        });
    }

    @Test
    public void testGetLastSecurityLogRetrievalTime() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
        // feature is disabled because there are non-affiliated secondary users.
        getServices().removeUser(CALLER_USER_HANDLE);
        when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs))
                .thenReturn(true);

        // No logs were retrieved so far.
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1);

        // Enabling logging should not change the timestamp.
        dpm.setSecurityLoggingEnabled(admin1, true);
        verify(getServices().settings).securityLogSetLoggingEnabledProperty(true);

        when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true);
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1);

        // Retrieving the logs should update the timestamp.
        final long beforeRetrieval = System.currentTimeMillis();
        dpm.retrieveSecurityLogs(admin1);
        final long firstSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime();
        final long afterRetrieval = System.currentTimeMillis();
        assertThat(firstSecurityLogRetrievalTime >= beforeRetrieval).isTrue();
        assertThat(firstSecurityLogRetrievalTime <= afterRetrieval).isTrue();

        // Retrieving the pre-boot logs should update the timestamp.
        Thread.sleep(2);
        dpm.retrievePreRebootSecurityLogs(admin1);
        final long secondSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime();
        assertThat(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime).isTrue();

        // Checking the timestamp again should not change it.
        Thread.sleep(2);
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(secondSecurityLogRetrievalTime);

        // Retrieving the logs again should update the timestamp.
        dpm.retrieveSecurityLogs(admin1);
        final long thirdSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime();
        assertThat(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime).isTrue();

        // Disabling logging should not change the timestamp.
        Thread.sleep(2);
        dpm.setSecurityLoggingEnabled(admin1, false);
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime);

        // Restarting the DPMS should not lose the timestamp.
        initializeDpms();
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime);

        // Any uid holding MANAGE_USERS permission can retrieve the timestamp.
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime);
        mContext.callerPermissions.remove(permission.MANAGE_USERS);

        // System can retrieve the timestamp.
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime);

        // Removing the device owner should clear the timestamp.
        clearDeviceOwner();
        assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1);
    }

    @Test
    public void testSetConfiguredNetworksLockdownStateWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setConfiguredNetworksLockdownState(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 1);

        dpm.setConfiguredNetworksLockdownState(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
    }

    @Test
    public void testSetConfiguredNetworksLockdownStateWithPO() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null,
                () -> dpm.setConfiguredNetworksLockdownState(admin1, false));
        verify(getServices().settings, never()).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
    }

    @Test
    public void testSetConfiguredNetworksLockdownStateWithPOOfOrganizationOwnedDevice()
            throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        dpm.setConfiguredNetworksLockdownState(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 1);

        dpm.setConfiguredNetworksLockdownState(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
    }

    @Test
    public void testUpdateNetworkPreferenceOnStartUser() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;
        mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        dpms.handleStartUser(managedProfileUserId);
        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
                .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                null, null);
    }

    @Test
    public void testUpdateNetworkPreferenceOnStopUser() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;
        mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        dpms.handleStopUser(managedProfileUserId);
        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);
    }

    @Test
    public void testGetSetPreferentialNetworkService() throws Exception {
        assertExpectException(SecurityException.class, null,
                () -> dpm.setPreferentialNetworkServiceEnabled(false));

        assertExpectException(SecurityException.class, null,
                () -> dpm.isPreferentialNetworkServiceEnabled());

        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        dpm.setPreferentialNetworkServiceEnabled(false);
        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();

        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);

        dpm.setPreferentialNetworkServiceEnabled(true);
        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isTrue();

        ProfileNetworkPreference preferenceDetails2 =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE)
                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
                        .build();
        List<ProfileNetworkPreference> preferences2 = new ArrayList<>();
        preferences2.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences2,
                        null, null);
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_noProfileOwner() throws Exception {
        assertExpectException(SecurityException.class, null,
                () -> dpm.setPreferentialNetworkServiceConfigs(
                        List.of(PreferentialNetworkServiceConfig.DEFAULT)));
    }

    @Test
    public void testIsPreferentialNetworkServiceEnabled_noProfileOwner() throws Exception {
        assertExpectException(SecurityException.class, null,
                () -> dpm.isPreferentialNetworkServiceEnabled());
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_invalidConfig() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        PreferentialNetworkServiceConfig.Builder preferentialNetworkServiceConfigBuilder =
                new PreferentialNetworkServiceConfig.Builder();
        assertExpectException(NullPointerException.class, null,
                () -> preferentialNetworkServiceConfigBuilder.setIncludedUids(null));
        assertExpectException(NullPointerException.class, null,
                () -> preferentialNetworkServiceConfigBuilder.setExcludedUids(null));
        assertExpectException(IllegalArgumentException.class, null,
                () -> preferentialNetworkServiceConfigBuilder.setNetworkId(6));
        int[] includedUids = new int[]{1, 2};
        int[] excludedUids = new int[]{3, 4};
        preferentialNetworkServiceConfigBuilder.setIncludedUids(includedUids);
        preferentialNetworkServiceConfigBuilder.setExcludedUids(excludedUids);

        assertExpectException(IllegalStateException.class, null,
                () -> preferentialNetworkServiceConfigBuilder.build());
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_defaultPreference() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        dpm.setPreferentialNetworkServiceConfigs(
                List.of(PreferentialNetworkServiceConfig.DEFAULT));
        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
        assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0).isEnabled()).isFalse();

        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_enterprisePreference() throws Exception {
        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
                (new PreferentialNetworkServiceConfig.Builder())
                        .setEnabled(true)
                        .setNetworkId(NET_ENTERPRISE_ID_1)
                        .build();

        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
        assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
                .isEnabled()).isTrue();
        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE)
                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceIncludedUids()
            throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
                (new PreferentialNetworkServiceConfig.Builder())
                        .setEnabled(true)
                        .setNetworkId(NET_ENTERPRISE_ID_1)
                        .setFallbackToDefaultConnectionAllowed(false)
                        .setIncludedUids(new int[]{1, 2})
                        .build();
        dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
        assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
                .isEnabled()).isTrue();
        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
                        .setIncludedUids(new int[]{1, 2})
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);
    }

    @Test
    public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceExcludedUids()
            throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
                (new PreferentialNetworkServiceConfig.Builder())
                        .setEnabled(true)
                        .setNetworkId(NET_ENTERPRISE_ID_1)
                        .setFallbackToDefaultConnectionAllowed(false)
                        .setExcludedUids(new int[]{1, 2})
                        .build();

        dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
        assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
                .isEnabled()).isTrue();
        ProfileNetworkPreference preferenceDetails =
                new ProfileNetworkPreference.Builder()
                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
                        .setExcludedUids(new int[]{1, 2})
                        .build();
        List<ProfileNetworkPreference> preferences = new ArrayList<>();
        preferences.clear();
        preferences.add(preferenceDetails);
        verify(getServices().connectivityManager, times(1))
                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
                        null, null);
    }

    @Test
    public void testSetSystemSettingFailWithNonWhitelistedSettings() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        assertExpectException(SecurityException.class, null, () ->
                dpm.setSystemSetting(admin1, Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, "0"));
    }

    @Test
    public void testSetSystemSettingWithDO() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
        verify(getServices().settings).settingsSystemPutStringForUser(
                Settings.System.SCREEN_BRIGHTNESS, "0", UserHandle.USER_SYSTEM);
    }

    @Test
    public void testSetSystemSettingWithPO() throws Exception {
        setupProfileOwner();
        dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
        verify(getServices().settings).settingsSystemPutStringForUser(
            Settings.System.SCREEN_BRIGHTNESS, "0", CALLER_USER_HANDLE);
    }

    @Test
    public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setAutoTimeEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);

        dpm.setAutoTimeEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
    }

    @Test
    public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        setupProfileOwnerOnUser0();
        dpm.setAutoTimeEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);

        dpm.setAutoTimeEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
    }

    @Test
    public void testSetAutoTimeEnabledFailWithPONotOnUser0() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null,
                () -> dpm.setAutoTimeEnabled(admin1, false));
        verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
    }

    @Test
    public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        dpm.setAutoTimeEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);

        dpm.setAutoTimeEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setAutoTimeZoneEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);

        dpm.setAutoTimeZoneEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        setupProfileOwnerOnUser0();
        dpm.setAutoTimeZoneEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);

        dpm.setAutoTimeZoneEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null,
                () -> dpm.setAutoTimeZoneEnabled(admin1, false));
        verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE,
                0);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        dpm.setAutoTimeZoneEnabled(admin1, true);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);

        dpm.setAutoTimeZoneEnabled(admin1, false);
        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
    }

    @Test
    public void testIsOrganizationOwnedDevice() throws Exception {
        // Set up the user manager to return correct user info
        addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);

        // Any caller should be able to call this method.
        assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isFalse();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        verify(getServices().userManager).setUserRestriction(
                eq(UserManager.DISALLOW_ADD_USER),
                eq(true),
                eq(UserHandle.of(UserHandle.USER_SYSTEM)));

        assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isTrue();

        // A random caller from another user should also be able to get the right result.
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isTrue();
    }

    @Test
    public void testMarkOrganizationOwnedDevice_baseRestrictionsAdded() throws Exception {
        addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);

        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        // Base restriction DISALLOW_REMOVE_MANAGED_PROFILE added
        verify(getServices().userManager).setUserRestriction(
                eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE),
                eq(true),
                eq(UserHandle.of(UserHandle.USER_SYSTEM)));

        // Base restriction DISALLOW_ADD_USER added
        verify(getServices().userManager).setUserRestriction(
                eq(UserManager.DISALLOW_ADD_USER),
                eq(true),
                eq(UserHandle.of(UserHandle.USER_SYSTEM)));

        // Assert base restrictions cannot be added or removed by admin
        assertExpectException(SecurityException.class, null, () ->
                parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
        assertExpectException(SecurityException.class, null, () ->
                parentDpm.clearUserRestriction(admin1,
                        UserManager.DISALLOW_REMOVE_MANAGED_PROFILE));
        assertExpectException(SecurityException.class, null, () ->
                parentDpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
        assertExpectException(SecurityException.class, null, () ->
                parentDpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER));
    }

    @Test
    public void testSetTime() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setTime(admin1, 0);
        verify(getServices().alarmManager).setTime(0);
    }

    @Test
    public void testSetTimeFailWithPO() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null, () -> dpm.setTime(admin1, 0));
    }

    @Test
    public void testSetTimeWithPOOfOrganizationOwnedDevice() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        dpm.setTime(admin1, 0);
        verify(getServices().alarmManager).setTime(0);
    }

    @Test
    public void testSetTimeWithAutoTimeOn() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME, 0))
                .thenReturn(1);
        assertThat(dpm.setTime(admin1, 0)).isFalse();
    }

    @Test
    public void testSetTimeZone() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setTimeZone(admin1, "Asia/Shanghai");
        verify(getServices().alarmManagerInternal)
                .setTimeZone(eq("Asia/Shanghai"), eq(TIME_ZONE_CONFIDENCE_HIGH), anyString());
    }

    @Test
    public void testSetTimeZoneFailWithPO() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null,
                () -> dpm.setTimeZone(admin1, "Asia/Shanghai"));
    }

    @Test
    public void testSetTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        dpm.setTimeZone(admin1, "Asia/Shanghai");
        verify(getServices().alarmManagerInternal)
                .setTimeZone(eq("Asia/Shanghai"), eq(TIME_ZONE_CONFIDENCE_HIGH), anyString());
    }

    @Test
    public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME_ZONE, 0))
                .thenReturn(1);
        assertThat(dpm.setTimeZone(admin1, "Asia/Shanghai")).isFalse();
    }

    @Test
    public void testGetLastBugReportRequestTime() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        mContext.packageName = admin1.getPackageName();
        mContext.applicationInfo = new ApplicationInfo();
        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
        // feature is disabled because there are non-affiliated secondary users.
        getServices().removeUser(CALLER_USER_HANDLE);

        // No bug reports were requested so far.
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(-1);

        // Requesting a bug report should update the timestamp.
        final long beforeRequest = System.currentTimeMillis();
        dpm.requestBugreport(admin1);
        final long bugReportRequestTime = dpm.getLastBugReportRequestTime();
        final long afterRequest = System.currentTimeMillis();
        assertThat(bugReportRequestTime).isAtLeast(beforeRequest);
        assertThat(bugReportRequestTime).isAtMost(afterRequest);

        // Checking the timestamp again should not change it.
        Thread.sleep(2);
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime);

        // Restarting the DPMS should not lose the timestamp.
        initializeDpms();
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime);

        // Any uid holding MANAGE_USERS permission can retrieve the timestamp.
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime);
        mContext.callerPermissions.remove(permission.MANAGE_USERS);

        // System can retrieve the timestamp.
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime);

        // Removing the device owner should clear the timestamp.
        clearDeviceOwner();
        assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(-1);
    }

    @Test
    public void testGetLastNetworkLogRetrievalTime() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        mContext.packageName = admin1.getPackageName();
        mContext.applicationInfo = new ApplicationInfo();
        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
        // feature is disabled because there are non-affiliated secondary users.
        getServices().removeUser(CALLER_USER_HANDLE);
        when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
                .thenReturn(true);

        // No logs were retrieved so far.
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Attempting to retrieve logs without enabling logging should not change the timestamp.
        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Enabling logging should not change the timestamp.
        dpm.setNetworkLoggingEnabled(admin1, true);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Retrieving the logs should update the timestamp.
        final long beforeRetrieval = System.currentTimeMillis();
        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
        final long firstNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime();
        final long afterRetrieval = System.currentTimeMillis();
        assertThat(firstNetworkLogRetrievalTime >= beforeRetrieval).isTrue();
        assertThat(firstNetworkLogRetrievalTime <= afterRetrieval).isTrue();

        // Checking the timestamp again should not change it.
        Thread.sleep(2);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(firstNetworkLogRetrievalTime);

        // Retrieving the logs again should update the timestamp.
        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);
        final long secondNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime();
        assertThat(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime).isTrue();

        // Disabling logging should not change the timestamp.
        Thread.sleep(2);
        dpm.setNetworkLoggingEnabled(admin1, false);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime);

        // Restarting the DPMS should not lose the timestamp.
        initializeDpms();
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime);

        // Any uid holding MANAGE_USERS permission can retrieve the timestamp.
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime);
        mContext.callerPermissions.remove(permission.MANAGE_USERS);

        // System can retrieve the timestamp.
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime);

        // Removing the device owner should clear the timestamp.
        clearDeviceOwner();
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);
    }

    @Test
    public void testSetNetworkLoggingEnabled_asPo() throws Exception {
        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        mContext.applicationInfo = new ApplicationInfo();
        mContext.packageName = admin1.getPackageName();
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.S);
        when(getServices().iipConnectivityMetrics
                .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true);

        // Check no logs have been retrieved so far.
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Enable network logging
        dpm.setNetworkLoggingEnabled(admin1, true);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Retrieve the network logs and verify timestamp has been updated.
        final long beforeRetrieval = System.currentTimeMillis();

        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);

        final long networkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime();
        final long afterRetrieval = System.currentTimeMillis();
        assertThat(networkLogRetrievalTime >= beforeRetrieval).isTrue();
        assertThat(networkLogRetrievalTime <= afterRetrieval).isTrue();
    }

    @Test
    public void testSetNetworkLoggingEnabled_asPoOfOrgOwnedDevice() throws Exception {
        // Setup profile owner on organization-owned device
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        mContext.packageName = admin1.getPackageName();
        mContext.applicationInfo = new ApplicationInfo();
        when(getServices().iipConnectivityMetrics
                .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true);

        // Check no logs have been retrieved so far.
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Enable network logging
        dpm.setNetworkLoggingEnabled(admin1, true);
        assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1);

        // Retrieve the network logs and verify timestamp has been updated.
        final long beforeRetrieval = System.currentTimeMillis();

        dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */);

        final long networkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime();
        final long afterRetrieval = System.currentTimeMillis();
        assertThat(networkLogRetrievalTime >= beforeRetrieval).isTrue();
        assertThat(networkLogRetrievalTime <= afterRetrieval).isTrue();
    }

    @Test
    public void testGetBindDeviceAdminTargetUsers() throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);

        // Setup device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        // Only device owner is setup, the result list should be empty.
        List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertEmpty(targetUsers);

        // Add a secondary user, it should never talk with.
        final int ANOTHER_USER_ID = 36;
        getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY);

        // Since the managed profile is not affiliated, they should not be allowed to talk to each
        // other.
        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertEmpty(targetUsers);

        // Setting affiliation ids
        final Set<String> userAffiliationIds = Collections.singleton("some.affiliation-id");
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        dpm.setAffiliationIds(admin1, userAffiliationIds);

        // Changing affiliation ids in one
        dpm.setAffiliationIds(admin1, Collections.singleton("some-different-affiliation-id"));

        // Since the managed profile is not affiliated any more, they should not be allowed to talk
        // to each other.
        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertEmpty(targetUsers);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertEmpty(targetUsers);
    }

    private void verifyLockTaskState(int userId) throws Exception {
        verifyLockTaskState(userId, new String[0],
                DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS);
    }

    private void verifyLockTaskState(int userId, String[] packages, int flags) throws Exception {
        verify(getServices().iactivityManager).updateLockTaskPackages(userId, packages);
        verify(getServices().iactivityTaskManager).updateLockTaskFeatures(userId, flags);
    }

    private void verifyCanSetLockTask(int uid, int userId, ComponentName who, String[] packages,
            int flags) throws Exception {
        mContext.binder.callingUid = uid;
        dpm.setLockTaskPackages(who, packages);
        MoreAsserts.assertEquals(packages, dpm.getLockTaskPackages(who));
        for (String p : packages) {
            assertThat(dpm.isLockTaskPermitted(p)).isTrue();
        }
        assertThat(dpm.isLockTaskPermitted("anotherPackage")).isFalse();
        // Test to see if set lock task features can be set
        dpm.setLockTaskFeatures(who, flags);
        verifyLockTaskState(userId, packages, flags);
    }

    private void verifyCanNotSetLockTask(int uid, ComponentName who, String[] packages,
            int flags) throws Exception {
        mContext.binder.callingUid = uid;
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.setLockTaskPackages(who, packages));
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.getLockTaskPackages(who));
        assertThat(dpm.isLockTaskPermitted("doPackage1")).isFalse();
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.setLockTaskFeatures(who, flags));
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testLockTaskPolicyForProfileOwner() throws Exception {
        mockPolicyExemptApps();
        mockVendorPolicyExemptApps();

        // Setup a PO
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);
        verifyLockTaskState(CALLER_USER_HANDLE);

        final String[] poPackages = {"poPackage1", "poPackage2"};
        final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_HOME
                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
        verifyCanSetLockTask(DpmMockContext.CALLER_UID, CALLER_USER_HANDLE, admin1,
                poPackages, poFlags);

        // Set up a managed profile managed by different package (package name shouldn't matter)
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
        final ComponentName adminDifferentPackage =
                new ComponentName("another.package", "whatever.class");
        addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
        verifyLockTaskState(MANAGED_PROFILE_USER_ID);

        // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages.
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        final String[] mpoPackages = {"poPackage1", "poPackage2"};
        final int mpoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_HOME
                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
        verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, mpoPackages,
                mpoFlags);
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testLockTaskFeatures_IllegalArgumentException() throws Exception {
        // Setup a device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // Lock task policy is updated when loading user data.
        verifyLockTaskState(UserHandle.USER_SYSTEM);

        final int flags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
        assertExpectException(IllegalArgumentException.class,
                "Cannot use LOCK_TASK_FEATURE_OVERVIEW without LOCK_TASK_FEATURE_HOME",
                () -> dpm.setLockTaskFeatures(admin1, flags));
    }

    @Test
    public void testSecondaryLockscreen_profileOwner() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        // Initial state is disabled.
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
        CALLER_USER_HANDLE))).isFalse();

        // Profile owner can set enabled state.
        setAsProfileOwner(admin1);
        when(mServiceContext.resources
                .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
                .thenReturn(admin1.flattenToString());
        dpm.setSecondaryLockscreenEnabled(admin1, true);
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
        CALLER_USER_HANDLE))).isTrue();

        // Managed profile managed by different package is unaffiliated - cannot set enabled.
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 20456);
        final ComponentName adminDifferentPackage =
                new ComponentName("another.package", "whatever.class");
        addManagedProfile(adminDifferentPackage, managedProfileAdminUid, admin2);
        mContext.binder.callingUid = managedProfileAdminUid;
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setSecondaryLockscreenEnabled(adminDifferentPackage, false));
    }

    @Test
    public void testSecondaryLockscreen_deviceOwner() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Initial state is disabled.
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM)))
                .isFalse();

        // Device owners can set enabled state.
        setupDeviceOwner();
        when(mServiceContext.resources
                .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
                .thenReturn(admin1.flattenToString());
        dpm.setSecondaryLockscreenEnabled(admin1, true);
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM)))
                .isTrue();
    }

    @Test
    public void testSecondaryLockscreen_nonOwner() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        // Initial state is disabled.
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse();

        // Non-DO/PO cannot set enabled state.
        when(mServiceContext.resources
                .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
                .thenReturn(admin1.flattenToString());
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setSecondaryLockscreenEnabled(admin1, true));
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse();
    }

    @Test
    public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        // Ensure packages are *not* flagged as test_only.
        doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
                eq(admin1.getPackageName()),
                anyLong(),
                eq(CALLER_USER_HANDLE));
        doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
                eq(admin2.getPackageName()),
                anyLong(),
                eq(CALLER_USER_HANDLE));

        // Initial state is disabled.
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse();

        // Caller is Profile Owner, but no supervision app is configured.
        setAsProfileOwner(admin1);
        assertExpectException(SecurityException.class, "is not the default supervision component",
                () -> dpm.setSecondaryLockscreenEnabled(admin1, true));
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse();

        // Caller is Profile Owner, but is not the default configured supervision app.
        when(mServiceContext.resources
                .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
                .thenReturn(admin2.flattenToString());
        assertExpectException(SecurityException.class, "is not the default supervision component",
                () -> dpm.setSecondaryLockscreenEnabled(admin1, true));
        assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse();
    }

    @Test
    public void testIsDeviceManaged() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        // The device owner itself, any uid holding MANAGE_USERS permission and the system can
        // find out that the device has a device owner.
        assertThat(dpm.isDeviceManaged()).isTrue();
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.isDeviceManaged()).isTrue();
        mContext.callerPermissions.remove(permission.MANAGE_USERS);
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.isDeviceManaged()).isTrue();

        clearDeviceOwner();

        // Any uid holding MANAGE_USERS permission and the system can find out that the device does
        // not have a device owner.
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.isDeviceManaged()).isFalse();
        mContext.callerPermissions.remove(permission.MANAGE_USERS);
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.isDeviceManaged()).isFalse();
    }

    @Test
    public void testDeviceOwnerOrganizationName() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        dpm.setOrganizationName(admin1, "organization");

        // Device owner can retrieve organization managing the device.
        assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization");

        // Any uid holding MANAGE_USERS permission can retrieve organization managing the device.
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization");
        mContext.callerPermissions.remove(permission.MANAGE_USERS);

        // System can retrieve organization managing the device.
        mContext.binder.clearCallingIdentity();
        assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization");

        // Removing the device owner clears the organization managing the device.
        clearDeviceOwner();
        assertThat(dpm.getDeviceOwnerOrganizationName()).isNull();
    }

    @Test
    public void testWipeDataManagedProfile() throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        // Get mock reason string since we throw an IAE with empty string input.
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe))
                .thenReturn("Just a test string.");

        dpm.wipeData(0);
        verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(
                MANAGED_PROFILE_USER_ID);
    }

    @Test
    @Ignore("b/277916462")
    public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception {
        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
                FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "true", false);
        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_TELEPHONY,
                FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "true", false);
        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        // Get mock reason string since we throw an IAE with empty string input.
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe))
                .thenReturn("Just a test string.");
        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        when(getServices().userManager.getPrimaryUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        when(getServices().subscriptionManager.getActiveSubscriptionIdList(false)).thenReturn(
                new int[1]);
        // Set some device-wide policies:
        // Security logging
        when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true);
        // System update policy
        dpms.mOwners.setSystemUpdatePolicy(SystemUpdatePolicy.createAutomaticInstallPolicy());
        // Make it look as if FRP agent is present.
        when(dpms.mMockInjector.getPersistentDataBlockManagerInternal().getAllowedUid())
                .thenReturn(12345 /* some UID in user 0 */);
        // Make personal apps look suspended
        dpms.getUserData(UserHandle.USER_SYSTEM).mAppsSuspended = true;
        // Screen capture
        dpm.setScreenCaptureDisabled(admin1, true);

        dpm.wipeData(0);
        verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(CALLER_USER_HANDLE);

        // Make sure COPE restrictions are lifted:
        verify(getServices().userManager).setUserRestriction(
                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM);
        verify(getServices().userManager).setUserRestriction(
                UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM);

        clearInvocations(getServices().iwindowManager);

        // Some device-wide policies are getting cleaned-up after the user is removed.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_REMOVED, CALLER_USER_HANDLE);

        // Screenlock info should be removed
        verify(getServices().lockPatternUtils).setDeviceOwnerInfo(null);
        // Wifi config lockdown should be lifted
        verify(getServices().settings).settingsGlobalPutInt(
                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
        // System update policy should be removed
        assertThat(dpms.mOwners.getSystemUpdatePolicy()).isNull();
        // FRP agent should be notified
        verify(mContext.spiedContext, times(0)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
        // Refresh strong auth timeout
        verify(getServices().lockSettingsInternal).refreshStrongAuthTimeout(UserHandle.USER_SYSTEM);
        // Refresh screen capture
        verify(getServices().iwindowManager).refreshScreenCaptureDisabled();
        // Unsuspend personal apps
        verify(getServices().packageManagerInternal)
                .unsuspendAdminSuspendedPackages(UserHandle.USER_SYSTEM);
        verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
                FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_TELEPHONY,
                FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
    }

    @Test
    public void testWipeDataManagedProfileDisallowed() throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                UserHandle.of(MANAGED_PROFILE_USER_ID)))
                .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
                thenReturn("Just a test string.");

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        // The PO is not allowed to remove the profile if the user restriction was set on the
        // profile by the system
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.wipeData(0));
    }

    @Test
    public void testWipeDevice_DeviceOwner() throws Exception {
        setDeviceOwner();
        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_FACTORY_RESET,
                UserHandle.SYSTEM))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
                thenReturn("Just a test string.");

        dpm.wipeDevice(0);

        verifyRebootWipeUserData(/* wipeEuicc= */ false);
    }

    @Test
    public void testWipeEuiccDataEnabled() throws Exception {
        setDeviceOwner();
        when(getServices().userManager.getUserRestrictionSource(
            UserManager.DISALLOW_FACTORY_RESET,
            UserHandle.SYSTEM))
            .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
                thenReturn("Just a test string.");

        dpm.wipeDevice(WIPE_EUICC);

        verifyRebootWipeUserData(/* wipeEuicc= */ true);
    }

    @Test
    public void testWipeDevice_DeviceOwnerDisallowed() throws Exception {
        setDeviceOwner();
        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_FACTORY_RESET,
                UserHandle.SYSTEM))
                .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);
        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
                thenReturn("Just a test string.");
        // The DO is not allowed to wipe the device if the user restriction was set
        // by the system
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.wipeDevice(0));
    }

    @Test
    public void testMaximumFailedPasswordAttemptsReachedManagedProfile() throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                UserHandle.of(MANAGED_PROFILE_USER_ID)))
                .thenReturn(UserManager.RESTRICTION_SOURCE_PROFILE_OWNER);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
        // Failed password attempts on the parent user are taken into account, as there isn't a
        // separate work challenge.
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // The profile should be wiped even if DISALLOW_REMOVE_MANAGED_PROFILE is enabled, because
        // both the user restriction and the policy were set by the PO.
        verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(
                MANAGED_PROFILE_USER_ID);
        verifyZeroInteractions(getServices().recoverySystem);
    }

    @Test
    public void testMaximumFailedPasswordAttemptsReachedManagedProfileDisallowed()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                UserHandle.of(MANAGED_PROFILE_USER_ID)))
                .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
        // Failed password attempts on the parent user are taken into account, as there isn't a
        // separate work challenge.
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // DISALLOW_REMOVE_MANAGED_PROFILE was set by the system, not the PO, so the profile is
        // not wiped.
        verify(getServices().userManagerInternal, never())
                .removeUserEvenWhenDisallowed(anyInt());
        verifyZeroInteractions(getServices().recoverySystem);
    }

    @Test
    public void testMaximumFailedPasswordAttemptsReachedDeviceOwner() throws Exception {
        setDeviceOwner();
        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_FACTORY_RESET,
                UserHandle.SYSTEM))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);

        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // The device should be wiped even if DISALLOW_FACTORY_RESET is enabled, because both the
        // user restriction and the policy were set by the DO.
        verifyRebootWipeUserData(/* wipeEuicc= */ false);
    }

    @Test
    public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception {
        setDeviceOwner();
        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_FACTORY_RESET,
                UserHandle.SYSTEM))
                .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM);

        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // DISALLOW_FACTORY_RESET was set by the system, not the DO, so the device is not wiped.
        verifyZeroInteractions(getServices().recoverySystem);
        verify(getServices().userManagerInternal, never())
                .removeUserEvenWhenDisallowed(anyInt());
    }

    @Test
    public void testMaximumFailedDevicePasswordAttemptsReachedOrgOwnedManagedProfile()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        configureProfileOwnerOfOrgOwnedDevice(admin1, MANAGED_PROFILE_USER_ID);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        assertThat(dpm.getMaximumFailedPasswordsForWipe(admin1)).isEqualTo(3);
        assertThat(dpm.getMaximumFailedPasswordsForWipe(null)).isEqualTo(3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        assertThat(dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)).isEqualTo(3);
        // Check that primary will be wiped as a result of failed primary user unlock attempts.
        assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM))
                .isEqualTo(UserHandle.USER_SYSTEM);

        // Failed password attempts on the parent user are taken into account, as there isn't a
        // separate work challenge.
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // For managed profile on an organization owned device, the whole device should be wiped.
        verifyRebootWipeUserData(/* wipeEuicc= */ false);
    }

    @Test
    public void testMaximumFailedProfilePasswordAttemptsReachedOrgOwnedManagedProfile()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        doReturn(true).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);

        // Configure separate challenge.
        configureProfileOwnerOfOrgOwnedDevice(admin1, MANAGED_PROFILE_USER_ID);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        assertThat(dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)).isEqualTo(0);
        assertThat(dpm.getMaximumFailedPasswordsForWipe(null, MANAGED_PROFILE_USER_ID))
                .isEqualTo(3);
        // Check that the policy is not affecting primary profile challenge.
        assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM))
                .isEqualTo(UserHandle.USER_NULL);
        // Check that primary will be wiped as a result of failed profile unlock attempts.
        assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(MANAGED_PROFILE_USER_ID))
                .isEqualTo(UserHandle.USER_SYSTEM);

        // Simulate three failed attempts at solving the separate challenge.
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);

        // For managed profile on an organization owned device, the whole device should be wiped.
        verifyRebootWipeUserData(/* wipeEuicc= */ false);
    }

    @Test
    public void testGetPermissionGrantState() throws Exception {
        final String permission = "some.permission";
        final String app1 = "com.example.app1";
        final String app2 = "com.example.app2";

        when(getServices().ipackageManager.checkPermission(eq(permission), eq(app1), anyInt()))
                .thenReturn(PackageManager.PERMISSION_GRANTED);
        doReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED).when(getServices().packageManager)
                .getPermissionFlags(permission, app1, UserHandle.SYSTEM);
        when(getServices().packageManager.getPermissionFlags(permission, app1,
                UserHandle.of(CALLER_USER_HANDLE)))
                .thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
        when(getServices().ipackageManager.checkPermission(eq(permission), eq(app2), anyInt()))
                .thenReturn(PackageManager.PERMISSION_DENIED);
        doReturn(0).when(getServices().packageManager).getPermissionFlags(permission, app2,
                UserHandle.SYSTEM);
        when(getServices().packageManager.getPermissionFlags(permission, app2,
                UserHandle.of(CALLER_USER_HANDLE))).thenReturn(0);

        // System can retrieve permission grant state.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = "android";
        assertThat(dpm.getPermissionGrantState(null, app1, permission))
                .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
        assertThat(dpm.getPermissionGrantState(null, app2, permission))
                .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);

        // A regular app cannot retrieve permission grant state.
        mContext.binder.callingUid = setupPackageInPackageManager(app1, 1);
        mContext.packageName = app1;
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.getPermissionGrantState(null, app1, permission));

        // Profile owner can retrieve permission grant state.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        mContext.packageName = admin1.getPackageName();
        setAsProfileOwner(admin1);
        assertThat(dpm.getPermissionGrantState(admin1, app1, permission))
                .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
        assertThat(dpm.getPermissionGrantState(admin1, app2, permission))
                .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
    }

    @Test
    @Ignore("b/277916462")
    public void testResetPasswordWithToken() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // test token validation
        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                () -> dpm.setResetPasswordToken(admin1, new byte[31]));

        // test adding a token
        final byte[] token = new byte[32];
        final long handle = 123456;
        final String password = "password";
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // test password activation
        when(getServices().lockPatternUtils.isEscrowTokenActive(handle, UserHandle.USER_SYSTEM))
                .thenReturn(true);
        assertThat(dpm.isResetPasswordTokenActive(admin1)).isTrue();

        // test reset password with token
        when(getServices().lockPatternUtils.setLockCredentialWithToken(
                LockscreenCredential.createPassword(password), handle, token,
                UserHandle.USER_SYSTEM)).thenReturn(true);
        assertThat(dpm.resetPasswordWithToken(admin1, password, token, 0)).isTrue();

        // test removing a token
        when(getServices().lockPatternUtils.removeEscrowToken(handle, UserHandle.USER_SYSTEM))
                .thenReturn(true);
        assertThat(dpm.clearResetPasswordToken(admin1)).isTrue();
    }

    @Test
    @Ignore("b/277916462")
    public void resetPasswordWithToken_NumericPin() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // adding a token
        final byte[] token = new byte[32];
        final long handle = 123456;
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // Test resetting with a numeric pin
        final String pin = "123456";
        when(getServices().lockPatternUtils.setLockCredentialWithToken(
                LockscreenCredential.createPin(pin), handle, token,
                UserHandle.USER_SYSTEM)).thenReturn(true);
        assertThat(dpm.resetPasswordWithToken(admin1, pin, token, 0)).isTrue();
    }

    @Test
    @Ignore("b/277916462")
    public void resetPasswordWithToken_EmptyPassword() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // adding a token
        final byte[] token = new byte[32];
        final long handle = 123456;
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // Test resetting with an empty password
        final String password = "";
        when(getServices().lockPatternUtils.setLockCredentialWithToken(
                LockscreenCredential.createNone(), handle, token,
                UserHandle.USER_SYSTEM)).thenReturn(true);
        assertThat(dpm.resetPasswordWithToken(admin1, password, token, 0)).isTrue();
    }

    @Test
    public void testIsActivePasswordSufficient() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        mContext.packageName = admin1.getPackageName();
        setupDeviceOwner();

        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
        dpm.setPasswordMinimumLength(admin1, 8);
        dpm.setPasswordMinimumLetters(admin1, 6);
        dpm.setPasswordMinimumLowerCase(admin1, 3);
        dpm.setPasswordMinimumUpperCase(admin1, 1);
        dpm.setPasswordMinimumNonLetter(admin1, 1);
        dpm.setPasswordMinimumNumeric(admin1, 1);
        dpm.setPasswordMinimumSymbols(admin1, 0);

        reset(mContext.spiedContext);

        PasswordMetrics passwordMetricsNoSymbols = metricsForPassword("abcdXYZ5");

        setActivePasswordState(passwordMetricsNoSymbols);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();

        initializeDpms();
        reset(mContext.spiedContext);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();

        // This call simulates the user entering the password for the first time after a reboot.
        // This causes password metrics to be reloaded into memory.  Until this happens,
        // dpm.isActivePasswordSufficient() will continue to return its last checkpointed value,
        // even if the DPC changes password requirements so that the password no longer meets the
        // requirements.  This is a known limitation of the current implementation of
        // isActivePasswordSufficient() - see b/34218769.
        setActivePasswordState(passwordMetricsNoSymbols);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();

        dpm.setPasswordMinimumSymbols(admin1, 1);
        // This assertion would fail if we had not called setActivePasswordState() again after
        // initializeDpms() - see previous comment.
        assertThat(dpm.isActivePasswordSufficient()).isFalse();

        initializeDpms();
        reset(mContext.spiedContext);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();

        PasswordMetrics passwordMetricsWithSymbols = metricsForPassword("abcd.XY5");

        setActivePasswordState(passwordMetricsWithSymbols);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void testIsActivePasswordSufficient_noLockScreen() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // If there is no lock screen, the password is considered empty no matter what, because
        // it provides no security.
        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(false);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        mContext.packageName = admin1.getPackageName();
        setupDeviceOwner();
        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
        // When there is no lockscreen, user password metrics is always empty.
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));

        // If no password requirements are set, isActivePasswordSufficient should succeed.
        assertThat(dpm.isActivePasswordSufficient()).isTrue();

        // Now set some password quality requirements.
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);

        reset(mContext.spiedContext);
        // This should be ignored, as there is no lock screen.
        dpm.reportPasswordChanged(new PasswordMetrics(CREDENTIAL_TYPE_NONE), userHandle);

        // No broadcast should be sent.
        verify(mContext.spiedContext, times(0)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED),
                MockUtils.checkUserHandle(userHandle));

        // The active (nonexistent) password doesn't comply with the requirements.
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
    }

    @Test
    public void testIsPasswordSufficientAfterProfileUnification() throws Exception {
        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;

        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        doReturn(true).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(managedProfileUserId);

        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);

        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPin("184342"));

        // Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
        // on the parent admin)
        assertThat(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM,
        UserHandle.USER_NULL)).isTrue();
        // Numeric password is not compliant if profile is to be unified: the profile has a
        // QUALITY_ALPHABETIC policy on itself which will be enforced on the password after
        // unification.
        assertThat(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM,
        managedProfileUserId)).isFalse();
    }

    @Test
    public void testGetAggregatedPasswordComplexity_IgnoreProfileRequirement()
            throws Exception {
        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);

        // Profile has a unified challenge
        doReturn(false).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(managedProfileUserId);
        doReturn(true).when(getServices().lockPatternUtils)
                .isProfileWithUnifiedChallenge(managedProfileUserId);

        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);

        assertThat(dpms.getAggregatedPasswordComplexityForUser(UserHandle.USER_SYSTEM, true))
                .isEqualTo(PASSWORD_COMPLEXITY_LOW);
        assertThat(dpms.getAggregatedPasswordComplexityForUser(UserHandle.USER_SYSTEM, false))
                .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
    }

    @Test
    public void testGetAggregatedPasswordMetrics_IgnoreProfileRequirement()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);

        // Profile has a unified challenge
        doReturn(false).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(managedProfileUserId);
        doReturn(true).when(getServices().lockPatternUtils)
                .isProfileWithUnifiedChallenge(managedProfileUserId);

        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
        dpm.setPasswordMinimumLength(admin1, 8);
        dpm.setPasswordMinimumLetters(admin1, 1);
        dpm.setPasswordMinimumNumeric(admin1, 2);
        dpm.setPasswordMinimumSymbols(admin1, 3);

        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);

        PasswordMetrics deviceMetrics =
                dpms.getPasswordMinimumMetrics(UserHandle.USER_SYSTEM, true);
        assertThat(deviceMetrics.credType).isEqualTo(LockPatternUtils.CREDENTIAL_TYPE_PATTERN);

        PasswordMetrics allMetrics =
                dpms.getPasswordMinimumMetrics(UserHandle.USER_SYSTEM, false);
        assertThat(allMetrics.credType).isEqualTo(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
        assertThat(allMetrics.length).isEqualTo(8);
        assertThat(allMetrics.letters).isEqualTo(1);
        assertThat(allMetrics.numeric).isEqualTo(2);
        assertThat(allMetrics.symbols).isEqualTo(3);
    }

    @Test
    public void testCanSetPasswordRequirementOnParentPreS() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
        dpms.mMockInjector.setChangeEnabledForPackage(165573442L, false,
                admin1.getPackageName(), managedProfileUserId);

        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
        assertThat(parentDpm.getPasswordQuality(admin1))
                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
    }

    @Test
    public void testCannotSetPasswordRequirementOnParent() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        dpms.mMockInjector.setChangeEnabledForPackage(165573442L, true,
                admin1.getPackageName(), managedProfileUserId);

        try {
            assertExpectException(SecurityException.class, null, () ->
                    parentDpm.setPasswordQuality(
                            admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX));
        } finally {
            dpms.mMockInjector.clearEnabledChanges();
        }
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileQualityRequirementMet()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set profile password quality requirement. No password added yet so
        // profile.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();

        // Set a work challenge and verify profile.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
                .thenReturn(metricsForPassword("abcdXYZ5"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileComplexityRequirementMet()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set profile password complexity requirement. No password added yet so
        // profile.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();

        // Set a work challenge and verify profile.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
                .thenReturn(metricsForPin("5156"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ParentQualityRequirementMet()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set parent password quality requirement. No password added yet so
        // parent.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPassword("acbdXYZ5"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ParentComplexityRequirementMet()
            throws Exception {
        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set parent password complexity requirement. No password added yet so
        // parent.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPin("1234"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileQualityRequirementMet()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set profile password quality requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPassword("abcdXYZ5"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileComplexityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set profile password complexity requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPin("51567548"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentQualityRequirementMet()
            throws Exception {
        assumeDeprecatedPasswordApisSupported();

        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set parent password quality requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPassword("abcdXYZ5"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentComplexityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set parent password complexity requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(metricsForPin("5156"));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    private void addManagedProfileForPasswordTests(int userId, int adminUid,
            boolean separateChallenge) throws Exception {
        addManagedProfile(admin1, adminUid, admin1);
        when(getServices().userManager.getProfileParent(userId))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        doReturn(separateChallenge).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(userId);
        doReturn(!separateChallenge).when(getServices().lockPatternUtils)
                .isProfileWithUnifiedChallenge(userId);
        when(getServices().userManager.getCredentialOwnerProfile(userId))
                .thenReturn(separateChallenge ? userId : UserHandle.USER_SYSTEM);
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userId))
                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));
    }

    @Test
    public void testPasswordQualityAppliesToParentPreS() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
        assertThat(parentDpm.getPasswordQuality(null))
                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
    }

    @Test
    public void testPasswordQualityDoesNotApplyToParentPostS() throws Exception {
        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);

        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
        assertThat(parentDpm.getPasswordQuality(admin1))
                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
    }

    private void setActivePasswordState(PasswordMetrics passwordMetrics)
            throws Exception {
        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
        final long ident = mContext.binder.clearCallingIdentity();

        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
                .thenReturn(passwordMetrics);
        dpm.reportPasswordChanged(passwordMetrics, userHandle);

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(userHandle),
                eq(null),
                any(Bundle.class));

        final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
        intent.setComponent(admin1);
        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userHandle));

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(userHandle),
                eq(null),
                any());

        // CertificateMonitor.updateInstalledCertificates is called on the background thread,
        // let it finish with system uid, otherwise it will throw and crash.
        flushTasks(dpms);

        mContext.binder.restoreCallingIdentity(ident);
    }

    @Test
    public void testIsCurrentInputMethodSetByOwnerForDeviceOwner() throws Exception {
        final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD;
        final Uri currentImeUri = Settings.Secure.getUriFor(currentIme);
        final int deviceOwnerUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
                DpmMockContext.SYSTEM_UID);
        final int secondUserSystemUid = UserHandle.getUid(CALLER_USER_HANDLE,
                DpmMockContext.SYSTEM_UID);

        // Set up a device owner.
        mContext.binder.callingUid = deviceOwnerUid;
        setupDeviceOwner();

        // First and second user set IMEs manually.
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Device owner changes IME for first user.
        mContext.binder.callingUid = deviceOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                UserHandle.USER_SYSTEM)).thenReturn("ime1");
        dpm.setSecureSetting(admin1, currentIme, "ime2");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime2",
                UserHandle.USER_SYSTEM);
        reset(getServices().settings);
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Second user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // First user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Device owner changes IME for first user again.
        mContext.binder.callingUid = deviceOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                UserHandle.USER_SYSTEM)).thenReturn("ime2");
        dpm.setSecureSetting(admin1, currentIme, "ime3");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime3",
                UserHandle.USER_SYSTEM);
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Restarting the DPMS should not lose information.
        initializeDpms();
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Device owner can find out whether it set the current IME itself.
        mContext.binder.callingUid = deviceOwnerUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // Removing the device owner should clear the information that it set the current IME.
        clearDeviceOwner();
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
    }

    @Test
    public void testIsCurrentInputMethodSetByOwnerForProfileOwner() throws Exception {
        final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD;
        final Uri currentImeUri = Settings.Secure.getUriFor(currentIme);
        final int profileOwnerUid = DpmMockContext.CALLER_UID;
        final int firstUserSystemUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
                DpmMockContext.SYSTEM_UID);
        final int secondUserSystemUid = UserHandle.getUid(CALLER_USER_HANDLE,
                DpmMockContext.SYSTEM_UID);

        // Set up a profile owner.
        mContext.binder.callingUid = profileOwnerUid;
        setupProfileOwner();

        // First and second user set IMEs manually.
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Profile owner changes IME for second user.
        mContext.binder.callingUid = profileOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                CALLER_USER_HANDLE)).thenReturn("ime1");
        dpm.setSecureSetting(admin1, currentIme, "ime2");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime2",
                CALLER_USER_HANDLE);
        reset(getServices().settings);
        dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // First user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // Second user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();

        // Profile owner changes IME for second user again.
        mContext.binder.callingUid = profileOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                CALLER_USER_HANDLE)).thenReturn("ime2");
        dpm.setSecureSetting(admin1, currentIme, "ime3");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime3",
                CALLER_USER_HANDLE);
        dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // Restarting the DPMS should not lose information.
        initializeDpms();
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // Profile owner can find out whether it set the current IME itself.
        mContext.binder.callingUid = profileOwnerUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue();

        // Removing the profile owner should clear the information that it set the current IME.
        dpm.clearProfileOwner(admin1);
        mContext.binder.callingUid = firstUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
        mContext.binder.callingUid = secondUserSystemUid;
        assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse();
    }

    @Test
    public void testSetPermittedCrossProfileNotificationListeners_unavailableForDo()
            throws Exception {
        // Set up a device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid);
    }

    @Test
    public void testSetPermittedCrossProfileNotificationListeners_unavailableForPoOnUser()
            throws Exception {
        // Set up a profile owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();
        assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid);
    }

    private void assertSetPermittedCrossProfileNotificationListenersUnavailable(
            int adminUid) throws Exception {
        mContext.binder.callingUid = adminUid;
        final int userId = UserHandle.getUserId(adminUid);

        final String packageName = "some.package";
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
        admin1, Collections.singletonList(packageName))).isFalse();
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(packageName, userId)).isTrue();

        // Attempt to set to empty list (which means no listener is allowlisted)
        mContext.binder.callingUid = adminUid;
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, emptyList())).isFalse();
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(packageName, userId)).isTrue();
    }

    @Test
    public void testIsNotificationListenerServicePermitted_onlySystemCanCall() throws Exception {
        // Set up a managed profile
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        final String permittedListener = "some.package";
        setupPackageInPackageManager(
                permittedListener,
                UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user.
                /*appId=*/ 12345, /*flags=*/ 0);

        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
        admin1, Collections.singletonList(permittedListener))).isTrue();

        // isNotificationListenerServicePermitted should throw if not called from System.
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpms.isNotificationListenerServicePermitted(
                        permittedListener, MANAGED_PROFILE_USER_ID));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        permittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
    }

    @Test
    public void testSetPermittedCrossProfileNotificationListeners_managedProfile()
            throws Exception {
        // Set up a managed profile
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        final String permittedListener = "permitted.package";
        int appId = 12345;
        setupPackageInPackageManager(
                permittedListener,
                UserHandle.USER_SYSTEM,  // We check the packageInfo from the primary user.
                appId, /*flags=*/ 0);

        final String notPermittedListener = "not.permitted.package";
        setupPackageInPackageManager(
                notPermittedListener,
                UserHandle.USER_SYSTEM,  // We check the packageInfo from the primary user.
                ++appId, /*flags=*/ 0);

        final String systemListener = "system.package";
        setupPackageInPackageManager(
                systemListener,
                UserHandle.USER_SYSTEM,  // We check the packageInfo from the primary user.
                ++appId, ApplicationInfo.FLAG_SYSTEM);

        // By default all packages are allowed
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        permittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        notPermittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();

        // Setting only one package in the allowlist
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
        admin1, Collections.singletonList(permittedListener))).isTrue();
        final List<String> permittedListeners =
                dpms.getPermittedCrossProfileNotificationListeners(admin1);
        assertThat(permittedListeners.size()).isEqualTo(1);
        assertThat(permittedListeners.get(0)).isEqualTo(permittedListener);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        permittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        notPermittedListener, MANAGED_PROFILE_USER_ID)).isFalse();
        // System packages are always allowed (even if not in the allowlist)
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();

        // Setting an empty allowlist - only system listeners allowed
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, emptyList())).isTrue();
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        permittedListener, MANAGED_PROFILE_USER_ID)).isFalse();
        assertThat(dpms.isNotificationListenerServicePermitted(
        notPermittedListener, MANAGED_PROFILE_USER_ID)).isFalse();
        // System packages are always allowed (even if not in the allowlist)
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();

        // Setting a null allowlist - all listeners allowed
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(admin1, null)).isTrue();
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        permittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        notPermittedListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
    }

    @Test
    public void testSetPermittedCrossProfileNotificationListeners_doesNotAffectPrimaryProfile()
            throws Exception {
        // Set up a managed profile
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;

        final String nonSystemPackage = "non.system.package";
        int appId = 12345;
        setupPackageInPackageManager(
                nonSystemPackage,
                UserHandle.USER_SYSTEM,  // We check the packageInfo from the primary user.
                appId, /*flags=*/ 0);

        final String systemListener = "system.package";
        setupPackageInPackageManager(
                systemListener,
                UserHandle.USER_SYSTEM,  // We check the packageInfo from the primary user.
                ++appId, ApplicationInfo.FLAG_SYSTEM);

        // By default all packages are allowed (for all profiles)
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        nonSystemPackage, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, UserHandle.USER_SYSTEM)).isTrue();

        // Setting an empty allowlist - only system listeners allowed in managed profile, but
        // all allowed in primary profile
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertThat(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, emptyList())).isTrue();
        assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpms.isNotificationListenerServicePermitted(
        nonSystemPackage, MANAGED_PROFILE_USER_ID)).isFalse();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, MANAGED_PROFILE_USER_ID)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpms.isNotificationListenerServicePermitted(
        systemListener, UserHandle.USER_SYSTEM)).isTrue();
    }

    @Test
    public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.applicationInfo = new ApplicationInfo();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setDeviceOwner();

        verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context);
    }

    @Test
    public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.applicationInfo = new ApplicationInfo();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);

        verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context);
        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, mAdmin1Context);
    }

    @Test
    public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.applicationInfo = new ApplicationInfo();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);

        var caller = new DpmMockContext(getServices(), mRealTestContext);
        caller.packageName = "com.example.delegate";
        caller.binder.callingUid = setupPackageInPackageManager(caller.packageName,
                CALLER_USER_HANDLE, 20988, ApplicationInfo.FLAG_HAS_CODE);

        // Make caller a delegated cert installer.
        runAsCaller(mAdmin1Context, dpms,
                dpm -> dpm.setCertInstallerPackage(admin1, caller.packageName));

        verifyCanGetOwnerInstalledCaCerts(null, caller);
        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller);
    }

    @Test
    public void testDisallowSharingIntoProfileSetRestriction() {
        when(mServiceContext.resources.getString(R.string.config_managed_provisioning_package))
                .thenReturn("com.android.managedprovisioning");
        when(getServices().userManagerInternal.getProfileParentId(anyInt()))
                .thenReturn(UserHandle.USER_SYSTEM);
        mServiceContext.binder.callingPid = DpmMockContext.SYSTEM_PID;
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        Bundle restriction = new Bundle();
        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);

        RestrictionsListener listener = new RestrictionsListener(
                mServiceContext, getServices().userManagerInternal, dpms);
        listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, restriction, new Bundle());

        verifyDataSharingAppliedBroadcast();
    }

    @Test
    public void testDisallowSharingIntoProfileClearRestriction() {
        when(mServiceContext.resources.getString(R.string.config_managed_provisioning_package))
                .thenReturn("com.android.managedprovisioning");
        when(getServices().userManagerInternal.getProfileParentId(anyInt()))
                .thenReturn(UserHandle.USER_SYSTEM);
        mServiceContext.binder.callingPid = DpmMockContext.SYSTEM_PID;
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        Bundle restriction = new Bundle();
        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);

        RestrictionsListener listener = new RestrictionsListener(
                mServiceContext, getServices().userManagerInternal, dpms);
        listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), restriction);

        verifyDataSharingAppliedBroadcast();
    }

    @Test
    public void testDisallowSharingIntoProfileUnchanged() {
        RestrictionsListener listener = new RestrictionsListener(
                mContext, getServices().userManagerInternal, dpms);
        listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), new Bundle());
        verify(mContext.spiedContext, never()).sendBroadcastAsUser(any(), any());
    }

    private void verifyDataSharingAppliedBroadcast() {
        Intent expectedIntent = new Intent(
                DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED);
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(expectedIntent),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE));
    }

    @Test
    public void testOverrideApnAPIsFailWithPO() throws Exception {
        when(getServices().packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))
                .thenReturn(true);
        // FEATURE_TELEPHONY is set in DPMS's constructor and therefore a new DPMS instance
        // is created after turning on the feature.
        initializeDpms();
        setupProfileOwner();
        ApnSetting apn = (new ApnSetting.Builder())
            .setApnName("test")
            .setEntryName("test")
            .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
            .build();
        assertExpectException(SecurityException.class, null, () ->
                dpm.addOverrideApn(admin1, apn));
        assertExpectException(SecurityException.class, null, () ->
                dpm.updateOverrideApn(admin1, 0, apn));
        assertExpectException(SecurityException.class, null, () ->
                dpm.removeOverrideApn(admin1, 0));
        assertExpectException(SecurityException.class, null, () ->
                dpm.getOverrideApns(admin1));
        assertExpectException(SecurityException.class, null, () ->
                dpm.setOverrideApnsEnabled(admin1, false));
        assertExpectException(SecurityException.class, null, () ->
                dpm.isOverrideApnEnabled(admin1));
    }

    private void verifyCanGetOwnerInstalledCaCerts(
            final ComponentName caller, final DpmMockContext callerContext) throws Exception {
        final String alias = "cert";
        final byte[] caCert = TEST_CA.getBytes();

        // device admin (used for posting the tls notification)
        DpmMockContext admin1Context = mAdmin1Context;
        if (admin1.getPackageName().equals(callerContext.getPackageName())) {
            admin1Context = callerContext;
        }
        when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

        // caller: device admin or delegated certificate installer
        callerContext.applicationInfo = new ApplicationInfo();
        final UserHandle callerUser = callerContext.binder.getCallingUserHandle();

        // system_server
        final DpmMockContext serviceContext = mContext;
        serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        getServices().addPackageContext(callerUser, admin1Context);
        getServices().addPackageContext(callerUser, callerContext);

        // Install a CA cert.
        runAsCaller(callerContext, dpms, (dpm) -> {
            when(getServices().keyChainConnection.getService().installCaCertificate(caCert))
                        .thenReturn(alias);
            assertThat(dpm.installCaCert(caller, caCert)).isTrue();
            when(getServices().keyChainConnection.getService().getUserCaAliases())
                    .thenReturn(asSlice(new String[] {alias}));
        });

        getServices().injectBroadcast(mServiceContext,
                new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                        .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                callerUser.getIdentifier());
        flushTasks(dpms);

        final List<String> ownerInstalledCaCerts = new ArrayList<>();

        // Device Owner / Profile Owner can find out which CA certs were installed by itself.
        runAsCaller(admin1Context, dpms, (dpm) -> {
            final List<String> installedCaCerts = dpm.getOwnerInstalledCaCerts(callerUser);
            assertThat(installedCaCerts).isEqualTo(Collections.singletonList(alias));
            ownerInstalledCaCerts.addAll(installedCaCerts);
        });

        // Restarting the DPMS should not lose information.
        initializeDpms();
        runAsCaller(admin1Context, dpms,
                (dpm) -> assertThat(dpm.getOwnerInstalledCaCerts(callerUser))
                        .isEqualTo(ownerInstalledCaCerts));

        // System can find out which CA certs were installed by the Device Owner / Profile Owner.
        runAsCaller(serviceContext, dpms, (dpm) -> {
            assertThat(dpm.getOwnerInstalledCaCerts(callerUser)).isEqualTo(ownerInstalledCaCerts);

            // Remove the CA cert.
            reset(getServices().keyChainConnection.getService());
        });

        getServices().injectBroadcast(mServiceContext,
                new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                        .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                callerUser.getIdentifier());
        flushTasks(dpms);

        // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile
        // Owner.
        runAsCaller(admin1Context, dpms, (dpm) -> {
            MoreAsserts.assertEmpty(dpm.getOwnerInstalledCaCerts(callerUser));
        });
    }

    private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(
            final ComponentName callerName, final DpmMockContext callerContext) throws Exception {
        final String alias = "cert";
        final byte[] caCert = TEST_CA.getBytes();

        // device admin (used for posting the tls notification)
        DpmMockContext admin1Context = mAdmin1Context;
        if (admin1.getPackageName().equals(callerContext.getPackageName())) {
            admin1Context = callerContext;
        }
        when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

        // caller: device admin or delegated certificate installer
        callerContext.applicationInfo = new ApplicationInfo();
        final UserHandle callerUser = callerContext.binder.getCallingUserHandle();

        // system_server
        final DpmMockContext serviceContext = mContext;
        serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        getServices().addPackageContext(callerUser, admin1Context);
        getServices().addPackageContext(callerUser, callerContext);

        // Install a CA cert as caller
        runAsCaller(callerContext, dpms, (dpm) -> {
            when(getServices().keyChainConnection.getService().installCaCertificate(caCert))
                    .thenReturn(alias);
            assertThat(dpm.installCaCert(callerName, caCert)).isTrue();
        });

        // Fake the CA cert as having been installed
        when(getServices().keyChainConnection.getService().getUserCaAliases())
                .thenReturn(asSlice(new String[] {alias}));
        getServices().injectBroadcast(mServiceContext,
                new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                        .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                callerUser.getIdentifier());
        flushTasks(dpms);

        // Removing the Profile Owner should clear the information on which CA certs were installed
        runAsCaller(admin1Context, dpms, dpm -> dpm.clearProfileOwner(admin1));

        runAsCaller(serviceContext, dpms, (dpm) -> {
            final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(callerUser);
            assertThat(ownerInstalledCaCerts).isNotNull();
            assertThat(ownerInstalledCaCerts.isEmpty()).isTrue();
        });
    }

    private void verifyRebootWipeUserData(boolean wipeEuicc) throws Exception {
        verify(getServices().recoverySystem).rebootWipeUserData(/*shutdown=*/ eq(false),
                /* reason= */ anyString(), /*force=*/ eq(true), eq(wipeEuicc),
                /* wipeAdoptableStorage= */ eq(false), /* wipeFactoryResetProtection= */ eq(false));
    }

    private void assertAttestationFlags(int attestationFlags, int[] expectedFlags) {
        int[] gotFlags = DevicePolicyManagerService.translateIdAttestationFlags(attestationFlags);
        Arrays.sort(gotFlags);
        Arrays.sort(expectedFlags);
        assertThat(Arrays.equals(expectedFlags, gotFlags)).isTrue();
    }

    @Test
    public void testTranslationOfIdAttestationFlag() {
        int[] allIdTypes = new int[]{ID_TYPE_SERIAL, ID_TYPE_IMEI, ID_TYPE_MEID};
        int[] correspondingAttUtilsTypes = new int[]{
            AttestationUtils.ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_IMEI,
            AttestationUtils.ID_TYPE_MEID};

        // Test translation of zero flags
        assertThat(DevicePolicyManagerService.translateIdAttestationFlags(0)).isNull();

        // Test translation of the ID_TYPE_BASE_INFO flag, which should yield an empty, but
        // non-null array
        assertAttestationFlags(ID_TYPE_BASE_INFO, new int[] {});

        // Test translation of a single flag
        assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_SERIAL,
                new int[] {AttestationUtils.ID_TYPE_SERIAL});
        assertAttestationFlags(ID_TYPE_SERIAL, new int[] {AttestationUtils.ID_TYPE_SERIAL});

        // Test translation of two flags
        assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI,
                new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL});
        assertAttestationFlags(ID_TYPE_BASE_INFO | ID_TYPE_MEID | ID_TYPE_SERIAL,
                new int[] {AttestationUtils.ID_TYPE_MEID, AttestationUtils.ID_TYPE_SERIAL});

        // Test translation of all three flags
        assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID,
                new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
                    AttestationUtils.ID_TYPE_MEID});
        // Test translation of all three flags
        assertAttestationFlags(ID_TYPE_SERIAL | ID_TYPE_IMEI | ID_TYPE_MEID | ID_TYPE_BASE_INFO,
                new int[] {AttestationUtils.ID_TYPE_IMEI, AttestationUtils.ID_TYPE_SERIAL,
                    AttestationUtils.ID_TYPE_MEID});
    }

    @Test
    public void testRevertDeviceOwnership_noMetadataFile() throws Exception {
        setDeviceOwner();
        initializeDpms();
        assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();
        assertThat(dpms.isDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
        assertThat(dpms.isAdminActive(admin1, UserHandle.USER_SYSTEM)).isTrue();
    }

    @FlakyTest(bugId = 148934649)
    @Test
    public void testRevertDeviceOwnership_adminAndDeviceMigrated() throws Exception {
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                getDeviceOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_migrated),
                getDeviceOwnerFile());
        assertDeviceOwnershipRevertedWithFakeTransferMetadata();
    }

    @FlakyTest(bugId = 148934649)
    @Test
    public void testRevertDeviceOwnership_deviceNotMigrated() throws Exception {
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                getDeviceOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_not_migrated),
                getDeviceOwnerFile());
        assertDeviceOwnershipRevertedWithFakeTransferMetadata();
    }

    @Test
    public void testRevertDeviceOwnership_adminAndDeviceNotMigrated() throws Exception {
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated),
                getDeviceOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_not_migrated),
                getDeviceOwnerFile());
        assertDeviceOwnershipRevertedWithFakeTransferMetadata();
    }

    @Test
    public void testRevertProfileOwnership_noMetadataFile() throws Exception {
        setupProfileOwner();
        initializeDpms();
        assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();
        assertThat(dpms.isProfileOwner(admin1, CALLER_USER_HANDLE)).isTrue();
        assertThat(dpms.isAdminActive(admin1, CALLER_USER_HANDLE)).isTrue();
    }

    @FlakyTest(bugId = 148934649)
    @Test
    public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception {
        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                getProfileOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_migrated),
                getProfileOwnerFile());
        assertProfileOwnershipRevertedWithFakeTransferMetadata();
    }

    @FlakyTest(bugId = 148934649)
    @Test
    public void testRevertProfileOwnership_profileNotMigrated() throws Exception {
        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                getProfileOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_not_migrated),
                getProfileOwnerFile());
        assertProfileOwnershipRevertedWithFakeTransferMetadata();
    }

    @Test
    public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception {
        getServices().addUser(CALLER_USER_HANDLE, 0,
                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated),
                getProfileOwnerPoliciesFile());
        DpmTestUtils.writeInputStreamToFile(
                getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_not_migrated),
                getProfileOwnerFile());
        assertProfileOwnershipRevertedWithFakeTransferMetadata();
    }

    @Test
    public void testGrantDeviceIdsAccess_notToProfileOwner() throws Exception {
        setupProfileOwner();
        configureContextForAccess(mContext, false);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin2, true));
    }

    @Test
    public void testGrantDeviceIdsAccess_notByAuthorizedCaller() throws Exception {
        setupProfileOwner();
        configureContextForAccess(mContext, false);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true));
    }

    @Test
    public void testGrantDeviceIdsAccess_byAuthorizedSystemCaller() throws Exception {
        setupProfileOwner();

        // This method will throw if the system context could not call
        // markProfileOwnerOfOrganizationOwnedDevice successfully.
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
    }

    private void configureContextForAccess(DpmMockContext context, boolean granted) {
        when(context.spiedContext.checkCallingPermission(
                permission.MARK_DEVICE_ORGANIZATION_OWNED))
                .thenReturn(granted ? PackageManager.PERMISSION_GRANTED
                        : PackageManager.PERMISSION_DENIED);

        when(getServices().userManager.getProfileParent(any()))
                .thenReturn(UserHandle.SYSTEM);
    }

    @Test
    public void testGrantDeviceIdsAccess_byAuthorizedManagedProvisioning() throws Exception {
        setupProfileOwner();

        final long ident = mServiceContext.binder.clearCallingIdentity();
        configureContextForAccess(mServiceContext, true);
        mServiceContext.permissions.add(permission.MARK_DEVICE_ORGANIZATION_OWNED);

        mServiceContext.binder.callingUid =
                UserHandle.getUid(CALLER_USER_HANDLE,
                        DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
        try {
            runAsCaller(mServiceContext, dpms, dpm -> {
                dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true);
            });
        } finally {
            mServiceContext.binder.restoreCallingIdentity(ident);
        }
    }

    @Test
    public void testHasDeviceIdAccessUnchecked_deviceOwnerCaller()
            throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        configureContextForAccess(mContext, false);

        // Device owner should be allowed to request Device ID attestation.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.CALLER_SYSTEM_USER_UID)).isTrue();

        // Another package must not be allowed to request Device ID attestation.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DpmMockContext.CALLER_SYSTEM_USER_UID)).isFalse();
    }

    @Test
    public void testHasDeviceIdAccessUnchecked_profileOwnerCaller()
            throws Exception {
        configureContextForAccess(mContext, false);

        // Make sure a security exception is thrown if the device has no profile owner.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.CALLER_UID)).isFalse();

        setupProfileOwner();
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        // The profile owner is allowed to request Device ID attestation.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.CALLER_UID)).isTrue();

        // But not another package.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DpmMockContext.CALLER_UID)).isFalse();

        // Or another component which is not the admin.
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.ANOTHER_UID)).isFalse();
    }

    public void runAsDelegatedCertInstaller(DpmRunnable action) throws Exception {
        final long ident = mServiceContext.binder.clearCallingIdentity();

        mServiceContext.binder.callingUid = UserHandle.getUid(CALLER_USER_HANDLE,
                DpmMockContext.DELEGATE_CERT_INSTALLER_UID);
        try {
            runAsCaller(mServiceContext, dpms, action);
        } finally {
            mServiceContext.binder.restoreCallingIdentity(ident);
        }
    }

    @Test
    public void testHasDeviceIdAccessUnchecked_delegateCaller() throws Exception {
        setupProfileOwner();
        markDelegatedCertInstallerAsInstalled();

        // Configure a delegated cert installer.
        runAsCaller(mServiceContext, dpms,
                dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
                        Arrays.asList(DELEGATION_CERT_INSTALL)));

        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        // Make sure that the profile owner can still request Device ID attestation.
        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.CALLER_UID)).isTrue();

        runAsDelegatedCertInstaller(dpm -> assertThat(
                dpms.hasDeviceIdAccessUnchecked(
                        DpmMockContext.DELEGATE_PACKAGE_NAME,
                        UserHandle.getUid(CALLER_USER_HANDLE,
                                DpmMockContext.DELEGATE_CERT_INSTALLER_UID))).isTrue());
    }

    @Test
    public void testHasDeviceIdAccessUnchecked_delegateCallerWithoutPermissions()
            throws Exception {
        setupProfileOwner();
        markDelegatedCertInstallerAsInstalled();

        // Configure a delegated cert installer.
        runAsCaller(mServiceContext, dpms,
                dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
                        Arrays.asList(DELEGATION_CERT_INSTALL)));

        assertThat(dpms.hasDeviceIdAccessUnchecked(
                admin1.getPackageName(),
                DpmMockContext.CALLER_UID)).isFalse();

        runAsDelegatedCertInstaller(dpm -> {
            assertThat(dpms.hasDeviceIdAccessUnchecked(
                    DpmMockContext.DELEGATE_PACKAGE_NAME,
                    DpmMockContext.CALLER_UID)).isFalse();
        });
    }

    @Test
    public void testGetPasswordComplexity_securityExceptionNotThrownForParentInstance() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
        setAsProfileOwner(admin1);

        parentDpm.getPasswordComplexity();

        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
    }

    @Test
    public void testGetPasswordComplexity_illegalStateExceptionIfLocked() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(false);
        assertThrows(IllegalStateException.class, () -> dpm.getPasswordComplexity());
    }

    @Test
    public void testGetPasswordComplexity_securityExceptionWithoutPermissions() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
        assertThrows(SecurityException.class, () -> dpm.getPasswordComplexity());
    }


    @Test
    public void testGetPasswordComplexity_currentUserNoPassword() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
        when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
                .thenReturn(CALLER_USER_HANDLE);

        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
    }

    @Test
    public void testGetPasswordComplexity_currentUserHasPassword() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
        when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
                .thenReturn(CALLER_USER_HANDLE);
        when(getServices().lockSettingsInternal
                .getUserPasswordMetrics(CALLER_USER_HANDLE))
                .thenReturn(metricsForPassword("asdf"));

        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
    }

    @Test
    public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() {
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
                new String[0]);
        when(getServices().userManager.isUserUnlocked(CALLER_USER_HANDLE)).thenReturn(true);
        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);

        UserInfo parentUser = new UserInfo();
        parentUser.id = CALLER_USER_HANDLE + 10;
        when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE))
                .thenReturn(parentUser.id);

        when(getServices().lockSettingsInternal
                .getUserPasswordMetrics(CALLER_USER_HANDLE))
                .thenReturn(metricsForPassword("asdf"));
        when(getServices().lockSettingsInternal
                .getUserPasswordMetrics(parentUser.id))
                .thenReturn(metricsForPassword("parentUser"));

        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
    }

    @Test
    public void testCrossProfileCalendarPackages_initiallyEmpty() {
        setAsProfileOwner(admin1);
        final Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
    }

    @Test
    public void testCrossProfileCalendarPackages_reopenDpms() {
        setAsProfileOwner(admin1);
        dpm.setCrossProfileCalendarPackages(admin1, null);
        Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertThat(packages == null).isTrue();
        initializeDpms();
        packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertThat(packages == null).isTrue();

        dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet());
        packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
        initializeDpms();
        packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());

        final String dummyPackageName = "test";
        final Set<String> testPackages = new ArraySet<String>(Arrays.asList(dummyPackageName));
        dpm.setCrossProfileCalendarPackages(admin1, testPackages);
        packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
        initializeDpms();
        packages = dpm.getCrossProfileCalendarPackages(admin1);
        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
    }

    private void assertCrossProfileCalendarPackagesEqual(Set<String> expected, Set<String> actual) {
        assertThat(expected).isNotNull();
        assertThat(actual).isNotNull();
        assertThat(actual).containsExactlyElementsIn(expected);
    }

    @Test
    public void testIsPackageAllowedToAccessCalendar_adminNotAllowed() {
        final String testPackage = "TEST_PACKAGE";
        setAsProfileOwner(admin1);
        dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet());
        when(getServices().settings.settingsSecureGetIntForUser(
                Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
                0, CALLER_USER_HANDLE)).thenReturn(1);
        mContext.permissions.add(permission.INTERACT_ACROSS_USERS);

        assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isFalse();
    }

    @Test
    public void testIsPackageAllowedToAccessCalendar_settingOff() {
        final String testPackage = "TEST_PACKAGE";
        setAsProfileOwner(admin1);
        dpm.setCrossProfileCalendarPackages(admin1, Collections.singleton(testPackage));
        when(getServices().settings.settingsSecureGetIntForUser(
                Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
                0, CALLER_USER_HANDLE)).thenReturn(0);
        mContext.permissions.add(permission.INTERACT_ACROSS_USERS);

        assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isFalse();
    }

    @Test
    public void testIsPackageAllowedToAccessCalendar_bothAllowed() {
        final String testPackage = "TEST_PACKAGE";
        getServices().addTestPackageUid(testPackage, DpmMockContext.ANOTHER_UID);
        setAsProfileOwner(admin1);
        dpm.setCrossProfileCalendarPackages(admin1, null);
        when(getServices().settings.settingsSecureGetIntForUser(
                Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
                0, CALLER_USER_HANDLE)).thenReturn(1);
        mContext.permissions.add(permission.INTERACT_ACROSS_USERS);

        assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isTrue();
    }

    @Test
    public void testIsPackageAllowedToAccessCalendar_requiresPermission() {
        final String testPackage = "TEST_PACKAGE";
        getServices().addTestPackageUid(testPackage, DpmMockContext.ANOTHER_UID);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.isPackageAllowedToAccessCalendar(testPackage));
    }

    @Test
    public void testIsPackageAllowedToAccessCalendar_samePackageAndSameUser_noPermissionRequired() {
        final String testPackage = "TEST_PACKAGE";
        setAsProfileOwner(admin1);
        dpm.setCrossProfileCalendarPackages(admin1, null);
        when(getServices().settings.settingsSecureGetIntForUser(
                Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED,
                0, CALLER_USER_HANDLE)).thenReturn(1);

        getServices().addTestPackageUid(testPackage, mContext.binder.callingUid);

        assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isTrue();
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserControlDisabledPackages_asDO() throws Exception {
        final List<String> testPackages = new ArrayList<>();
        testPackages.add("package_1");
        testPackages.add("package_2");
        mServiceContext.permissions.add(permission.MANAGE_DEVICE_ADMINS);
        setDeviceOwner();

        dpm.setUserControlDisabledPackages(admin1, testPackages);

        verify(getServices().packageManagerInternal)
                .setOwnerProtectedPackages(UserHandle.USER_ALL, testPackages);
        assertThat(dpm.getUserControlDisabledPackages(admin1)).isEqualTo(testPackages);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserControlDisabledPackages_asPO() {
        final List<String> testPackages = new ArrayList<>();
        testPackages.add("package_1");
        testPackages.add("package_2");
        mServiceContext.permissions.add(permission.MANAGE_DEVICE_ADMINS);
        setAsProfileOwner(admin1);

        dpm.setUserControlDisabledPackages(admin1, testPackages);

        verify(getServices().packageManagerInternal)
                .setOwnerProtectedPackages(CALLER_USER_HANDLE, testPackages);
        assertThat(dpm.getUserControlDisabledPackages(admin1)).isEqualTo(testPackages);
    }

    private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
        final long ident = mServiceContext.binder.clearCallingIdentity();
        mServiceContext.binder.callingUid = UserHandle.getUid(userId, DpmMockContext.SYSTEM_UID);

        configureContextForAccess(mServiceContext, true);
        runAsCaller(mServiceContext, dpms, dpm -> {
            dpm.setProfileOwnerOnOrganizationOwnedDevice(who, true);
        });
        mServiceContext.binder.restoreCallingIdentity(ident);
    }

    @Test
    public void testGetCrossProfilePackages_notSet_returnsEmpty() {
        setAsProfileOwner(admin1);
        assertThat(dpm.getCrossProfilePackages(admin1).isEmpty()).isTrue();
    }

    @Test
    public void testGetCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty() {
        setAsProfileOwner(admin1);

        initializeDpms();

        assertThat(dpm.getCrossProfilePackages(admin1).isEmpty()).isTrue();
    }

    @Test
    public void testGetCrossProfilePackages_whenSet_returnsEqual() {
        setAsProfileOwner(admin1);
        Set<String> packages = Collections.singleton("TEST_PACKAGE");

        dpm.setCrossProfilePackages(admin1, packages);

        assertThat(dpm.getCrossProfilePackages(admin1)).isEqualTo(packages);
    }

    @Test
    public void testGetCrossProfilePackages_whenSet_dpmsReinitialized_returnsEqual() {
        setAsProfileOwner(admin1);
        Set<String> packages = Collections.singleton("TEST_PACKAGE");

        dpm.setCrossProfilePackages(admin1, packages);
        initializeDpms();

        assertThat(dpm.getCrossProfilePackages(admin1)).isEqualTo(packages);
    }

    @Test
    public void testGetAllCrossProfilePackages_notSet_returnsEmpty() throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
        addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
        mContext.packageName = admin1.getPackageName();

        setCrossProfileAppsList();
        setVendorCrossProfileAppsList();

        assertThat(dpm.getAllCrossProfilePackages().isEmpty()).isTrue();
    }

    @Test
    public void testGetAllCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty()
            throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
        addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
        mContext.packageName = admin1.getPackageName();

        setCrossProfileAppsList();
        setVendorCrossProfileAppsList();
        initializeDpms();

        assertThat(dpm.getAllCrossProfilePackages().isEmpty()).isTrue();
    }

    @Test
    public void testGetAllCrossProfilePackages_whenSet_returnsCombinedSet() throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
        addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
        final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE");
        mContext.packageName = admin1.getPackageName();

        dpm.setCrossProfilePackages(admin1, packages);
        setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
        setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");

        assertThat(dpm.getAllCrossProfilePackages()).containsExactly(
                "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE",
                "TEST_VENDOR_DEFAULT_PACKAGE");
    }

    @Test
    public void testGetAllCrossProfilePackages_whenSet_dpmsReinitialized_returnsCombinedSet()
            throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
        addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
        final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE");
        mContext.packageName = admin1.getPackageName();

        dpm.setCrossProfilePackages(admin1, packages);
        setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
        setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");
        initializeDpms();

        assertThat(dpm.getAllCrossProfilePackages()).containsExactly(
                "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE",
                "TEST_VENDOR_DEFAULT_PACKAGE");
    }

    @Test
    public void testGetDefaultCrossProfilePackages_noPackagesSet_returnsEmpty() {
        setCrossProfileAppsList();
        setVendorCrossProfileAppsList();

        assertThat(dpm.getDefaultCrossProfilePackages()).isEmpty();
    }

    @Test
    public void testGetDefaultCrossProfilePackages_packagesSet_returnsCombinedSet() {
        setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
        setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");

        assertThat(dpm.getDefaultCrossProfilePackages()).containsExactly(
                "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", "TEST_VENDOR_DEFAULT_PACKAGE");
    }

    @Test
    public void testSetCommonCriteriaMode_asDeviceOwner() throws Exception {
        setDeviceOwner();

        assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isFalse();
        assertThat(dpm.isCommonCriteriaModeEnabled(null)).isFalse();

        dpm.setCommonCriteriaModeEnabled(admin1, true);

        assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isTrue();
        assertThat(dpm.isCommonCriteriaModeEnabled(null)).isTrue();
    }

    @Test
    public void testSetCommonCriteriaMode_asPoOfOrgOwnedDevice() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
        mContext.binder.callingUid = managedProfileAdminUid;

        assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isFalse();
        assertThat(dpm.isCommonCriteriaModeEnabled(null)).isFalse();

        dpm.setCommonCriteriaModeEnabled(admin1, true);

        assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isTrue();
        assertThat(dpm.isCommonCriteriaModeEnabled(null)).isTrue();
    }

    @Test
    public void testCanProfileOwnerResetPasswordWhenLocked_nonDirectBootAwarePo()
            throws Exception {
        setDeviceEncryptionPerUser();
        setupProfileOwner();
        setupPasswordResetToken();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertWithMessage("po is not direct boot aware")
                .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse();
    }

    @Test
    public void testCanProfileOwnerResetPasswordWhenLocked_noActiveToken() throws Exception {
        setDeviceEncryptionPerUser();
        setupProfileOwner();
        makeAdmin1DirectBootAware();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertWithMessage("po doesn't have an active password reset token")
                .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse();
    }

    @Test
    public void testCanProfileOwnerResetPasswordWhenLocked_nonFbeDevice() throws Exception {
        setupProfileOwner();
        makeAdmin1DirectBootAware();
        setupPasswordResetToken();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertWithMessage("device is not FBE")
                .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse();
    }

    @Test
    @Ignore("b/277916462")
    public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception {
        setDeviceEncryptionPerUser();
        setupProfileOwner();
        makeAdmin1DirectBootAware();
        setupPasswordResetToken();

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertWithMessage("direct boot aware po with active password reset token")
                .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isTrue();
    }

    private void setupPasswordResetToken() {
        final byte[] token = new byte[32];
        final long handle = 123456;

        when(getServices().lockPatternUtils
                .addEscrowToken(eq(token), eq(CALLER_USER_HANDLE),
                        nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);

        dpm.setResetPasswordToken(admin1, token);

        when(getServices().lockPatternUtils
                .isEscrowTokenActive(eq(handle), eq(CALLER_USER_HANDLE)))
                .thenReturn(true);

        assertWithMessage("failed to activate token").that(dpm.isResetPasswordTokenActive(admin1))
                .isTrue();
    }

    private void makeAdmin1DirectBootAware()
            throws PackageManager.NameNotFoundException, android.os.RemoteException {
        Mockito.reset(getServices().ipackageManager);

        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
                mRealTestContext.getPackageManager().getApplicationInfo(
                        admin1.getPackageName(),
                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
        ai.privateFlags = PRIVATE_FLAG_DIRECT_BOOT_AWARE;

        doReturn(ai).when(getServices().ipackageManager).getApplicationInfo(
                eq(admin1.getPackageName()),
                anyLong(),
                eq(CALLER_USER_HANDLE));
    }

    private void setDeviceEncryptionPerUser() {
        when(getServices().storageManager.isFileBasedEncryptionEnabled()).thenReturn(true);
    }

    private void setCrossProfileAppsList(String... packages) {
        when(mContext.getResources()
                .getStringArray(eq(R.array.cross_profile_apps)))
                .thenReturn(packages);
    }

    private void setVendorCrossProfileAppsList(String... packages) {
        when(mContext.getResources()
                .getStringArray(eq(R.array.vendor_cross_profile_apps)))
                .thenReturn(packages);
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
        setupProfileOwner();

        final String accountType = "com.example.account.type";
        int originalUid = mContext.binder.callingUid;
        dpm.setAccountManagementDisabled(admin1, accountType, true);
        assertThat(dpm.getAccountTypesWithManagementDisabled()).asList().containsExactly(
                accountType);
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();

        mContext.binder.callingUid = originalUid;
        dpm.setAccountManagementDisabled(admin1, accountType, false);
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
    }

    @Test
    @Ignore("b/277916462")
    public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
            throws Exception {
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);

        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);

        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;

        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);

        int originalUid = mContext.binder.callingUid;
        final String accountType = "com.example.account.type";
        dpm.getParentProfileInstance(admin1).setAccountManagementDisabled(admin1, accountType,
                true);
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).asList().containsExactly(
                accountType);
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).asList().containsExactly(
                accountType);

        mContext.binder.callingUid = originalUid;
        dpm.getParentProfileInstance(admin1).setAccountManagementDisabled(admin1, accountType,
                false);
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
    }

    /**
     * Tests the case when the user doesn't turn the profile on in time, verifies that the user is
     * warned with a notification and then the apps get suspended.
     */
    @Test
    @Ignore // Temp disabled - broken with flags
    public void testMaximumProfileTimeOff_profileOffTimeExceeded() throws Exception {
        prepareMocksForSetMaximumProfileTimeOff();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        // The profile is running, neither alarm nor notification should be posted.
        verify(getServices().alarmManager, never())
                .set(anyInt(), anyLong(), any(PendingIntent.class));
        verify(getServices().notificationManager, never())
                .notify(anyInt(), any(Notification.class));
        // Apps shouldn't be suspended.
        verifyZeroInteractions(getServices().ipackageManager);
        clearInvocations(getServices().alarmManager);

        setUserUnlocked(CALLER_USER_HANDLE, false);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);

        // Verify the alarm was scheduled for time when the warning should be shown.
        verify(getServices().alarmManager, times(1))
                .set(anyInt(), eq(PROFILE_OFF_WARNING_TIME), any());
        // But still no notification should be posted at this point.
        verify(getServices().notificationManager, never())
                .notify(anyInt(), any(Notification.class));
        // Apps shouldn't be suspended.
        verifyZeroInteractions(getServices().ipackageManager);
        clearInvocations(getServices().alarmManager);

        // Pretend the alarm went off.
        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);

        // Verify the alarm was scheduled for the actual deadline this time.
        verify(getServices().alarmManager, times(1)).set(anyInt(), eq(PROFILE_OFF_DEADLINE), any());
        // Now the user should see a warning notification.
        verify(getServices().notificationManager, times(1))
                .notifyAsUser(any(), anyInt(), any(), any());
        // Apps shouldn't be suspended yet.
        verifyZeroInteractions(getServices().ipackageManager);
        clearInvocations(getServices().alarmManager);
        clearInvocations(getServices().notificationManager);

        // Pretend the alarm went off.
        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);

        // Verify the alarm was not set.
        verifyZeroInteractions(getServices().alarmManager);
        // Now the user should see a notification about suspended apps.
        verify(getServices().notificationManager, times(1))
                .notifyAsUser(any(), anyInt(), any(), any());
        // Verify that the apps are suspended.
        verify(getServices().packageManagerInternal, times(1))
                .setPackagesSuspendedByAdmin(anyInt(), any(), eq(true));
    }

    /**
     * Tests the case when the user turns the profile back on long before the deadline (> 1 day).
     */
    @Test
    public void testMaximumProfileTimeOff_turnOnBeforeWarning() throws Exception {
        prepareMocksForSetMaximumProfileTimeOff();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        setUserUnlocked(CALLER_USER_HANDLE, false);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
        clearInvocations(getServices().alarmManager);
        setUserUnlocked(CALLER_USER_HANDLE, true);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);

        // Verify that the alarm got discharged.
        verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
    }

    /**
     * Tests the case when the user turns the profile back on after the warning notification.
     */
    @Test
    public void testMaximumProfileTimeOff_turnOnAfterWarning() throws Exception {
        prepareMocksForSetMaximumProfileTimeOff();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        setUserUnlocked(CALLER_USER_HANDLE, false);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);

        // Pretend the alarm went off.
        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);

        clearInvocations(getServices().alarmManager);
        clearInvocations(getServices().notificationManager);
        setUserUnlocked(CALLER_USER_HANDLE, true);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);

        // Verify that the alarm got discharged.
        verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
        // Verify that the notification is removed.
        verify(getServices().notificationManager, times(1))
                .cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
    }

    /**
     * Tests the case when the user turns the profile back on when the apps are already suspended.
     */
    @Test
    @Ignore("b/277916462")
    public void testMaximumProfileTimeOff_turnOnAfterDeadline() throws Exception {
        prepareMocksForSetMaximumProfileTimeOff();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        dpm.setManagedProfileMaximumTimeOff(admin1, PROFILE_OFF_TIMEOUT);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        setUserUnlocked(CALLER_USER_HANDLE, false);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);

        // Pretend the alarm went off after the deadline.
        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);

        clearInvocations(getServices().alarmManager);
        clearInvocations(getServices().notificationManager);
        clearInvocations(getServices().ipackageManager);

        // Pretend the user clicked on the "apps suspended" notification to turn the profile on.
        sendBroadcastWithUser(dpms, ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
        // Verify that the profile is turned on.
        verify(getServices().userManager, times(1))
                .requestQuietModeEnabled(eq(false), eq(UserHandle.of(CALLER_USER_HANDLE)));

        setUserUnlocked(CALLER_USER_HANDLE, true);
        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);

        // Verify that the notification is removed (at this point DPC should show it).
        verify(getServices().notificationManager, times(1))
                .cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
        // Verify that the apps are NOT unsuspeded.
        verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
                any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
        // Verify that DPC is invoked to check policy compliance.
        verify(mContext.spiedContext).startActivityAsUser(
                MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
                MockUtils.checkUserHandle(CALLER_USER_HANDLE));

        // Verify that correct suspension reason is reported to the DPC.
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        assertThat(dpm.getPersonalAppsSuspendedReasons(admin1))
                .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);

        // Verify that rolling time back doesn't change the status.
        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_START);
        assertThat(dpm.getPersonalAppsSuspendedReasons(admin1))
                .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
    }

    @Test
    public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnDO() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // DO must be able to set it.
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
        // But not on the parent DPM.
        assertExpectException(IllegalArgumentException.class, null,
                () -> parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
        // Another package must not be allowed to set password complexity.
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertExpectException(SecurityException.class, null,
                () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
    }

    @Test
    public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnPO() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();
        // PO must be able to set it.
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
        // And on the parent profile DPM instance.
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
        // Another package must not be allowed to set password complexity.
        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
        assertExpectException(SecurityException.class, null,
                () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
    }

    @Test
    public void testSetRequiredPasswordComplexity_validValuesOnly() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();

        // Cannot set value other than password_complexity none/low/medium/high
        assertExpectException(IllegalArgumentException.class, null, () ->
                dpm.setRequiredPasswordComplexity(-1));
        assertExpectException(IllegalArgumentException.class, null, () ->
                dpm.setRequiredPasswordComplexity(7));
        assertExpectException(IllegalArgumentException.class, null, () ->
                dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH + 1));

        final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
        for (int complexity : allowedModes) {
            // Ensure exception is not thrown.
            dpm.setRequiredPasswordComplexity(complexity);
        }
    }

    @Test
    public void testSetRequiredPasswordComplexity_setAndGet() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();

        final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
        for (int complexity : allowedModes) {
            dpm.setRequiredPasswordComplexity(complexity);
            assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(complexity);
        }
    }

    @Test
    public void testSetRequiredPasswordComplexityOnParent_setAndGet() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);

        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        mContext.binder.callingUid = managedProfileAdminUid;
        when(getServices().userManager.isManagedProfile()).thenReturn(true);

        final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
        for (int complexity : allowedModes) {
            dpm.getParentProfileInstance(admin1).setRequiredPasswordComplexity(complexity);
            assertThat(dpm.getParentProfileInstance(admin1).getRequiredPasswordComplexity())
                    .isEqualTo(complexity);
            assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
        }
    }

    @Test
    public void testSetRequiredPasswordComplexity_isSufficient() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        mContext.packageName = admin1.getPackageName();
        setupDeviceOwner();

        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
        when(getServices().packageManager.getPackagesForUid(
                DpmMockContext.CALLER_SYSTEM_USER_UID)).thenReturn(new String[0]);
        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);

        reset(mContext.spiedContext);
        PasswordMetrics passwordMetricsNoSymbols = metricsForPin("1234");
        setActivePasswordState(passwordMetricsNoSymbols);
        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();

        reset(mContext.spiedContext);
        passwordMetricsNoSymbols = metricsForPassword("84125312943a");
        setActivePasswordState(passwordMetricsNoSymbols);
        assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
        // using isActivePasswordSufficient
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void testSetRequiredPasswordComplexity_resetBySettingQuality() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();

        // Test that calling setPasswordQuality resets complexity to none.
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
        assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
    }

    @Test
    public void testSetRequiredPasswordComplexity_overridesQuality() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setupProfileOwner();

        // Test that calling setRequiredPasswordComplexity resets password quality.
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
        assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(
                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(
                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
    }

    @Test
    public void testSetRequiredPasswordComplexityFailsWithQualityOnParent() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);

        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);

        assertThrows(IllegalStateException.class,
                () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH));
    }

    @Test
    public void testSetQualityOnParentFailsWithComplexityOnProfile() throws Exception {
        assumeDeprecatedPasswordApisSupported();

        final int managedProfileUserId = CALLER_USER_HANDLE;
        final int managedProfileAdminUid =
                UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = managedProfileAdminUid;
        addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);

        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);

        assertThrows(IllegalStateException.class,
                () -> parentDpm.setPasswordQuality(admin1,
                        DevicePolicyManager.PASSWORD_QUALITY_COMPLEX));
    }

    @Test
    public void testSetDeviceOwnerType_throwsExceptionWhenCallerNotAuthorized() {
        assertThrows(SecurityException.class,
                () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
    }

    @Test
    public void testSetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
        mContext.binder.clearCallingIdentity();
        assertThrows(IllegalStateException.class,
                () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
    }

    @Test
    public void testSetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
        setDeviceOwner();

        assertThrows(IllegalStateException.class,
                () -> dpm.setDeviceOwnerType(admin2, DEVICE_OWNER_TYPE_FINANCED));
    }

    @Test
    public void testSetDeviceOwnerType_asDeviceOwner_toFinancedDevice() throws Exception {
        setDeviceOwner();

        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertThat(dpm.isFinancedDevice()).isTrue();
        initializeDpms();
        assertThat(dpm.isFinancedDevice()).isTrue();
    }

    @Test
    public void testSetDeviceOwnerType_asDeviceOwner_setDeviceOwnerTypeTwice_success()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT);

        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertThat(dpm.isFinancedDevice()).isTrue();
    }

    @Test
    public void testIsFinancedDevice_throwsExceptionWhenThereIsNoDeviceOwner() {
        assertThrows(SecurityException.class, () -> dpm.isFinancedDevice());
    }

    @Test
    public void testSetUserRestriction_financeDo_invalidRestrictions_restrictionNotSet()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        for (String restriction : UserRestrictionsUtils.USER_RESTRICTIONS) {
            if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(restriction)) {
                assertNoDeviceOwnerRestrictions();
                assertExpectException(SecurityException.class, /* messageRegex= */ null,
                        () -> dpm.addUserRestriction(admin1, restriction));

                verify(getServices().userManagerInternal, never())
                        .setDevicePolicyUserRestrictions(anyInt(), any(), any(), anyBoolean());
                DpmTestUtils.assertRestrictions(new Bundle(), dpm.getUserRestrictions(admin1));
            }
        }
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserRestriction_financeDo_validRestrictions_setsRestriction()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        for (String restriction : UserRestrictionsUtils.USER_RESTRICTIONS) {
            if (UserRestrictionsUtils.canFinancedDeviceOwnerChange(restriction)) {
                assertNoDeviceOwnerRestrictions();
                dpm.addUserRestriction(admin1, restriction);

                Bundle globalRestrictions =
                        dpms.getDeviceOwnerAdminLocked().getGlobalUserRestrictions(
                                UserManagerInternal.OWNER_TYPE_DEVICE_OWNER);
                RestrictionsSet localRestrictions = new RestrictionsSet();
                localRestrictions.updateRestrictions(
                        UserHandle.USER_SYSTEM,
                        dpms.getDeviceOwnerAdminLocked().getLocalUserRestrictions(
                                UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
                verify(getServices().userManagerInternal)
                        .setDevicePolicyUserRestrictions(eq(UserHandle.USER_SYSTEM),
                                MockUtils.checkUserRestrictions(globalRestrictions),
                                MockUtils.checkUserRestrictions(
                                        UserHandle.USER_SYSTEM, localRestrictions),
                                eq(true));
                reset(getServices().userManagerInternal);

                DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(restriction),
                        dpm.getUserRestrictions(admin1));

                dpm.clearUserRestriction(admin1, restriction);
                reset(getServices().userManagerInternal);
            }
        }
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testSetLockTaskFeatures_financeDo_validLockTaskFeatures_lockTaskFeaturesSet()
            throws Exception {
        int validLockTaskFeatures = LOCK_TASK_FEATURE_SYSTEM_INFO | LOCK_TASK_FEATURE_KEYGUARD
                | LOCK_TASK_FEATURE_HOME | LOCK_TASK_FEATURE_GLOBAL_ACTIONS
                | LOCK_TASK_FEATURE_NOTIFICATIONS | LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK;
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setLockTaskFeatures(admin1, validLockTaskFeatures);

        verify(getServices().iactivityTaskManager)
                .updateLockTaskFeatures(eq(UserHandle.USER_SYSTEM), eq(validLockTaskFeatures));
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testSetLockTaskFeatures_financeDo_invalidLockTaskFeatures_throwsException()
            throws Exception {
        int invalidLockTaskFeatures = LOCK_TASK_FEATURE_NONE | LOCK_TASK_FEATURE_OVERVIEW
                | LOCK_TASK_FEATURE_HOME;
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
        // Called during setup.
        verify(getServices().iactivityTaskManager).updateLockTaskFeatures(anyInt(), anyInt());

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setLockTaskFeatures(admin1, invalidLockTaskFeatures));

        verifyNoMoreInteractions(getServices().iactivityTaskManager);
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testIsUninstallBlocked_financeDo_success() throws Exception {
        String packageName = "com.android.foo.package";
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
        when(getServices().ipackageManager.getBlockUninstallForUser(
                eq(packageName), eq(UserHandle.getCallingUserId())))
                .thenReturn(true);

        assertThat(dpm.isUninstallBlocked(admin1, packageName)).isTrue();
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUninstallBlocked_financeDo_success() throws Exception {
        String packageName = "com.android.foo.package";
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setUninstallBlocked(admin1, packageName, false);

        verify(getServices().ipackageManager)
                .setBlockUninstallForUser(eq(packageName), eq(false),
                        eq(UserHandle.USER_SYSTEM));
    }

    @Test
    @Ignore("b/277916462")
    public void testSetUserControlDisabledPackages_financeDo_success() throws Exception {
        List<String> packages = new ArrayList<>();
        packages.add("com.android.foo.package");
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setUserControlDisabledPackages(admin1, packages);

        verify(getServices().packageManagerInternal)
                .setOwnerProtectedPackages(eq(UserHandle.USER_ALL), eq(packages));
    }

    @Test
    public void testGetUserControlDisabledPackages_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertThat(dpm.getUserControlDisabledPackages(admin1)).isEmpty();
    }

    @Test
    public void testSetOrganizationName_financeDo_success() throws Exception {
        String organizationName = "Test Organization";
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setOrganizationName(admin1, organizationName);

        assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo(organizationName);
    }

    @Test
    public void testSetShortSupportMessage_financeDo_success() throws Exception {
        String supportMessage = "Test short support message";
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setShortSupportMessage(admin1, supportMessage);

        assertThat(dpm.getShortSupportMessage(admin1)).isEqualTo(supportMessage);
    }

    @Test
    public void testIsBackupServiceEnabled_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
        when(getServices().ibackupManager.isBackupServiceActive(eq(UserHandle.USER_SYSTEM)))
                .thenReturn(true);

        assertThat(dpm.isBackupServiceEnabled(admin1)).isTrue();
    }

    @Test
    public void testSetBackupServiceEnabled_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setBackupServiceEnabled(admin1, true);

        verify(getServices().ibackupManager)
                .setBackupServiceActive(eq(UserHandle.USER_SYSTEM), eq(true));
    }

    @Test
    public void testIsLockTaskPermitted_financeDo_success() throws Exception {
        String packageName = "com.android.foo.package";
        mockPolicyExemptApps(packageName);
        mockVendorPolicyExemptApps();
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertThat(dpm.isLockTaskPermitted(packageName)).isTrue();
    }

    @Test
    @FlakyTest(bugId = 260145949)
    public void testSetLockTaskPackages_financeDo_success() throws Exception {
        String[] packages = {"com.android.foo.package"};
        mockEmptyPolicyExemptApps();
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.setLockTaskPackages(admin1, packages);

        verify(getServices().iactivityManager)
                .updateLockTaskPackages(eq(UserHandle.USER_SYSTEM), eq(packages));
    }

    @Test
    @Ignore("b/277916462")
    public void testAddPersistentPreferredActivity_financeDo_success() throws Exception {
        IntentFilter filter = new IntentFilter();
        ComponentName target = new ComponentName(admin2.getPackageName(), "test.class");
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.addPersistentPreferredActivity(admin1, filter, target);

        verify(getServices().ipackageManager)
                .addPersistentPreferredActivity(eq(filter), eq(target), eq(UserHandle.USER_SYSTEM));
        verify(getServices().ipackageManager)
                .flushPackageRestrictionsAsUser(eq(UserHandle.USER_SYSTEM));
    }

    @Test
    @Ignore("b/277916462")
    public void testClearPackagePersistentPreferredActvities_financeDo_success() throws Exception {
        String packageName = admin2.getPackageName();
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.clearPackagePersistentPreferredActivities(admin1, packageName);

        verify(getServices().ipackageManager)
                .clearPackagePersistentPreferredActivities(
                        eq(packageName), eq(UserHandle.USER_SYSTEM));
        verify(getServices().ipackageManager)
                .flushPackageRestrictionsAsUser(eq(UserHandle.USER_SYSTEM));
    }

    @Test
    public void testWipeDevice_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
        when(getServices().userManager.getUserRestrictionSource(
                UserManager.DISALLOW_FACTORY_RESET,
                UserHandle.SYSTEM))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
        when(mMockContext.getResources()
                .getString(R.string.work_profile_deleted_description_dpm_wipe))
                .thenReturn("Test string");

        dpm.wipeDevice(0);

        verifyRebootWipeUserData(/* wipeEuicc= */ false);
    }

    @Test
    public void testIsDeviceOwnerApp_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
    }

    @Test
    public void testClearDeviceOwnerApp_financeDo_success() throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        dpm.clearDeviceOwnerApp(admin1.getPackageName());

        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isNull();
        assertThat(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM)).isFalse();
        verify(mMockContext.spiedContext, times(2))
                .sendBroadcastAsUser(
                        MockUtils.checkIntentAction(
                                DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                        eq(UserHandle.SYSTEM));
    }

    @Test
    public void testSetPermissionGrantState_financeDo_notReadPhoneStatePermission_throwsException()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setPermissionGrantState(admin1, admin1.getPackageName(),
                        permission.READ_CALENDAR,
                        DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED));
    }

    @Test
    public void testSetPermissionGrantState_financeDo_grantPermissionToNonDeviceOwnerPackage_throwsException()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setPermissionGrantState(admin1, "com.android.foo.package",
                        permission.READ_PHONE_STATE,
                        DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED));
    }

    @Test
    public void testGetPermissionGrantState_financeDo_notReadPhoneStatePermission_throwsException()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.getPermissionGrantState(admin1, admin1.getPackageName(),
                        permission.READ_CALENDAR));
    }

    @Test
    public void testGetPermissionGrantState_financeDo_notDeviceOwnerPackage_throwsException()
            throws Exception {
        setDeviceOwner();
        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);

        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.getPermissionGrantState(admin1, "com.android.foo.package",
                        permission.READ_PHONE_STATE));
    }

    @Test
    public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() {
        assertThrows(SecurityException.class,
                () -> dpm.setUsbDataSignalingEnabled(true));
    }

    @Test
    public void testSetUsbDataSignalingEnabled_asDeviceOwner() throws Exception {
        setDeviceOwner();
        when(getServices().usbManager.enableUsbDataSignal(false)).thenReturn(true);
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_3);

        assertThat(dpm.isUsbDataSignalingEnabled()).isTrue();

        dpm.setUsbDataSignalingEnabled(false);

        assertThat(dpm.isUsbDataSignalingEnabled()).isFalse();
    }

    @Test
    public void testIsUsbDataSignalingEnabledForUser() throws Exception {
        when(getServices().usbManager.enableUsbDataSignal(false)).thenReturn(true);
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_3);
        setDeviceOwner();
        dpm.setUsbDataSignalingEnabled(false);

        assertThat(dpm.isUsbDataSignalingEnabled()).isFalse();
    }

    @Test
    public void testSetUsbDataSignalingEnabled_asPoOfOrgOwnedDevice() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
        mContext.binder.callingUid = managedProfileAdminUid;
        when(getServices().usbManager.enableUsbDataSignal(false)).thenReturn(true);
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_3);

        assertThat(dpm.isUsbDataSignalingEnabled()).isTrue();

        dpm.setUsbDataSignalingEnabled(false);

        assertThat(dpm.isUsbDataSignalingEnabled()).isFalse();
    }

    @Test
    public void testCanUsbDataSignalingBeDisabled_canBeDisabled() throws Exception {
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_3);

        assertThat(dpm.canUsbDataSignalingBeDisabled()).isTrue();
    }

    @Test
    public void testCanUsbDataSignalingBeDisabled_cannotBeDisabled() throws Exception {
        setDeviceOwner();
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_2);

        assertThat(dpm.canUsbDataSignalingBeDisabled()).isFalse();
        assertThrows(IllegalStateException.class,
                () -> dpm.setUsbDataSignalingEnabled(true));
    }

    @Test
    public void testSetUsbDataSignalingEnabled_noChangeToActiveAdmin()
            throws Exception {
        setDeviceOwner();
        when(getServices().usbManager.getUsbHalVersion()).thenReturn(UsbManager.USB_HAL_V1_3);
        boolean enabled = dpm.isUsbDataSignalingEnabled();

        dpm.setUsbDataSignalingEnabled(true);

        assertThat(dpm.isUsbDataSignalingEnabled()).isEqualTo(enabled);
    }

    @Test
    public void testGetPolicyExemptApps_noPermission() {
        assertThrows(SecurityException.class, () -> dpm.getPolicyExemptApps());
    }

    @Test
    public void testGetPolicyExemptApps_empty() {
        grantManageDeviceAdmins();
        mockPolicyExemptApps();
        mockVendorPolicyExemptApps();

        assertThat(dpm.getPolicyExemptApps()).isEmpty();
    }

    @Test
    public void testGetPolicyExemptApps_baseOnly() {
        grantManageDeviceAdmins();
        mockPolicyExemptApps("foo");
        mockVendorPolicyExemptApps();

        assertThat(dpm.getPolicyExemptApps()).containsExactly("foo");
    }

    @Test
    public void testGetPolicyExemptApps_vendorOnly() {
        grantManageDeviceAdmins();
        mockPolicyExemptApps();
        mockVendorPolicyExemptApps("bar");

        assertThat(dpm.getPolicyExemptApps()).containsExactly("bar");
    }

    @Test
    public void testGetPolicyExemptApps_baseAndVendor() {
        grantManageDeviceAdmins();
        mockPolicyExemptApps("4", "23", "15", "42", "8");
        mockVendorPolicyExemptApps("16", "15", "4");

        assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42");
    }

    @Test
    public void testSetGlobalPrivateDnsModeOpportunistic_asDeviceOwner() throws Exception {
        setDeviceOwner();
        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
        // feature is disabled because there are non-affiliated secondary users.
        getServices().removeUser(CALLER_USER_HANDLE);
        clearInvocations(getServices().settings);

        int result = dpm.setGlobalPrivateDnsModeOpportunistic(admin1);

        assertThat(result).isEqualTo(PRIVATE_DNS_SET_NO_ERROR);
    }

    @Test
    public void testSetGlobalPrivateDnsModeOpportunistic_hasUnaffiliatedUsers() throws Exception {
        setDeviceOwner();
        setAsProfileOwner(admin2);

        assertThrows(SecurityException.class,
                () -> dpm.setGlobalPrivateDnsModeOpportunistic(admin1));
    }

    @Test
    public void testSetRecommendedGlobalProxy_asDeviceOwner() throws Exception {
        setDeviceOwner();
        // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
        // feature is disabled because there are non-affiliated secondary users.
        getServices().removeUser(CALLER_USER_HANDLE);

        dpm.setRecommendedGlobalProxy(admin1, null);

        verify(getServices().connectivityManager).setGlobalProxy(null);
    }

    @Test
    public void testSetRecommendedGlobalProxy_hasUnaffiliatedUsers() throws Exception {
        setDeviceOwner();
        setAsProfileOwner(admin2);

        assertThrows(SecurityException.class, () -> dpm.setRecommendedGlobalProxy(admin1, null));
    }

    @Test
    public void testSetAlwaysOnVpnPackage_clearsAdminVpn() throws Exception {
        setDeviceOwner();

        when(getServices().vpnManager
                .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
                .thenReturn(true);

        // Set VPN package to admin package.
        dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null);

        verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
                UserHandle.USER_SYSTEM, admin1.getPackageName(), false, null);

        // Clear VPN package.
        dpm.setAlwaysOnVpnPackage(admin1, null, false, null);

        // Change should be propagated to VpnManager
        verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
                UserHandle.USER_SYSTEM, null, false, null);
        // The package should lose authorization to start VPN.
        verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN,
                DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT);
    }

    @Test
    public void testSetAlwaysOnVpnPackage_doesntKillUserVpn() throws Exception {
        setDeviceOwner();

        when(getServices().vpnManager
                .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
                .thenReturn(true);

        // this time it shouldn't go into VpnManager anymore.
        dpm.setAlwaysOnVpnPackage(admin1, null, false, null);

        verifyNoMoreInteractions(getServices().vpnManager);
        verifyNoMoreInteractions(getServices().appOpsManager);
    }

    @Test
    public void testDisallowConfigVpn_clearsUserVpn() throws Exception {
        final String userVpnPackage = "org.some.vpn.servcie";
        final int userVpnUid = 20374;

        setDeviceOwner();

        setupVpnAuthorization(userVpnPackage, userVpnUid);

        simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN);

        verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser(
                UserHandle.USER_SYSTEM, null, false, null);
        verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN,
                userVpnUid, userVpnPackage, MODE_DEFAULT);
    }

    @Test
    public void testDisallowConfigVpn_doesntKillAdminVpn() throws Exception {
        setDeviceOwner();

        when(getServices().vpnManager
                .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any()))
                .thenReturn(true);

        // Set VPN package to admin package.
        dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null);
        setupVpnAuthorization(admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID);
        clearInvocations(getServices().vpnManager);

        simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN);

        // Admin-set package should remain always-on and should retain its authorization.
        verifyNoMoreInteractions(getServices().vpnManager);
        verify(getServices().appOpsManager, never()).setMode(OP_ACTIVATE_VPN,
                DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT);
    }

    @Test
    public void testGetOrganizationNameForUser_calledByNonPrivilegedApp_throwsException() {
        assertExpectException(SecurityException.class, "Calling identity is not authorized",
                () -> dpm.getOrganizationNameForUser(UserHandle.USER_SYSTEM));
    }

    @Test
    public void testSetWifiMinimumSecurity_noDeviceOwnerOrPoOfOrgOwnedDevice() {
        assertThrows(SecurityException.class, () -> dpm.setMinimumRequiredWifiSecurityLevel(
                DevicePolicyManager.WIFI_SECURITY_PERSONAL));
    }

    @Test
    public void testSetWifiMinimumSecurity_asDeviceOwner() throws Exception {
        setDeviceOwner();

        final Set<Integer> allowedLevels = Set.of(WIFI_SECURITY_OPEN, WIFI_SECURITY_PERSONAL,
                WIFI_SECURITY_ENTERPRISE_EAP, WIFI_SECURITY_ENTERPRISE_192);
        for (int level : allowedLevels) {
            dpm.setMinimumRequiredWifiSecurityLevel(level);
            assertThat(dpm.getMinimumRequiredWifiSecurityLevel()).isEqualTo(level);
        }
    }

    @Test
    public void testSetWifiMinimumSecurity_asPoOfOrgOwnedDevice() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
        mContext.binder.callingUid = managedProfileAdminUid;

        final Set<Integer> allowedLevels = Set.of(WIFI_SECURITY_OPEN, WIFI_SECURITY_PERSONAL,
                WIFI_SECURITY_ENTERPRISE_EAP, WIFI_SECURITY_ENTERPRISE_192);
        for (int level : allowedLevels) {
            dpm.setMinimumRequiredWifiSecurityLevel(level);
            assertThat(dpm.getMinimumRequiredWifiSecurityLevel()).isEqualTo(level);
        }
    }

    @Test
    public void testSetSsidAllowlist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
        assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
    }

    @Test
    public void testSetSsidAllowlist_asDeviceOwner() throws Exception {
        setDeviceOwner();

        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
        dpm.setWifiSsidPolicy(policy);
        assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
        assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST);
    }

    @Test
    public void testSetSsidAllowlist_asPoOfOrgOwnedDevice() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
        mContext.binder.callingUid = managedProfileAdminUid;

        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
        dpm.setWifiSsidPolicy(policy);
        assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
        assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST);
    }

    @Test
    public void testSetSsidAllowlist_emptyList() throws Exception {
        setDeviceOwner();

        final Set<WifiSsid> ssids = new ArraySet<>();
        assertThrows(IllegalArgumentException.class,
                () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids));
    }

    @Test
    public void testSetSsidDenylist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
        assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
    }

    @Test
    public void testSetSsidDenylist_asDeviceOwner() throws Exception {
        setDeviceOwner();

        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
        dpm.setWifiSsidPolicy(policy);
        assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
        assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST);
    }

    @Test
    public void testSetSsidDenylist_asPoOfOrgOwnedDevice() throws Exception {
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfile(admin1, managedProfileAdminUid, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
        mContext.binder.callingUid = managedProfileAdminUid;

        final Set<WifiSsid> ssids = new ArraySet<>(
                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
        WifiSsidPolicy policy = new WifiSsidPolicy(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
        dpm.setWifiSsidPolicy(policy);
        assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
        assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST);
    }

    @Test
    public void testSetSsidDenylist_emptyList() throws Exception {
        setDeviceOwner();

        final Set<WifiSsid> ssids = new ArraySet<>();
        assertThrows(IllegalArgumentException.class,
                () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids));
    }

    @Test
    public void testSendLostModeLocationUpdate_noPermission() {
        assertThrows(SecurityException.class, () -> dpm.sendLostModeLocationUpdate(
                getServices().executor, /* empty callback */ result -> {}));
    }

    @Test
    public void testSendLostModeLocationUpdate_notOrganizationOwnedDevice() {
        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
        assertThrows(IllegalStateException.class, () -> dpm.sendLostModeLocationUpdate(
                getServices().executor, /* empty callback */ result -> {}));
    }

    @Test
    public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception {
        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
        setDeviceOwner();
        when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true);

        dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});

        verify(getServices().locationManager, times(1)).getCurrentLocation(
                eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
    }

    @Test
    public void testSendLostModeLocationUpdate_asProfileOwnerOfOrgOwnedDevice() throws Exception {
        final int MANAGED_PROFILE_ADMIN_UID =
                UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
        when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true);

        dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});

        verify(getServices().locationManager, times(1)).getCurrentLocation(
                eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
    }

    @Test
    public void testSendLostModeLocationUpdate_noProviderIsEnabled() throws Exception {
        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
        setDeviceOwner();
        when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(false);
        when(getServices().locationManager.isProviderEnabled(NETWORK_PROVIDER)).thenReturn(false);
        when(getServices().locationManager.isProviderEnabled(GPS_PROVIDER)).thenReturn(false);

        dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {});

        verify(getServices().locationManager, never()).getCurrentLocation(
                eq(FUSED_PROVIDER), any(), eq(getServices().executor), any());
    }

    /**
     * Verifies that bundles with tons of moderately long strings are persisted correctly.
     *
     * Policy is serialized into binary XML and there is a limit on the max string length: 65535.
     * This test ensures that as long as each string in the trust agent configuration is below this
     * limit, the policy can be serialized and deserialized correctly, even when the total length
     * of the configuration is above that limit. This should be the case because PersistableBundle
     * contents are stored as XML subtrees rather than as strings.
     */
    @Test
    public void testSetTrustAgentConfiguration_largeBundlePersisted() {
        setAsProfileOwner(admin1);

        ComponentName agent = new ComponentName("some.trust.agent", "some.trust.agent.Agent");
        PersistableBundle configIn = new PersistableBundle();
        String kilobyteString = new String(new char[1024]).replace('\0', 'A');
        for (int i = 0; i < 1024; i++) {
            configIn.putString("key-" + i, kilobyteString);
        }

        runAsCaller(mAdmin1Context, dpms, dpm -> {
            dpm.setTrustAgentConfiguration(admin1, agent, configIn);
        });

        // Re-read policies to see if they were serialized/deserialized correctly.
        initializeDpms();

        List<PersistableBundle> configsOut = new ArrayList<>();
        runAsCaller(mAdmin1Context, dpms, dpm -> {
            configsOut.addAll(dpm.getTrustAgentConfiguration(admin1, agent));
        });

        assertThat(configsOut.size()).isEqualTo(1);
        PersistableBundle configOut = configsOut.get(0);
        assertThat(configOut.size()).isEqualTo(1024);
        for (int i = 0; i < 1024; i++) {
            assertThat(configOut.getString("key-" + i, null)).isEqualTo(kilobyteString);
        }
    }

    private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {
        final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage,
                userVpnUid, List.of(new AppOpsManager.OpEntry(
                OP_ACTIVATE_VPN, MODE_ALLOWED, Collections.emptyMap())));
        when(getServices().appOpsManager.getPackagesForOps(any(int[].class)))
                .thenReturn(List.of(vpnOp));
    }

    private void simulateRestrictionAdded(String restriction) {
        RestrictionsListener listener = new RestrictionsListener(
                mServiceContext, getServices().userManagerInternal, dpms);

        final Bundle newRestrictions = new Bundle();
        newRestrictions.putBoolean(restriction, true);
        listener.onUserRestrictionsChanged(UserHandle.USER_SYSTEM, newRestrictions, new Bundle());
    }

    private void setUserUnlocked(int userHandle, boolean unlocked) {
        when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
        when(getServices().userManagerInternal.isUserUnlockingOrUnlocked(eq(userHandle)))
                .thenReturn(unlocked);
    }

    private void prepareMocksForSetMaximumProfileTimeOff() throws Exception {
        addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);

        when(getServices().userManager.isUserUnlocked()).thenReturn(true);

        doReturn(Collections.singletonList(new ResolveInfo()))
                .when(getServices().packageManager).queryIntentActivitiesAsUser(
                        any(Intent.class), anyInt(), eq(CALLER_USER_HANDLE));

        dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_START);
        // To allow creation of Notification via Notification.Builder
        mContext.applicationInfo = mRealTestContext.getApplicationInfo();

        // Make locale available for date formatting:
        when(mServiceContext.resources.getConfiguration())
                .thenReturn(mRealTestContext.getResources().getConfiguration());

        clearInvocations(getServices().ipackageManager);
    }

    private static Matcher<Notification> hasExtra(String... extras) {
        assertWithMessage("Odd number of extra key-values").that(extras.length % 2).isEqualTo(0);
        return new BaseMatcher<Notification>() {
            @Override
            public boolean matches(Object item) {
                final Notification notification = (Notification) item;
                for (int i = 0; i < extras.length / 2; i++) {
                    if (!extras[i * 2 + 1].equals(notification.extras.getString(extras[i * 2]))) {
                        return false;
                    }
                }
                return true;
            }
            @Override
            public void describeTo(Description description) {
                description.appendText("Notification{");
                for (int i = 0; i < extras.length / 2; i++) {
                    if (i > 0) {
                        description.appendText(",");
                    }
                    description.appendText(extras[i * 2] + "=\"" + extras[i * 2 + 1] + "\"");
                }
                description.appendText("}");
            }
        };
    }

    // admin1 is the outgoing DPC, adminAnotherPackage is the incoming one.
    private void assertDeviceOwnershipRevertedWithFakeTransferMetadata() throws Exception {
        writeFakeTransferMetadataFile(UserHandle.USER_SYSTEM,
                TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER);

        final long ident = mServiceContext.binder.clearCallingIdentity();
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
        setUpPackageManagerForFakeAdmin(adminAnotherPackage,
                DpmMockContext.CALLER_SYSTEM_USER_UID, admin1);
        // To simulate a reboot, we just reinitialize dpms and call systemReady
        initializeDpms();

        assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue();
        assertThat(dpm.isDeviceOwnerApp(adminAnotherPackage.getPackageName())).isFalse();
        assertThat(dpm.isAdminActive(adminAnotherPackage)).isFalse();
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue();
        assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);

        assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue();
        assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
        assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
        assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();

        mServiceContext.binder.restoreCallingIdentity(ident);
    }

    // admin1 is the outgoing DPC, adminAnotherPackage is the incoming one.
    private void assertProfileOwnershipRevertedWithFakeTransferMetadata() throws Exception {
        writeFakeTransferMetadataFile(CALLER_USER_HANDLE,
                TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER);

        int uid = UserHandle.getUid(CALLER_USER_HANDLE,
                DpmMockContext.CALLER_SYSTEM_USER_UID);
        setUpPackageManagerForAdmin(admin1, uid);
        setUpPackageManagerForFakeAdmin(adminAnotherPackage, uid, admin1);
        // To simulate a reboot, we just reinitialize dpms and call systemReady
        initializeDpms();

        assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isTrue();
        assertThat(dpm.isAdminActive(admin1)).isTrue();
        assertThat(dpm.isProfileOwnerApp(adminAnotherPackage.getPackageName())).isFalse();
        assertThat(dpm.isAdminActive(adminAnotherPackage)).isFalse();
        assertThat(admin1).isEqualTo(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE));
        assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();
    }

    private void writeFakeTransferMetadataFile(int callerUserHandle, String adminType) {
        TransferOwnershipMetadataManager metadataManager = getMockTransferMetadataManager();
        metadataManager.deleteMetadataFile();

        final TransferOwnershipMetadataManager.Metadata metadata =
                new TransferOwnershipMetadataManager.Metadata(
                        admin1.flattenToString(), adminAnotherPackage.flattenToString(),
                        callerUserHandle,
                        adminType);
        metadataManager.saveMetadataFile(metadata);
    }

    private File getDeviceOwnerFile() {
        return dpms.mOwners.getDeviceOwnerFile();
    }

    private File getProfileOwnerFile() {
        return dpms.mOwners.getProfileOwnerFile(CALLER_USER_HANDLE);
    }

    private File getProfileOwnerPoliciesFile() {
        File parentDir = getServices().pathProvider.getUserSystemDirectory(CALLER_USER_HANDLE);
        return getPoliciesFile(parentDir);
    }

    private File getDeviceOwnerPoliciesFile() {
        return getPoliciesFile(getServices().systemUserDataDir);
    }

    private File getPoliciesFile(File parentDir) {
        return new File(parentDir, "device_policies.xml");
    }

    private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
        when(getServices().settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
        dpms.notifyChangeToContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
    }

    private void assertProvisioningAllowed(String action, boolean expected) {
        assertWithMessage("isProvisioningAllowed(%s) returning unexpected result", action)
                .that(dpm.isProvisioningAllowed(action)).isEqualTo(expected);
    }

    private void assertProvisioningAllowed(String action, boolean expected, String packageName,
            int uid) {
        final String previousPackageName = mContext.packageName;
        final int previousUid = mMockContext.binder.callingUid;

        // Call assertProvisioningAllowed with the packageName / uid passed as arguments.
        mContext.packageName = packageName;
        mMockContext.binder.callingUid = uid;
        assertProvisioningAllowed(action, expected);

        // Set the previous package name / calling uid to go back to the initial state.
        mContext.packageName = previousPackageName;
        mMockContext.binder.callingUid = previousUid;
    }

    private void assertCheckProvisioningPreCondition(String action, int provisioningCondition) {
        assertCheckProvisioningPreCondition(action, admin1.getPackageName(), provisioningCondition);
    }

    private void assertCheckProvisioningPreCondition(
            String action, String packageName, int provisioningCondition) {
        assertWithMessage("checkProvisioningPreCondition(%s, %s) returning unexpected result",
                action, packageName).that(dpm.checkProvisioningPrecondition(action, packageName))
                        .isEqualTo(provisioningCondition);
    }

    /**
     * Setup a managed profile with the specified admin and its uid.
     * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
     * @param adminUid uid of the admin package.
     * @param copyFromAdmin package information for {@code admin} will be built based on this
     *     component's information.
     * @param appTargetSdk admin's target SDK level
     */
    private void addManagedProfile(
            ComponentName admin, int adminUid, ComponentName copyFromAdmin, int appTargetSdk)
            throws Exception {
        final int userId = UserHandle.getUserId(adminUid);
        getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
                UserHandle.USER_SYSTEM);
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
        setUpPackageManagerForFakeAdmin(admin, adminUid, /* enabledSetting= */ null,
                appTargetSdk, copyFromAdmin);
        dpm.setActiveAdmin(admin, false, userId);
        assertThat(dpm.setProfileOwner(admin, userId)).isTrue();
        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    /**
     * Same as {@code addManagedProfile} above, except using development API level as the API
     * level of the admin.
     */
    private void addManagedProfile(
            ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
        addManagedProfile(admin, adminUid, copyFromAdmin, VERSION_CODES.CUR_DEVELOPMENT);
    }

    /**
     * Convert String[] to StringParceledListSlice.
     */
    private static StringParceledListSlice asSlice(String[] s) {
        return new StringParceledListSlice(Arrays.asList(s));
    }

    private void grantManageDeviceAdmins() {
        Log.d(TAG, "Granting " + permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
    }

    private void mockPolicyExemptApps(String... apps) {
        Log.d(TAG, "Mocking R.array.policy_exempt_apps to return " + Arrays.toString(apps));
        when(mContext.resources.getStringArray(R.array.policy_exempt_apps)).thenReturn(apps);
    }

    private void mockVendorPolicyExemptApps(String... apps) {
        Log.d(TAG, "Mocking R.array.vendor_policy_exempt_apps to return " + Arrays.toString(apps));
        when(mContext.resources.getStringArray(R.array.vendor_policy_exempt_apps)).thenReturn(apps);
    }

    private void mockEmptyPolicyExemptApps() {
        when(mContext.getResources().getStringArray(R.array.policy_exempt_apps))
                .thenReturn(new String[0]);
        when(mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps))
                .thenReturn(new String[0]);
    }

    private boolean isDeprecatedPasswordApisSupported() {
        return !mIsAutomotive;
    }

    private void assumeDeprecatedPasswordApisSupported() {
        assumeTrue("device doesn't support deprecated password APIs",
                isDeprecatedPasswordApisSupported());
    }

    private static PasswordMetrics metricsForPassword(String password) {
        return PasswordMetrics.computeForCredential(LockscreenCredential.createPassword(password));
    }

    private static PasswordMetrics metricsForPin(String pin) {
        return PasswordMetrics.computeForCredential(LockscreenCredential.createPin(pin));
    }
}
