/*
 * 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.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
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.WIPE_EUICC;
import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;

import static com.android.server.testutils.TestUtils.assertExpectException;

import static org.mockito.Matchers.any;
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.atLeast;
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 android.Manifest.permission;
import android.annotation.RawRes;
import android.app.Activity;
import android.app.Notification;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
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.net.Uri;
import android.net.wifi.WifiInfo;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
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.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.Pair;

import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsListener;
import com.android.server.pm.UserRestrictionsUtils;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.io.File;
import java.io.InputStream;
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).
 * You can run them via:
 m FrameworksServicesTests &&
 adb install \
   -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
 adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner

 (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
 *
 * , or:
 * runtest -c com.android.server.devicepolicy.DevicePolicyManagerTest frameworks-services
 */
@SmallTest
@Presubmit
public class DevicePolicyManagerTest extends DpmTestBase {
    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 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 DevicePolicyManagerServiceTestable dpms;

    /*
     * 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";

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        mContext = getContext();
        mServiceContext = mContext;
        mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
        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));

        // 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();
    }

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

    @Override
    protected void tearDown() throws Exception {
        flushTasks();
        getMockTransferMetadataManager().deleteMetadataFile();
        super.tearDown();
    }

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

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

        dpm = new DevicePolicyManagerTestable(mContext, dpms);

        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(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                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(new Answer<Bundle>() {
            @Override
            public Bundle answer(InvocationOnMock invocation) throws Throwable {
                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));

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

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

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

        mServiceContext.binder.restoreCallingIdentity(ident);
    }

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

        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
        new DevicePolicyManagerServiceTestable(getServices(), mContext);

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

    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(DpmMockContext.CALLER_USER_HANDLE, 1306);
        setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
        dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false,
                DpmMockContext.CALLER_USER_HANDLE);
        assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage,
                DpmMockContext.CALLER_USER_HANDLE));

        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(DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
        verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
    }

    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, DpmMockContext.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.
     */
    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, DpmMockContext.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}
     */
    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(DpmMockContext.CALLER_USER_HANDLE));
        verify(mContext.spiedContext).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));

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

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

        // TODO Verify other calls too.

        // Make sure it's active admin1.
        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isAdminActive(admin2));
        assertFalse(dpm.isAdminActive(admin3));

        // 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");

        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
        assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));

        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.
        assertTrue(dpm.isAdminActive(admin1));
        assertTrue(dpm.isAdminActive(admin2));
        assertFalse(dpm.isAdminActive(admin3));

        // 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(DpmMockContext.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(), DpmMockContext.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();
        assertEquals(2, admins.size());
        assertEquals(admin1, admins.get(0));
        assertEquals(admin2, admins.get(1));

        // 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");

        assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
                dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));

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

    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;
        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isAdminActive(admin2));

        mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
        assertFalse(dpm.isAdminActive(admin1));
        assertTrue(dpm.isAdminActive(admin2));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setActiveAdmin}
     * with replace=false
     */
    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);
        assertTrue(dpm.isAdminActive(admin1));

        // 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.
     */
    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));
        assertFalse(dpm.isAdminActive(adminNoPerm));

        // 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);
        assertTrue(dpm.isAdminActive(adminNoPerm));

        // 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}
     */
    public void testRemoveActiveAdmin_SecurityException() {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.

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

        assertTrue(dpm.isAdminActive(admin1));

        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // Directly call the DPMS method with a different userid, which should fail.
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpms.removeActiveAdmin(admin1, DpmMockContext.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, DpmMockContext.CALLER_USER_HANDLE));
    }

    /**
     * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked
     * (because we can't send the remove broadcast).
     */
    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);

        assertTrue(dpm.isAdminActive(admin1));

        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // 1. User not unlocked.
        when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
                .thenReturn(false);
        assertExpectException(IllegalStateException.class,
                /* messageRegex= */ "User must be running and unlocked",
                () -> dpm.removeActiveAdmin(admin1));

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

        // 2. User unlocked.
        when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
                .thenReturn(true);

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

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

        // Add admin1.

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

        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // 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, DpmMockContext.CALLER_USER_HANDLE);
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);

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

    /**
     * Test for:
     * {@link DevicePolicyManager#removeActiveAdmin}
     */
    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);

        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // Broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));

        // 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(DpmMockContext.CALLER_USER_HANDLE),
                isNull(String.class),
                any(BroadcastReceiver.class),
                eq(dpms.mHandler),
                eq(Activity.RESULT_OK),
                isNull(String.class),
                isNull(Bundle.class));

        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));

        // TODO Check other internal calls.
    }

    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);

        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

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

        assertTrue(dpm.isAdminActive(admin2));
        assertFalse(dpm.isRemovingAdmin(admin2, DpmMockContext.CALLER_USER_HANDLE));

        // Broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));

        // 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(DpmMockContext.CALLER_USER_HANDLE),
                isNull(String.class),
                any(BroadcastReceiver.class),
                eq(dpms.mHandler),
                eq(Activity.RESULT_OK),
                isNull(String.class),
                isNull(Bundle.class));

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

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    }

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

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

        // Calling from a non-shell uid should fail with a SecurityException
        mContext.binder.callingUid = 123456;
        assertExpectException(SecurityException.class,
                /* messageRegex =*/ "Non-shell user attempted to call",
                () -> dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

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

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

    /**
     * Test for: @{link DevicePolicyManager#setActivePasswordState}
     *
     * 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.
     */
    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);

        // Setup device owner.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = admin1.getPackageName();
        setupDeviceOwner();

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

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

        // 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(UserHandle.USER_SYSTEM));

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID));
    }

    /**
     * Test for: @{link DevicePolicyManager#setActivePasswordState}
     *
     * 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.
     */
    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);

        // Setup device owner.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = admin1.getPackageName();
        doReturn(true).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);
        setupDeviceOwner();

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

        // Change the profile's password.
        dpm.reportPasswordChanged(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));
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(intent),
                MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID));
    }
    /**
     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
     */
    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, "owner-name", UserHandle.USER_SYSTEM));

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

        // 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!
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));

        // getDeviceOwnerComponent should return the admin1 component.
        assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());

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

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // Verify internal calls.
        verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
                eq(admin1.getPackageName()));

        // TODO We should check if the caller has called clearCallerIdentity().
        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                eq(UserHandle.USER_SYSTEM), eq(false));

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

        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
    }

    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) {
            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());

            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
        } else {
            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());

            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        if (hasDeviceOwner) {
            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());

            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
        } else {
            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());

            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        // Still with MANAGE_USERS.
        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());

        if (hasDeviceOwner) {
            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
        } else {
            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
        }

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

            assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
        } else {
            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());

            assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
            assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
        }

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        // Still no MANAGE_USERS.
        if (hasDeviceOwner) {
            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
        } else {
            assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
            assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
        }

        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.
        assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
        assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());

        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.
     */
    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")));
    }

    public void testSetDeviceOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetDeviceOwner().
    }

    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);
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));

        // Verify internal calls.
        verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
                eq(admin1.getPackageName()));

        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());

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

        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM));

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

        // Now call clear.
        doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(getServices().packageManager).
                getPackageUidAsUser(eq(admin1.getPackageName()), anyInt());

        // 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);
        reset(getServices().userManagerInternal);
        dpm.clearDeviceOwnerApp(admin1.getPackageName());

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

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

        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                eq(null),
                eq(true), eq(CAMERA_NOT_DISABLED));

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

        assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));

        // 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.
    }

    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);
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));

        // Verify internal calls.
        verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
                eq(admin1.getPackageName()));

        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());

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

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

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

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

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

        // 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, DpmMockContext.CALLER_USER_HANDLE);
            assertExpectException(IllegalStateException.class,
                    /* messageRegex= */ "already has a profile owner",
                    () -> dpm.setDeviceOwner(admin2, "owner-name",
                            DpmMockContext.CALLER_USER_HANDLE));
        });
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;

        assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // 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
        assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);
    }

    public void testSetProfileOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetProfileOwner().
    }

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

    private void checkDeviceOwnerWithMultipleDeviceAdmins() throws Exception {
        // In ths test, we use 3 users (system + 2 secondary users), set some device admins to them,
        // set admin2 on CALLER_USER_HANDLE 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;

        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);

        // Make sure the admin packge 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, DpmMockContext.CALLER_USER_HANDLE);
        dpm.setActiveAdmin(admin2, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);

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

        // Set DO on the first non-system user.
        getServices().setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
        assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));

        assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));

        // Then check getDeviceOwnerAdminLocked().
        assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
        assertEquals(DpmMockContext.CALLER_UID, dpms.getDeviceOwnerAdminLocked().getUid());
    }

    /**
     * This essentially tests
     * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
     * private.)
     *
     * We didn't use to persist the DO component class name, but now we do, and the above method
     * finds the right component from a package name upon migration.
     */
    public void testDeviceOwnerMigration() throws Exception {
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        checkDeviceOwnerWithMultipleDeviceAdmins();

        // Overwrite the device owner setting and clears the clas name.
        dpms.mOwners.setDeviceOwner(
                new ComponentName(admin2.getPackageName(), ""),
                "owner-name", DpmMockContext.CALLER_USER_HANDLE);
        dpms.mOwners.writeDeviceOwner();

        // Make sure the DO component name doesn't have a class name.
        assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());

        // Then create a new DPMS to have it load the settings from files.
        when(getServices().userManager.getUserRestrictions(any(UserHandle.class)))
                .thenReturn(new Bundle());
        initializeDpms();

        // Now the DO component name is a full name.
        // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
        // DO.
        assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
    }

    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");
            assertNotNull(returned);
            assertEquals(returned.size(), 1);
            assertEquals(returned.get("KEY_STRING"), "Foo1");
        }

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

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

    /**
     * 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, DpmMockContext.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),
                anyInt(),
                eq(userId));
        doReturn(pi.applicationInfo).when(getServices().ipackageManager).getApplicationInfo(
                eq(packageName),
                anyInt(),
                eq(userId));
        doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId);
        // Setup application UID with the PackageManager
        doReturn(uid).when(getServices().packageManager).getPackageUidAsUser(
                eq(packageName),
                eq(userId));
        // Associate packageName to uid
        doReturn(packageName).when(getServices().ipackageManager).getNameForUid(eq(uid));
        doReturn(new String[]{packageName})
                .when(getServices().ipackageManager).getPackagesForUid(eq(uid));
        return uid;
    }

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

        mContext.applicationInfo = new ApplicationInfo();
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        mContext.packageName = "com.android.frameworks.servicestests";
        getServices().addPackageContext(user, mContext);
        when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);

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

        final String TEST_STRING = "Test for exactly 2 certs out of 4";
        doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2));

        // 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.
        verify(getServices().notificationManager, timeout(1000))
                .notifyAsUser(anyString(), anyInt(), argThat(
                        new BaseMatcher<Notification>() {
                            @Override
                            public boolean matches(Object item) {
                                final Notification noti = (Notification) item;
                                return TEST_STRING.equals(
                                        noti.extras.getString(Notification.EXTRA_TITLE));
                            }
                            @Override
                            public void describeTo(Description description) {
                                description.appendText(
                                        "Notification{title=\"" + TEST_STRING + "\"}");
                            }
                        }), eq(user));
    }

    /**
     * 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.
     */
    public void testDelegation() throws Exception {
        setAsProfileOwner(admin1);

        final int userHandle = DpmMockContext.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
        DevicePolicyManagerService.DevicePolicyData policy = dpms.mUserData.get(userHandle);
        assertEquals(2, policy.mDelegationMap.size());
        MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE),
            DELEGATION_CERT_INSTALL);
        MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, CERT_DELEGATE),
            DELEGATION_CERT_INSTALL);
        assertEquals(CERT_DELEGATE, dpm.getCertInstallerPackage(admin1));
        MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(RESTRICTIONS_DELEGATE),
            DELEGATION_APP_RESTRICTIONS);
        MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, RESTRICTIONS_DELEGATE),
            DELEGATION_APP_RESTRICTIONS);
        assertEquals(RESTRICTIONS_DELEGATE, dpm.getApplicationRestrictionsManagingPackage(admin1));

        // 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");
        }
    }

    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 a delegate of scope delegation-app-restrictions.";
        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();
        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
        final Bundle rest = new Bundle();
        rest.putString("KEY_STRING", "Foo1");
        assertExpectException(SecurityException.class, nonDelegateExceptionMessageRegex,
                () -> 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();
        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());

        // 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);
        assertEquals(appRestrictionsManagerPackage,
                dpm.getApplicationRestrictionsManagingPackage(admin1));

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

        // 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);
        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
        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();
        assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1"));
        dpm.setApplicationRestrictions(admin1, "pkg1", null);
        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());

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

    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);
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                UserHandle.USER_SYSTEM));

        // Check that the user restrictions that are enabled by default are set. Then unset them.
        final String[] defaultRestrictions = UserRestrictionsUtils
                .getDefaultEnabledForDeviceOwner().toArray(new String[0]);
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(defaultRestrictions),
                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(defaultRestrictions),
                dpm.getUserRestrictions(admin1)
        );
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(defaultRestrictions),
                eq(true) /* isDeviceOwner */,
                eq(CAMERA_NOT_DISABLED)
        );
        reset(getServices().userManagerInternal);

        for (String restriction : defaultRestrictions) {
            dpm.clearUserRestriction(admin1, restriction);
        }

        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),
                eq(true), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

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

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
                dpms.getDeviceOwnerAdminLocked().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(UserManager.DISALLOW_OUTGOING_CALLS),
                eq(true), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
                dpms.getDeviceOwnerAdminLocked().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(),
                eq(true), eq(CAMERA_NOT_DISABLED));
        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),
                eq(true), eq(CAMERA_NOT_DISABLED));
        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),
                eq(true), eq(CAMERA_NOT_DISABLED));
        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),
                eq(true), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

        dpm.setCameraDisabled(admin1, true);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                // DISALLOW_CAMERA will be applied to both local and global.
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
                        UserManager.DISALLOW_ADD_USER),
                eq(true), eq(CAMERA_DISABLED_GLOBALLY));
        reset(getServices().userManagerInternal);

        // Set up another DA and let it disable camera.  Now DISALLOW_CAMERA will only be applied
        // locally.
        dpm.setCameraDisabled(admin1, false);
        reset(getServices().userManagerInternal);

        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
        dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM);
        dpm.setCameraDisabled(admin2, true);

        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
                        UserManager.DISALLOW_ADD_USER),
                eq(true), eq(CAMERA_DISABLED_LOCALLY));
        reset(getServices().userManagerInternal);
        // TODO Make sure restrictions are written to the file.
    }

    public void testSetUserRestriction_asPo() {
        setAsProfileOwner(admin1);

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

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

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

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpms.getProfileOwnerAdminLocked(DpmMockContext.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(DpmMockContext.CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
                eq(false), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(
                        UserManager.DISALLOW_OUTGOING_CALLS
                ),
                dpms.getProfileOwnerAdminLocked(DpmMockContext.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(DpmMockContext.CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(),
                eq(false), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getProfileOwnerAdminLocked(DpmMockContext.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);
        reset(getServices().userManagerInternal);
        dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(DpmMockContext.CALLER_USER_HANDLE),
                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
                eq(false), eq(CAMERA_NOT_DISABLED));
        reset(getServices().userManagerInternal);

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

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


    public void testDefaultEnabledUserRestrictions() 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);
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                UserHandle.USER_SYSTEM));

        // Check that the user restrictions that are enabled by default are set. Then unset them.
        String[] defaultRestrictions = UserRestrictionsUtils
                .getDefaultEnabledForDeviceOwner().toArray(new String[0]);
        assertTrue(defaultRestrictions.length > 0);
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(defaultRestrictions),
                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(defaultRestrictions),
                dpm.getUserRestrictions(admin1)
        );
        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(defaultRestrictions),
                eq(true) /* isDeviceOwner */,
                eq(CAMERA_NOT_DISABLED)
        );
        reset(getServices().userManagerInternal);

        for (String restriction : defaultRestrictions) {
            dpm.clearUserRestriction(admin1, restriction);
        }

        assertNoDeviceOwnerRestrictions();

        // Initialize DPMS again and check that the user restriction wasn't enabled again.
        reset(getServices().userManagerInternal);
        initializeDpms();
        assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
        assertNotNull(dpms.getDeviceOwnerAdminLocked());

        assertNoDeviceOwnerRestrictions();

        // Add a new restriction to the default set, initialize DPMS, and check that the restriction
        // is set as it wasn't enabled during setDeviceOwner.
        final String newDefaultEnabledRestriction = UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
        assertFalse(UserRestrictionsUtils
                .getDefaultEnabledForDeviceOwner().contains(newDefaultEnabledRestriction));
        UserRestrictionsUtils
                .getDefaultEnabledForDeviceOwner().add(newDefaultEnabledRestriction);
        try {
            reset(getServices().userManagerInternal);
            initializeDpms();
            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertNotNull(dpms.getDeviceOwnerAdminLocked());

            DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(newDefaultEnabledRestriction),
                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
            );
            DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(newDefaultEnabledRestriction),
                dpm.getUserRestrictions(admin1)
            );
            verify(getServices().userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
                eq(UserHandle.USER_SYSTEM),
                MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
                eq(true) /* isDeviceOwner */,
                eq(CAMERA_NOT_DISABLED)
            );
            reset(getServices().userManagerInternal);

            // Remove the restriction.
            dpm.clearUserRestriction(admin1, newDefaultEnabledRestriction);

            // Initialize DPMS again. The restriction shouldn't be enabled for a second time.
            initializeDpms();
            assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
            assertNotNull(dpms.getDeviceOwnerAdminLocked());
            assertNoDeviceOwnerRestrictions();
        } finally {
            UserRestrictionsUtils
                .getDefaultEnabledForDeviceOwner().remove(newDefaultEnabledRestriction);
        }
    }

    private void assertNoDeviceOwnerRestrictions() {
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
        );
        DpmTestUtils.assertRestrictions(
                DpmTestUtils.newRestrictions(),
                dpm.getUserRestrictions(admin1)
        );
    }

    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= */ "No active admin",
                () -> dpm.getWifiMacAddress(admin1));

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

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

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

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

        // 4-1.  But no WifiInfo.
        assertNull(dpm.getWifiMacAddress(admin1));

        // 4-2.  Returns WifiInfo, but with the default MAC.
        when(getServices().wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
        assertNull(dpm.getWifiMacAddress(admin1));

        // 4-3. With a real MAC address.
        final WifiInfo wi = new WifiInfo();
        wi.setMacAddress("11:22:33:44:55:66");
        when(getServices().wifiManager.getConnectionInfo()).thenReturn(wi);
        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
    }

    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);
        assertTrue(dpm.isAdminActive(admin1));
        assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
                () -> dpm.reboot(admin1));

        // Set admin1 as PO.
        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
        assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
                () -> dpm.reboot(admin1));

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

        // 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);
    }

    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.
        {
            assertNull(dpm.getLongSupportMessage(admin1));
            assertNull(dpm.getShortSupportMessage(admin1));
            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
            assertNull(dpm.getShortSupportMessageForUser(admin1,
                    DpmMockContext.CALLER_USER_HANDLE));
            assertNull(dpm.getLongSupportMessageForUser(admin1,
                    DpmMockContext.CALLER_USER_HANDLE));
            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
        }

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

        // Can't set message for admin in another uid.
        {
            mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
            assertExpectException(SecurityException.class,
                    /* messageRegex= */ "is not owned by uid",
                    () -> 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);
            assertEquals(supportText, dpm.getShortSupportMessage(admin1));
            assertNull(dpm.getLongSupportMessage(admin1));
            assertNull(dpm.getShortSupportMessage(admin2));

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

            dpm.setShortSupportMessage(admin1, null);
            assertNull(dpm.getShortSupportMessage(admin1));
        }

        // 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);
            assertEquals(supportText, dpm.getLongSupportMessage(admin1));
            assertNull(dpm.getShortSupportMessage(admin1));
            assertNull(dpm.getLongSupportMessage(admin2));

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

            dpm.setLongSupportMessage(admin1, null);
            assertNull(dpm.getLongSupportMessage(admin1));
        }
    }

    public void testSetGetMeteredDataDisabled() throws Exception {
        setAsProfileOwner(admin1);

        final ArrayList<String> emptyList = new ArrayList<>();
        assertEquals(emptyList, dpm.getMeteredDataDisabled(admin1));

        // 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, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
        setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
        List<String> excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict);

        // Verify
        assertEquals(emptyList, excludedPkgs);
        assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1));
        verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
                MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
                eq(DpmMockContext.CALLER_USER_HANDLE));

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

        // Verify
        assertEquals(emptyList, excludedPkgs);
        assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1));
        verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
                MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
                eq(DpmMockContext.CALLER_USER_HANDLE));
    }

    public void testSetGetMeteredDataDisabled_deviceAdmin() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        dpm.setActiveAdmin(admin1, true);
        assertTrue(dpm.isAdminActive(admin1));
        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);

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

    public void testGetMeteredDataDisabledForUser() throws Exception {
        setAsProfileOwner(admin1);

        // Setup
        final ArrayList<String> emptyList = new ArrayList<>();
        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, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
        setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
        List<String> excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict);

        // Verify
        assertEquals(emptyList, excludedPkgs);
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(package1 + "should be restricted",
                dpm.isMeteredDataDisabledForUser(admin1, package1,
                        DpmMockContext.CALLER_USER_HANDLE));
        assertTrue(package2 + "should be restricted",
                dpm.isMeteredDataDisabledForUser(admin1, package2,
                        DpmMockContext.CALLER_USER_HANDLE));
        assertFalse(package3 + "should not be restricted",
                dpm.isMeteredDataDisabledForUser(admin1, package3,
                        DpmMockContext.CALLER_USER_HANDLE));
    }

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

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

    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");
        assertNull(intent);

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

        // 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);
        assertNull(intent);

        // Permission that is set by device owner returns correct intent
        when(getServices().userManager.getUserRestrictionSource(
                eq(UserManager.DISALLOW_ADJUST_VOLUME),
                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
        intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
        assertNotNull(intent);
        assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction());
        assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID),
                intent.getIntExtra(Intent.EXTRA_USER_ID, -1));
        assertEquals(admin1, intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN));
        assertEquals(UserManager.DISALLOW_ADJUST_VOLUME,
                intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));

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

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

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

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

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

        // Backups are not mandatory
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_MANDATORY_BACKUPS);
        assertNull(intent);

        // Backups are mandatory
        ComponentName transportComponent = ComponentName.unflattenFromString(
                "android/com.android.internal.backup.LocalTransport");
        dpm.setMandatoryBackupTransport(admin1, transportComponent);
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_MANDATORY_BACKUPS);
        assertNotNull(intent);
        assertEquals(DevicePolicyManager.POLICY_MANDATORY_BACKUPS,
                intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));

        // 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);
        assertNotNull(intent);
        assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA,
                intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
        assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID),
                intent.getIntExtra(Intent.EXTRA_USER_ID, -1));
        // ScreenCapture should not be disabled by device owner
        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
        assertNull(intent);
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#setAffiliationIds}
     * {@link DevicePolicyManager#getAffiliationIds}
     * {@link DevicePolicyManager#isAffiliatedUser}
     */
    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);

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

        // 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);
        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
        assertTrue(dpm.isAffiliatedUser());
        assertTrue(dpm.getAffiliationIds(admin1).isEmpty());

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

        // 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");
        assertFalse(dpm.isAffiliatedUser());

        // 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;
        assertFalse(dpm.isAffiliatedUser());

        // 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");
        assertTrue(dpm.isAffiliatedUser());

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

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

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

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

    public void testGetUserProvisioningState_defaultResult() {
        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
    }

    public void testSetUserProvisioningState_permission() throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

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

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

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

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

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

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

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

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

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

    public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
            throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
                DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
                DevicePolicyManager.STATE_USER_UNMANAGED);
    }

    public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
            throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

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

    public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

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

    public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

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

    public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
            throws Exception {
        setupProfileOwner();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

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

    private void exerciseUserProvisioningTransitions(int userId, int... states) {
        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
        for (int state : states) {
            dpm.setUserProvisioningState(state, userId);
            assertEquals(state, dpm.getUserProvisioningState());
        }
    }

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

        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
        dpm.setActiveAdmin(admin1, false);
        assertTrue(dpm.setProfileOwner(admin1, null, DpmMockContext.CALLER_USER_HANDLE));

        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);
        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));

        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    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, UserHandle.USER_SYSTEM);
        verifyStayOnWhilePluggedCleared(false);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

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

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

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

        dpm.setMaximumTimeToLock(admin2, 4);
        verifyScreenTimeoutCall(4L, UserHandle.USER_SYSTEM);
        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, UserHandle.USER_SYSTEM);
        verifyStayOnWhilePluggedCleared(true);
        reset(getServices().powerManagerInternal);
        reset(getServices().settings);

        dpm.setMaximumTimeToLock(admin2, 10);
        verifyScreenTimeoutCall(10L, UserHandle.USER_SYSTEM);
        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, UserHandle.USER_SYSTEM);
        verifyStayOnWhilePluggedCleared(false);
    }

    // Test if lock timeout on managed profile is handled correctly depending on whether profile
    // uses separate challenge.
    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);

        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);
    }

    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);
        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);

        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
        assertEquals(dpm.getRequiredStrongAuthTimeout(null),
                DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);

        // admin not participating by default
        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);

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

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

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

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

        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);

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

        // 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.isSplitSystemUser()).thenReturn(false);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                .thenReturn(true);
        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    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_MANAGED_PROFILE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
    }

    public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception {
        setup_DeviceAdminFeatureOff();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED);
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    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_MANAGED_PROFILE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);

        // Test again when split user is on
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
    }

    public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception {
        setup_ManagedProfileFeatureOff();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);

        // Test again when split user is on
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_MANAGED_USERS_NOT_SUPPORTED);
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
        setup_nonSplitUser_firstBoot_primaryUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                false /* because of non-split user */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                false /* because of non-split user */);
    }

    public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser()
            throws Exception {
        setup_nonSplitUser_firstBoot_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

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

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

    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
            throws Exception {
        setup_nonSplitUser_afterDeviceSetup_primaryUser();
        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_MANAGED_PROFILE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                false/* because of non-split user */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                false/* because of non-split user */);
    }

    public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser()
            throws Exception {
        setup_nonSplitUser_afterDeviceSetup_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT);
    }

    public void testProvisioning_nonSplitUser_withDo_primaryUser() throws Exception {
        setup_nonSplitUser_withDo_primaryUser();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_HAS_DEVICE_OWNER);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);

        // COMP mode is allowed.
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);

        // And other DPCs can also provision a managed profile (DO + BYOD case).
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception {
        setup_nonSplitUser_withDo_primaryUser();
        mContext.packageName = admin1.getPackageName();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        // The DO should be allowed to initiate provisioning if it set the restriction itself, but
        // other packages should be forbidden.
        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_DEVICE_OWNER);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedBySystem()
            throws Exception {
        setup_nonSplitUser_withDo_primaryUser();
        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.CODE_ADD_MANAGED_PROFILE_DISALLOWED);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);

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

    public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception {
        setup_nonSplitUser_withDo_primaryUser_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.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DpmMockContext.ANOTHER_PACKAGE_NAME,
                DevicePolicyManager.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true,
                DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID);
    }

    public void testCheckProvisioningPreCondition_nonSplitUser_comp_cannot_remove_profile()
            throws Exception {
        setup_nonSplitUser_withDo_primaryUser_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.CODE_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.CODE_OK);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
        setup_splitUser_firstBoot_systemUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                false /* because canAddMoreManagedProfiles returns false */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                false/* because calling uid is system user */);
    }

    public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser()
            throws Exception {
        setup_splitUser_firstBoot_systemUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_SYSTEM_USER);
    }

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

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
        setup_splitUser_afterDeviceSetup_systemUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                true/* it's undefined behavior. Can be changed into false in the future */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                false /* because canAddMoreManagedProfiles returns false */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                true/* it's undefined behavior. Can be changed into false in the future */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                false/* because calling uid is system user */);
    }

    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser()
            throws Exception {
        setup_splitUser_afterDeviceSetup_systemUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_SYSTEM_USER);
    }

    private void setup_splitUser_firstBoot_primaryUser() throws Exception {
        when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                .thenReturn(true);
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                true)).thenReturn(true);
        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    }

    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
        setup_splitUser_firstBoot_primaryUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
    }

    public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser()
            throws Exception {
        setup_splitUser_firstBoot_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_OK);
    }

    private void setup_splitUser_afterDeviceSetup_primaryUser() throws Exception {
        when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                .thenReturn(true);
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                true)).thenReturn(true);
        setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    }

    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
            throws Exception {
        setup_splitUser_afterDeviceSetup_primaryUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                true/* it's undefined behavior. Can be changed into false in the future */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                true/* it's undefined behavior. Can be changed into false in the future */);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                false/* because user setup completed */);
    }

    public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser()
            throws Exception {
        setup_splitUser_afterDeviceSetup_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(
                DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
                DevicePolicyManager.CODE_OK);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
                DevicePolicyManager.CODE_USER_SETUP_COMPLETED);
    }

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

        when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                .thenReturn(true);
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                .thenReturn(false);
        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);

        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
    }

    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
            throws Exception {
        setup_provisionManagedProfileWithDeviceOwner_systemUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                false /* can't provision managed profile on system user */);
    }

    public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser()
            throws Exception {
        setup_provisionManagedProfileWithDeviceOwner_systemUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER);
    }

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

        when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                .thenReturn(true);
        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
        when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                true)).thenReturn(true);
        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    }

    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, true);
    }

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

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

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

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

        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
    }

    public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
            throws Exception {
        setup_provisionManagedProfileCantRemoveUser_primaryUser();
        mContext.packageName = admin1.getPackageName();
        setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
    }

    public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser()
            throws Exception {
        setup_provisionManagedProfileCantRemoveUser_primaryUser();
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
                DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
    }

    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"));
    }

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

    public void testForceUpdateUserSetupComplete_systemUser() {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        // GIVEN calling from user 20
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.forceUpdateUserSetupComplete());
    }

    public void testForceUpdateUserSetupComplete_userbuild() {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        final int userId = UserHandle.USER_SYSTEM;
        // GIVEN userComplete is false in SettingsProvider
        setUserSetupCompleteForUser(false, userId);

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

        // GIVEN it's user build
        getServices().buildMock.isDebuggable = false;

        assertTrue(dpms.hasUserSetupCompleted());

        dpm.forceUpdateUserSetupComplete();

        // THEN the state in dpms is not changed
        assertTrue(dpms.hasUserSetupCompleted());
    }

    public void testForceUpdateUserSetupComplete_userDebugbuild() {
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        final int userId = UserHandle.USER_SYSTEM;
        // GIVEN userComplete is false in SettingsProvider
        setUserSetupCompleteForUser(false, userId);

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

        // GIVEN it's userdebug build
        getServices().buildMock.isDebuggable = true;

        assertTrue(dpms.hasUserSetupCompleted());

        dpm.forceUpdateUserSetupComplete();

        // THEN the state in dpms is not changed
        assertFalse(dpms.hasUserSetupCompleted());
    }

    private void clearDeviceOwner() throws Exception {
        doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(getServices().packageManager)
                .getPackageUidAsUser(eq(admin1.getPackageName()), anyInt());

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

    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(DpmMockContext.CALLER_USER_HANDLE);
        when(mContext.resources.getBoolean(R.bool.config_supportPreRebootSecurityLogs))
                .thenReturn(true);

        // No logs were retrieved so far.
        assertEquals(-1, dpm.getLastSecurityLogRetrievalTime());

        // Enabling logging should not change the timestamp.
        dpm.setSecurityLoggingEnabled(admin1, true);
        verify(getServices().settings)
                .securityLogSetLoggingEnabledProperty(true);
        when(getServices().settings.securityLogGetLoggingEnabledProperty())
                .thenReturn(true);
        assertEquals(-1, dpm.getLastSecurityLogRetrievalTime());

        // 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();
        assertTrue(firstSecurityLogRetrievalTime >= beforeRetrieval);
        assertTrue(firstSecurityLogRetrievalTime <= afterRetrieval);

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

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

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

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

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

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

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

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

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

    public void testSetSystemSettingFailWithPO() throws Exception {
        setupProfileOwner();
        assertExpectException(SecurityException.class, null, () ->
                dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"));
    }

    public void testSetSystemSetting() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0");
        verify(getServices().settings).settingsSystemPutString(
                Settings.System.SCREEN_BRIGHTNESS, "0");
    }

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

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

    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);
        assertFalse(dpm.setTime(admin1, 0));
    }

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

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

    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);
        assertFalse(dpm.setTimeZone(admin1, "Asia/Shanghai"));
    }

    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(eq(R.color.notification_action_list), anyObject()))
                .thenReturn(Color.WHITE);
        when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
                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(DpmMockContext.CALLER_USER_HANDLE);

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

        // 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();
        assertTrue(bugReportRequestTime >= beforeRequest);
        assertTrue(bugReportRequestTime <= afterRequest);

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

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

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

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

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

    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(eq(R.color.notification_action_list), anyObject()))
                .thenReturn(Color.WHITE);
        when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
                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(DpmMockContext.CALLER_USER_HANDLE);
        when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
                .thenReturn(true);

        // No logs were retrieved so far.
        assertEquals(-1, dpm.getLastNetworkLogRetrievalTime());

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

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

        // 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();
        assertTrue(firstNetworkLogRetrievalTime >= beforeRetrieval);
        assertTrue(firstNetworkLogRetrievalTime <= afterRetrieval);

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

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

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

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

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

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

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

    public void testGetBindDeviceAdminTargetUsers() throws Exception {
        // 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);

        // Setup a managed profile managed by the same admin.
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

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

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

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        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);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setAffiliationIds(admin1, userAffiliationIds);

        // Calling from device owner admin, the result list should just contain the managed
        // profile user id.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID));

        // Calling from managed profile admin, the result list should just contain the system
        // user id.
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM);

        // 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);
    }

    public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception {
        // Setup a device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();

        // Set up a managed profile managed by different package.
        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);

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

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);

        // Calling from device owner admin, we should get zero bind device admin target users as
        // their packages are different.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
        MoreAsserts.assertEmpty(targetUsers);

        // Calling from managed profile admin, we should still get zero target users for the same
        // reason.
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage);
        MoreAsserts.assertEmpty(targetUsers);
    }

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

    private void verifyLockTaskState(int userId, String[] packages, int flags) throws Exception {
        verify(getServices().iactivityManager).updateLockTaskPackages(userId, packages);
        verify(getServices().iactivityManager).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) {
            assertTrue(dpm.isLockTaskPermitted(p));
        }
        assertFalse(dpm.isLockTaskPermitted("anotherPackage"));
        // 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));
        assertFalse(dpm.isLockTaskPermitted("doPackage1"));
        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
                () -> dpm.setLockTaskFeatures(who, flags));
    }

    public void testLockTaskPolicyAllowedForAffiliatedUsers() 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);

        // 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);

        // Setup a PO on the secondary user
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin3);
        verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE);

        // The DO can still set lock task packages
        final String[] doPackages = {"doPackage1", "doPackage2"};
        final int flags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS;
        verifyCanSetLockTask(DpmMockContext.CALLER_SYSTEM_USER_UID, UserHandle.USER_SYSTEM, admin1, doPackages, flags);

        final String[] secondaryPoPackages = {"secondaryPoPackage1", "secondaryPoPackage2"};
        final int secondaryPoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS;
        verifyCanNotSetLockTask(DpmMockContext.CALLER_UID, admin3, secondaryPoPackages, secondaryPoFlags);

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

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

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds);

        // Now the managed profile can set lock task packages.
        dpm.setLockTaskPackages(adminDifferentPackage, poPackages);
        MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage));
        assertTrue(dpm.isLockTaskPermitted("poPackage1"));
        assertFalse(dpm.isLockTaskPermitted("doPackage2"));
        // And it can set lock task features.
        dpm.setLockTaskFeatures(adminDifferentPackage, poFlags);
        verifyLockTaskState(MANAGED_PROFILE_USER_ID, poPackages, poFlags);

        // Unaffiliate the profile, lock task mode no longer available on the profile.
        dpm.setAffiliationIds(adminDifferentPackage, Collections.emptySet());
        assertFalse(dpm.isLockTaskPermitted("poPackage1"));
        // Lock task packages cleared when loading user data and when the user becomes unaffiliated.
        verify(getServices().iactivityManager, times(2)).updateLockTaskPackages(
                MANAGED_PROFILE_USER_ID, new String[0]);
        verify(getServices().iactivityManager, times(2)).updateLockTaskFeatures(
                MANAGED_PROFILE_USER_ID, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);

        // Verify that lock task packages were not cleared for the DO
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        assertTrue(dpm.isLockTaskPermitted("doPackage1"));

    }

    public void testLockTaskPolicyForProfileOwner() throws Exception {
        // Setup a PO
        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);
        verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE);

        final String[] poPackages = {"poPackage1", "poPackage2"};
        final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS
                | DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS;
        verifyCanSetLockTask(DpmMockContext.CALLER_UID, DpmMockContext.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_RECENTS;
        verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, mpoPackages, mpoFlags);
    }

    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.
        assertTrue(dpm.isDeviceManaged());
        mContext.binder.callingUid = 1234567;
        mContext.callerPermissions.add(permission.MANAGE_USERS);
        assertTrue(dpm.isDeviceManaged());
        mContext.callerPermissions.remove(permission.MANAGE_USERS);
        mContext.binder.clearCallingIdentity();
        assertTrue(dpm.isDeviceManaged());

        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);
        assertFalse(dpm.isDeviceManaged());
        mContext.callerPermissions.remove(permission.MANAGE_USERS);
        mContext.binder.clearCallingIdentity();
        assertFalse(dpm.isDeviceManaged());
    }

    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.
        assertEquals("organization", dpm.getDeviceOwnerOrganizationName());

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

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

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

    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;

        // 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);
    }

    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));
    }

    public void testWipeDataDeviceOwner() 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.wipeData(0);
        verify(getServices().recoverySystem).rebootWipeUserData(
                /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
                /*wipeEuicc=*/ eq(false));
    }

    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.wipeData(WIPE_EUICC);
        verify(getServices().recoverySystem).rebootWipeUserData(
                /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
                /*wipeEuicc=*/ eq(true));
    }

    public void testWipeDataDeviceOwnerDisallowed() 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.wipeData(0));
    }

    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);
    }

    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);
    }

    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.
        verify(getServices().recoverySystem).rebootWipeUserData(
                /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
                /*wipeEuicc=*/ eq(false));
    }

    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());
    }

    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(DpmMockContext.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(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(0);

        // System can retrieve permission grant state.
        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.packageName = "com.example.system";
        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
                dpm.getPermissionGrantState(null, app1, permission));
        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
                dpm.getPermissionGrantState(null, app2, permission));

        // 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);
        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
                dpm.getPermissionGrantState(admin1, app1, permission));
        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
                dpm.getPermissionGrantState(admin1, app2, permission));
    }

    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)))
            .thenReturn(handle);
        assertTrue(dpm.setResetPasswordToken(admin1, token));

        // test password activation
        when(getServices().lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM)))
            .thenReturn(true);
        assertTrue(dpm.isResetPasswordTokenActive(admin1));

        // test reset password with token
        when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
                eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
                eq(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED), eq(handle), eq(token),
                eq(UserHandle.USER_SYSTEM)))
                .thenReturn(true);
        assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0));

        // test removing a token
        when(getServices().lockPatternUtils.removeEscrowToken(eq(handle), eq(UserHandle.USER_SYSTEM)))
                .thenReturn(true);
        assertTrue(dpm.clearResetPasswordToken(admin1));
    }

    public void testSetPasswordBlacklistCannotBeCalledByNonAdmin() throws Exception {
        assertExpectException(SecurityException.class, /* messageRegex= */ null,
                () -> dpm.setPasswordBlacklist(admin1, null, null));
        verifyZeroInteractions(getServices().passwordBlacklist);
    }

    public void testClearingPasswordBlacklistDoesNotCreateNewBlacklist() throws Exception {
        setupProfileOwner();
        dpm.setPasswordBlacklist(admin1, null, null);
        verifyZeroInteractions(getServices().passwordBlacklist);
    }

    public void testSetPasswordBlacklistCreatesNewBlacklist() throws Exception {
        final String name = "myblacklist";
        final List<String> explicit = Arrays.asList("password", "letmein");
        setupProfileOwner();
        dpm.setPasswordBlacklist(admin1, name, explicit);
        verify(getServices().passwordBlacklist).savePasswordBlacklist(name, explicit);
    }

    public void testSetPasswordBlacklistOnlyConvertsExplicitToLowerCase() throws Exception {
        final List<String> mixedCase = Arrays.asList("password", "LETMEIN", "FooTBAll");
        final List<String> lowerCase = Arrays.asList("password", "letmein", "football");
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        final String name = "Name of the Blacklist";
        dpm.setPasswordBlacklist(admin1, name, mixedCase);
        verify(getServices().passwordBlacklist).savePasswordBlacklist(name, lowerCase);
    }

    public void testIsActivePasswordSufficient() throws Exception {
        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 = new PasswordMetrics(
                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
                8, 2,
                6, 1,
                0, 1);

        setActivePasswordState(passwordMetricsNoSymbols);
        assertTrue(dpm.isActivePasswordSufficient());

        initializeDpms();
        reset(mContext.spiedContext);
        assertTrue(dpm.isActivePasswordSufficient());

        // 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);
        assertTrue(dpm.isActivePasswordSufficient());

        dpm.setPasswordMinimumSymbols(admin1, 1);
        // This assertion would fail if we had not called setActivePasswordState() again after
        // initializeDpms() - see previous comment.
        assertFalse(dpm.isActivePasswordSufficient());

        initializeDpms();
        reset(mContext.spiedContext);
        assertFalse(dpm.isActivePasswordSufficient());

        PasswordMetrics passwordMetricsWithSymbols = new PasswordMetrics(
                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
                7, 2,
                5, 1,
                1, 2);

        setActivePasswordState(passwordMetricsWithSymbols);
        assertTrue(dpm.isActivePasswordSufficient());
    }

    private void setActivePasswordState(PasswordMetrics passwordMetrics)
            throws Exception {
        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
        final long ident = mContext.binder.clearCallingIdentity();

        dpm.setActivePasswordState(passwordMetrics, userHandle);
        dpm.reportPasswordChanged(userHandle);

        // Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of
        // reportPasswordChanged()
        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(userHandle));

        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));

        // CertificateMonitor.updateInstalledCertificates is called on the background thread,
        // let it finish with system uid, otherwise it will throw and crash.
        flushTasks();

        mContext.binder.restoreCallingIdentity(ident);
    }

    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(DpmMockContext.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;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // 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;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // Second user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // First user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // 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;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // Restarting the DPMS should not lose information.
        initializeDpms();
        mContext.binder.callingUid = firstUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // Device owner can find out whether it set the current IME itself.
        mContext.binder.callingUid = deviceOwnerUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // Removing the device owner should clear the information that it set the current IME.
        clearDeviceOwner();
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
    }

    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(DpmMockContext.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;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // Profile owner changes IME for second user.
        mContext.binder.callingUid = profileOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime1");
        dpm.setSecureSetting(admin1, currentIme, "ime2");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime2",
                DpmMockContext.CALLER_USER_HANDLE);
        reset(getServices().settings);
        dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // First user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // Second user changes IME manually.
        dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());

        // Profile owner changes IME for second user again.
        mContext.binder.callingUid = profileOwnerUid;
        when(getServices().settings.settingsSecureGetStringForUser(currentIme,
                DpmMockContext.CALLER_USER_HANDLE)).thenReturn("ime2");
        dpm.setSecureSetting(admin1, currentIme, "ime3");
        verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime3",
                DpmMockContext.CALLER_USER_HANDLE);
        dpms.notifyChangeToContentObserver(currentImeUri, DpmMockContext.CALLER_USER_HANDLE);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // Restarting the DPMS should not lose information.
        initializeDpms();
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // Profile owner can find out whether it set the current IME itself.
        mContext.binder.callingUid = profileOwnerUid;
        assertTrue(dpm.isCurrentInputMethodSetByOwner());

        // Removing the profile owner should clear the information that it set the current IME.
        dpm.clearProfileOwner(admin1);
        mContext.binder.callingUid = firstUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
        mContext.binder.callingUid = secondUserSystemUid;
        assertFalse(dpm.isCurrentInputMethodSetByOwner());
    }

    public void testSetPermittedCrossProfileNotificationListeners_unavailableForDo()
            throws Exception {
        // Set up a device owner.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid);
    }

    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";
        assertFalse(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.singletonList(packageName)));
        assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId));

        // Attempt to set to empty list (which means no listener is whitelisted)
        mContext.binder.callingUid = adminUid;
        assertFalse(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.emptyList()));
        assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId));
    }

    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);

        assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.singletonList(permittedListener)));

        // 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;
        assertTrue(dpms.isNotificationListenerServicePermitted(
                permittedListener, MANAGED_PROFILE_USER_ID));
    }

    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
        assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(
                permittedListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                notPermittedListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));

        // Setting only one package in the whitelist
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.singletonList(permittedListener)));
        final List<String> permittedListeners =
                dpms.getPermittedCrossProfileNotificationListeners(admin1);
        assertEquals(1, permittedListeners.size());
        assertEquals(permittedListener, permittedListeners.get(0));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(
                permittedListener, MANAGED_PROFILE_USER_ID));
        assertFalse(dpms.isNotificationListenerServicePermitted(
                notPermittedListener, MANAGED_PROFILE_USER_ID));
        // System packages are always allowed (even if not in the whitelist)
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));

        // Setting an empty whitelist - only system listeners allowed
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.emptyList()));
        assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertFalse(dpms.isNotificationListenerServicePermitted(
                permittedListener, MANAGED_PROFILE_USER_ID));
        assertFalse(dpms.isNotificationListenerServicePermitted(
                notPermittedListener, MANAGED_PROFILE_USER_ID));
        // System packages are always allowed (even if not in the whitelist)
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));

        // Setting a null whitelist - all listeners allowed
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertTrue(dpms.setPermittedCrossProfileNotificationListeners(admin1, null));
        assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(
                permittedListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                notPermittedListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));
    }

    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)
        assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertTrue(dpms.isNotificationListenerServicePermitted(
                nonSystemPackage, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                nonSystemPackage, UserHandle.USER_SYSTEM));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, UserHandle.USER_SYSTEM));

        // Setting an empty whitelist - only system listeners allowed in managed profile, but
        // all allowed in primary profile
        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
                admin1, Collections.emptyList()));
        assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        assertFalse(dpms.isNotificationListenerServicePermitted(
                nonSystemPackage, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, MANAGED_PROFILE_USER_ID));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                nonSystemPackage, UserHandle.USER_SYSTEM));
        assertTrue(dpms.isNotificationListenerServicePermitted(
                systemListener, UserHandle.USER_SYSTEM));
    }

    public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setDeviceOwner();

        verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context);
    }

    public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);

        verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context);
        verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, mAdmin1Context);
    }

    public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
        mServiceContext.packageName = mRealTestContext.getPackageName();
        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
        setAsProfileOwner(admin1);

        final DpmMockContext caller = new DpmMockContext(getServices(), mRealTestContext);
        caller.packageName = "com.example.delegate";
        caller.binder.callingUid = setupPackageInPackageManager(caller.packageName,
                DpmMockContext.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);
    }

    public void testDisallowSharingIntoProfileSetRestriction() {
        Bundle restriction = new Bundle();
        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        RestrictionsListener listener = new RestrictionsListener(mContext);
        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, restriction,
                new Bundle());
        verifyDataSharingChangedBroadcast();
    }

    public void testDisallowSharingIntoProfileClearRestriction() {
        Bundle restriction = new Bundle();
        restriction.putBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, true);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        RestrictionsListener listener = new RestrictionsListener(mContext);
        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
                restriction);
        verifyDataSharingChangedBroadcast();
    }

    public void testDisallowSharingIntoProfileUnchanged() {
        RestrictionsListener listener = new RestrictionsListener(mContext);
        listener.onUserRestrictionsChanged(DpmMockContext.CALLER_USER_HANDLE, new Bundle(),
                new Bundle());
        verify(mContext.spiedContext, never()).sendBroadcastAsUser(any(), any());
    }

    private void verifyDataSharingChangedBroadcast() {
        Intent expectedIntent = new Intent(
                DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_CHANGED);
        expectedIntent.setPackage("com.android.managedprovisioning");
        expectedIntent.putExtra(Intent.EXTRA_USER_ID, DpmMockContext.CALLER_USER_HANDLE);
        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntent(expectedIntent),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
    }

    public void testOverrideApnAPIsFailWithPO() throws Exception {
        setupProfileOwner();
        ApnSetting apn = (new ApnSetting.Builder()).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);
            assertTrue(dpm.installCaCert(caller, caCert));
            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();

        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);
            assertEquals(Collections.singletonList(alias), installedCaCerts);
            ownerInstalledCaCerts.addAll(installedCaCerts);
        });

        // Restarting the DPMS should not lose information.
        initializeDpms();
        runAsCaller(admin1Context, dpms, (dpm) ->
                assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)));

        // System can find out which CA certs were installed by the Device Owner / Profile Owner.
        runAsCaller(serviceContext, dpms, (dpm) -> {
            assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser));

            // 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();

        // 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);
            assertTrue(dpm.installCaCert(callerName, caCert));
        });

        // 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();

        // 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);
            assertNotNull(ownerInstalledCaCerts);
            assertTrue(ownerInstalledCaCerts.isEmpty());
        });
    }

    private void assertAttestationFlags(int attestationFlags, int[] expectedFlags) {
        int[] gotFlags = DevicePolicyManagerService.translateIdAttestationFlags(attestationFlags);
        Arrays.sort(gotFlags);
        Arrays.sort(expectedFlags);
        assertTrue(Arrays.equals(expectedFlags, gotFlags));
    }

    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
        assertNull(DevicePolicyManagerService.translateIdAttestationFlags(0));

        // 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});
    }

    public void testRevertDeviceOwnership_noMetadataFile() throws Exception {
        setDeviceOwner();
        initializeDpms();
        assertFalse(getMockTransferMetadataManager().metadataFileExists());
        assertTrue(dpms.isDeviceOwner(admin1, UserHandle.USER_SYSTEM));
        assertTrue(dpms.isAdminActive(admin1, UserHandle.USER_SYSTEM));
    }

    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();
    }

    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();
    }

    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();
    }

    public void testRevertProfileOwnership_noMetadataFile() throws Exception {
        setupProfileOwner();
        initializeDpms();
        assertFalse(getMockTransferMetadataManager().metadataFileExists());
        assertTrue(dpms.isProfileOwner(admin1, DpmMockContext.CALLER_USER_HANDLE));
        assertTrue(dpms.isAdminActive(admin1, DpmMockContext.CALLER_USER_HANDLE));
        UserHandle userHandle = UserHandle.of(DpmMockContext.CALLER_USER_HANDLE);
    }

    public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception {
        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
                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();
    }

    public void testRevertProfileOwnership_profileNotMigrated() throws Exception {
        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
                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();
    }

    public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception {
        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
                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();
    }

    // admin1 is the outgoing DPC, adminAnotherPakcage 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();

        assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isDeviceOwnerApp(adminAnotherPackage.getPackageName()));
        assertFalse(dpm.isAdminActive(adminAnotherPackage));
        assertTrue(dpm.isAdminActive(admin1));
        assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
        assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());

        assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
        assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
        assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
        assertFalse(getMockTransferMetadataManager().metadataFileExists());

        mServiceContext.binder.restoreCallingIdentity(ident);
    }

    // admin1 is the outgoing DPC, adminAnotherPakcage is the incoming one.
    private void assertProfileOwnershipRevertedWithFakeTransferMetadata() throws Exception {
        writeFakeTransferMetadataFile(DpmMockContext.CALLER_USER_HANDLE,
                TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER);

        int uid = UserHandle.getUid(DpmMockContext.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();

        assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName()));
        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isProfileOwnerApp(adminAnotherPackage.getPackageName()));
        assertFalse(dpm.isAdminActive(adminAnotherPackage));
        assertEquals(dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE), admin1);
        assertFalse(getMockTransferMetadataManager().metadataFileExists());
    }

    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(DpmMockContext.CALLER_USER_HANDLE);
    }

    private File getProfileOwnerPoliciesFile() {
        File parentDir = dpms.mMockInjector.environmentGetUserSystemDirectory(
                DpmMockContext.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 InputStream getRawStream(@RawRes int id) {
        return mRealTestContext.getResources().openRawResource(id);
    }

    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) {
        assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
                dpm.isProvisioningAllowed(action));
    }

    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) {
        assertEquals("checkProvisioningPreCondition("
                        + action + ", " + packageName + ") returning unexpected result",
                provisioningCondition, dpm.checkProvisioningPreCondition(action, packageName));
    }

    /**
     * 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.
     */
    private void addManagedProfile(
            ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
        final int userId = UserHandle.getUserId(adminUid);
        getServices().addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM);
        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
        setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
        dpm.setActiveAdmin(admin, false, userId);
        assertTrue(dpm.setProfileOwner(admin, null, userId));
        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
    }

    /**
     * Convert String[] to StringParceledListSlice.
     */
    private static StringParceledListSlice asSlice(String[] s) {
        return new StringParceledListSlice(Arrays.asList(s));
    }

    private void flushTasks() throws Exception {
        dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/);
        dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/);

        // We can't let exceptions happen on the background thread. Throw them here if they happen
        // so they still cause the test to fail despite being suppressed.
        getServices().rethrowBackgroundBroadcastExceptions();
    }
}
