/*
 * Copyright (C) 2016 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.cts.managedprofile;

import static org.testng.Assert.assertThrows;

import android.app.admin.DevicePolicyManager;
import android.util.Log;

import com.google.common.collect.ImmutableSet;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Tests related to the parent profile of a managed profile.
 *
 * The parent profile is obtained by
 * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
 */
public class ParentProfileTest extends BaseManagedProfileTest {

    /**
     * An allowlist of public API methods in {@link android.app.admin.DevicePolicyManager}
     * that are supported on a parent profile.
     */
    private static final ImmutableSet<String> SUPPORTED_APIS = new ImmutableSet.Builder<String>()
            .add("getPasswordQuality")
            .add("setPasswordQuality")
            .add("getPasswordMinimumLength")
            .add("setPasswordMinimumLength")
            .add("getPasswordMinimumUpperCase")
            .add("setPasswordMinimumUpperCase")
            .add("getPasswordMinimumLowerCase")
            .add("setPasswordMinimumLowerCase")
            .add("getPasswordMinimumLetters")
            .add("setPasswordMinimumLetters")
            .add("getPasswordMinimumNumeric")
            .add("setPasswordMinimumNumeric")
            .add("getPasswordMinimumSymbols")
            .add("setPasswordMinimumSymbols")
            .add("getPasswordMinimumNonLetter")
            .add("setPasswordMinimumNonLetter")
            .add("getPasswordHistoryLength")
            .add("setPasswordHistoryLength")
            .add("getPasswordExpirationTimeout")
            .add("setPasswordExpirationTimeout")
            .add("getPasswordExpiration")
            .add("getPasswordMaximumLength")
            .add("getPasswordComplexity")
            .add("getRequiredPasswordComplexity")
            .add("setRequiredPasswordComplexity")
            .add("setCameraDisabled")
            .add("getCameraDisabled")
            .add("isActivePasswordSufficient")
            .add("isActivePasswordSufficientForDeviceRequirement")
            .add("getCurrentFailedPasswordAttempts")
            .add("getMaximumFailedPasswordsForWipe")
            .add("setMaximumFailedPasswordsForWipe")
            .add("getMaximumTimeToLock")
            .add("setMaximumTimeToLock")
            .add("lockNow")
            .add("getKeyguardDisabledFeatures")
            .add("setKeyguardDisabledFeatures")
            .add("getTrustAgentConfiguration")
            .add("setTrustAgentConfiguration")
            .add("getRequiredStrongAuthTimeout")
            .add("setRequiredStrongAuthTimeout")
            .add("isDeviceIdAttestationSupported")
            .add("isUniqueDeviceAttestationSupported")
            .add("wipeData")
            .add("getAutoTimeEnabled")
            .add("setAutoTimeEnabled")
            .add("addUserRestriction")
            .add("clearUserRestriction")
            .add("getUserRestrictions")
            .add("setApplicationHidden")
            .add("isApplicationHidden")
            .add("setScreenCaptureDisabled")
            .add("getScreenCaptureDisabled")
            .add("getAccountTypesWithManagementDisabled")
            .add("setAccountManagementDisabled")
            .add("setDefaultSmsApplication")
            .add("getPermittedInputMethods")
            .add("setPermittedInputMethods")
            .build();

    private static final String LOG_TAG = "ParentProfileTest";

    private static final String PACKAGE_NAME = DevicePolicyManager.class.getPackage().getName();
    private static final String CLASS_NAME = DevicePolicyManager.class.getSimpleName();

    /**
     * Verify that all public API methods of {@link android.app.admin.DevicePolicyManager},
     * except those explicitly allowed in {@link #SUPPORTED_APIS},
     * throw a {@link SecurityException} when called on a parent profile.
     *
     * <p><b>Note:</b> System API methods (i.e. those with the
     * {@link android.annotation.SystemApi} annotation) are NOT tested.
     */
    public void testParentProfileApiDisabled() throws Exception {
        List<Method> methods = CurrentApiHelper.getPublicApis(PACKAGE_NAME, CLASS_NAME);
        assertValidMethodNames(SUPPORTED_APIS, methods);

        ArrayList<String> failedMethods = new ArrayList<String>();

        for (Method method : methods) {
            String methodName = method.getName();
            if (SUPPORTED_APIS.contains(methodName)) {
                continue;
            }

            try {
                int paramCount = method.getParameterCount();
                Object[] params = new Object[paramCount];
                Class[] paramTypes = method.getParameterTypes();
                for (int i = 0; i < paramCount; ++i) {
                    params[i] = CurrentApiHelper.instantiate(paramTypes[i]);
                }
                method.invoke(mParentDevicePolicyManager, params);

            } catch (InvocationTargetException e) {
                if (e.getCause() instanceof SecurityException) {
                    // Method throws SecurityException as expected
                    continue;
                } else {
                    Log.e(LOG_TAG,
                            methodName + " throws exception other than SecurityException.", e);
                }
            }

            // Either no exception is thrown, or the exception thrown is not a SecurityException
            failedMethods.add(methodName);
            Log.e(LOG_TAG, methodName + " failed to throw SecurityException");
        }

        assertTrue("Some method(s) failed to throw SecurityException: " + failedMethods,
                failedMethods.isEmpty());
    }

    private void assertValidMethodNames(Collection<String> names, Collection<Method> allMethods) {
        Set<String> allNames = allMethods.stream()
                .map(Method::getName)
                .collect(Collectors.toSet());

        for (String name : names) {
            assertTrue(name + " is not found in the API list", allNames.contains(name));
        }
    }

    public void testCannotWipeParentProfile() {
        assertThrows(SecurityException.class,
                () -> mParentDevicePolicyManager.wipeData(0));
    }

    public void testCannotCallAutoTimeMethodsOnParentProfile() {
        assertThrows(SecurityException.class,
                () -> mParentDevicePolicyManager.setAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT,
                        true));

        assertThrows(SecurityException.class,
                () -> mParentDevicePolicyManager.getAutoTimeEnabled(ADMIN_RECEIVER_COMPONENT));
    }

    public void testCannotCallSetDefaultSmsApplicationOnParentProfile() {
        String messagesPackageName = "com.google.android.apps.messaging";
        assertThrows(SecurityException.class,
                () -> mParentDevicePolicyManager.setDefaultSmsApplication(ADMIN_RECEIVER_COMPONENT,
                        messagesPackageName));
    }

}
