/*
 * Copyright (C) 2019 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 android.app.cts;

import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OPSTR_CAMERA;
import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_TOP;

import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;

import static org.junit.Assert.assertEquals;

import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOp;
import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.HistoricalOpsRequest;
import android.app.Instrumentation;
import android.app.cts.android.app.cts.tools.WaitForBroadcast;
import android.app.cts.android.app.cts.tools.WatchUidRunner;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.permission.cts.PermissionUtils;
import android.provider.DeviceConfig;
import android.provider.Settings;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * AppOpsManager.MODE_FOREGROUND is introduced in API level 29. This test class specifically tests
 * ActivityManagerService's interaction with AppOpsService regarding MODE_FOREGROUND operation.
 * If an operation's mode is MODE_FOREGROUND, this operation is allowed only when the process is in
 * one of the foreground state (including foreground_service state), this operation will be denied
 * when the process is in background state.
 */
@RunWith(AndroidJUnit4.class)
//@Suppress
public class ActivityManagerApi29Test {
    private static final String PACKAGE_NAME = "android.app.cts.activitymanager.api29";
    private static final String SIMPLE_ACTIVITY = ".SimpleActivity";
    private static final String ACTION_SIMPLE_ACTIVITY_START_RESULT =
            "android.app.cts.activitymanager.api29.SimpleActivity.RESULT";
    private static final String ACTION_SERVICE_START_RESULT =
            "android.app.cts.activitymanager.api29.LocationForegroundService.RESULT";
    private static final String SERVICE_NAME = ".LocationForegroundService";
    private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
    private static final int WAITFOR_MSEC = 10000;
    private static final int NOTEOP_COUNT = 5;

    //TODO: remove this when development is done.
    private static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;

    private static final Instrumentation sInstrumentation =
            InstrumentationRegistry.getInstrumentation();
    private static final Context sContext = sInstrumentation.getContext();
    private static final Context sTargetContext = sInstrumentation.getTargetContext();
    private static final AppOpsManager sAppOps =
            (AppOpsManager) sContext.getSystemService(AppOpsManager.class);
    private static Intent sActivityIntent;
    private static Intent sServiceIntent = new Intent().setClassName(
            PACKAGE_NAME, PACKAGE_NAME + SERVICE_NAME);
    private static int sUid;
    static {
        try {
            sUid = sContext.getPackageManager().getApplicationInfo(PACKAGE_NAME, 0).uid;
        } catch (NameNotFoundException e) {
            throw new RuntimeException("NameNotFoundException:" + e);
        }
    }

    private String mOldAppOpsSettings;
    private boolean mWasPermissionsHubEnabled = false;
    private WatchUidRunner mUidWatcher;

    @Before
    public void setUp() throws Exception {
        CtsAppTestUtils.turnScreenOn(sInstrumentation, sContext);
        CtsAppTestUtils.makeUidIdle(sInstrumentation, PACKAGE_NAME);
        // PACKAGE_NAME's targetSdkVersion is 29, when ACCESS_COARSE_LOCATION is granted, appOp is
        // MODE_FOREGROUND (In API level lower than 29, appOp is MODE_ALLOWED).
        assertEquals(MODE_FOREGROUND,
                PermissionUtils.getAppOp(PACKAGE_NAME, ACCESS_COARSE_LOCATION));
        runWithShellPermissionIdentity(()-> {
            mOldAppOpsSettings = Settings.Global.getString(sContext.getContentResolver(),
                    Settings.Global.APP_OPS_CONSTANTS);
            Settings.Global.putString(sContext.getContentResolver(),
                    Settings.Global.APP_OPS_CONSTANTS,
                    "top_state_settle_time=0,fg_service_state_settle_time=0,"
                    + "bg_state_settle_time=0");
            mWasPermissionsHubEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                    PROPERTY_PERMISSIONS_HUB_ENABLED, false);
            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
                    PROPERTY_PERMISSIONS_HUB_ENABLED, Boolean.toString(true), false);
            sAppOps.clearHistory();
            sAppOps.resetHistoryParameters(); }
        );
        mUidWatcher = new WatchUidRunner(sInstrumentation, sUid, WAITFOR_MSEC);
    }

    @After
    public void tearDown() throws Exception {
        CtsAppTestUtils.makeUidIdle(sInstrumentation, PACKAGE_NAME);
        runWithShellPermissionIdentity(() -> {
            // restore old AppOps settings.
            Settings.Global.putString(sContext.getContentResolver(),
                    Settings.Global.APP_OPS_CONSTANTS, mOldAppOpsSettings);
            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
                    PROPERTY_PERMISSIONS_HUB_ENABLED, Boolean.toString(mWasPermissionsHubEnabled),
                    false);
            sAppOps.clearHistory();
            sAppOps.resetHistoryParameters(); }
        );
        mUidWatcher.finish();
    }

    private void startSimpleActivity() {
        sActivityIntent = new Intent(Intent.ACTION_MAIN)
                .setClassName(PACKAGE_NAME, PACKAGE_NAME + SIMPLE_ACTIVITY)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        sTargetContext.startActivity(sActivityIntent);
    }

    private void stopSimpleActivity() {
        sActivityIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                .putExtra("finish", true);
        sTargetContext.startActivity(sActivityIntent);
    }

    private void startSimpleService() {
        sTargetContext.startForegroundService(sServiceIntent);
    }

    private void stopSimpleService() {
        sTargetContext.stopService(sServiceIntent);
    }

    /**
     * This tests app in PROCESS_STATE_TOP state can have location access.
     * The app's permission is AppOpsManager.MODE_FOREGROUND. If the process is in PROCESS_STATE_TOP
     * , even its capability is zero, it still has location access.
     * @throws Exception
     */
    @Test
    public void testTopActivityWithAppOps() throws Exception {
        startSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP,
                new Integer(PROCESS_CAPABILITY_ALL));

        // AppOps location access should be allowed.
        assertEquals(MODE_ALLOWED, noteOp(OPSTR_COARSE_LOCATION));

        stopSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
                new Integer(PROCESS_CAPABILITY_NONE));

        // AppOps location access should be denied.
        assertEquals(MODE_IGNORED, noteOp(OPSTR_COARSE_LOCATION));
    }

    /**
     * When ActivityManagerService process states and capability changes, it updates AppOpsService.
     * This test starts a foreground service with location type, it updates AppOpsService with
     * PROCESS_STATE_FOREGROUND_SERVICE and PROCESS_CAPABILITY_FOREGROUND_LOCATION, then check if
     * AppOpsManager allow ACCESS_COARSE_LOCATION of MODE_FOREGROUND.
     *
     * The "android.app.cts.activitymanager.api29" package's targetSdkVersion is 29.
     * @throws Exception
     */
    @Test
    public void testFgsLocationWithAppOps() throws Exception {
        // Start a foreground service with location
        startSimpleService();
        // Wait for state and capability change.
        // BG started FGS does not have location capability.
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
                new Integer(DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION));

        startSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP,
                new Integer(PROCESS_CAPABILITY_ALL));

        // AppOps location access should be allowed.
        assertEquals(MODE_ALLOWED, noteOp(OPSTR_COARSE_LOCATION));

        stopSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
                new Integer(DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION));

        // AppOps location access should be denied.
        assertEquals(MODE_IGNORED, noteOp(OPSTR_COARSE_LOCATION));

        stopSimpleService();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
                new Integer(PROCESS_CAPABILITY_NONE));

        // AppOps location access should be denied.
        assertEquals(MODE_IGNORED, noteOp(OPSTR_COARSE_LOCATION));
    }

    /**
     * After calling AppOpsManager.noteOp() interface multiple times in different process states,
     * this test calls AppOpsManager.getHistoricalOps() and check the access count and reject count
     * in HistoricalOps.
      *
     * @throws Exception
     */
    @Test
    public void testAppOpsHistoricalOps() throws Exception {
        runWithShellPermissionIdentity(
                () ->  sAppOps.setHistoryParameters(AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE,
                        1000, 10)
        );
        WaitForBroadcast waiter = new WaitForBroadcast(sInstrumentation.getTargetContext());
        waiter.prepare(ACTION_SIMPLE_ACTIVITY_START_RESULT);
        startSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP,
                new Integer(PROCESS_CAPABILITY_ALL));
        waiter.doWait(WAITFOR_MSEC);

        waiter = new WaitForBroadcast(sInstrumentation.getTargetContext());
        waiter.prepare(ACTION_SERVICE_START_RESULT);
        startSimpleService();
        waiter.doWait(WAITFOR_MSEC);

        for (int i = 0; i < NOTEOP_COUNT; i++) {
            noteOp(OPSTR_COARSE_LOCATION);
        }

        stopSimpleActivity();
        // The callingPackage to start FGS is in background.
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
                new Integer(DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION));
        for (int i = 0; i < NOTEOP_COUNT; i++) {
            noteOp(OPSTR_COARSE_LOCATION);
        }
        stopSimpleService();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
                new Integer(PROCESS_CAPABILITY_NONE));

        for (int i = 0; i < NOTEOP_COUNT; i++) {
            noteOp(OPSTR_COARSE_LOCATION);
        }
        runWithShellPermissionIdentity(() -> {
            CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
            HistoricalOpsRequest histOpsRequest = new HistoricalOpsRequest.Builder(
                    Instant.now().minus(1, ChronoUnit.HOURS).toEpochMilli(),
                    Long.MAX_VALUE)
                    .setUid(sUid)
                    .setPackageName(PACKAGE_NAME)
                    .setOpNames(Arrays.asList(OPSTR_COARSE_LOCATION))
                    .setFlags(OP_FLAGS_ALL)
                    .build();
            sAppOps.getHistoricalOps(histOpsRequest, sContext.getMainExecutor(), ops::complete);
            HistoricalOp hOp = ops.get(5000, TimeUnit.MILLISECONDS)
                    .getUidOps(sUid).getPackageOps(PACKAGE_NAME)
                    .getOp(OPSTR_COARSE_LOCATION);
            assertEquals(NOTEOP_COUNT, hOp.getAccessCount(UID_STATE_TOP,
                    UID_STATE_FOREGROUND_SERVICE, AppOpsManager.OP_FLAGS_ALL));
            assertEquals(NOTEOP_COUNT, hOp.getForegroundAccessCount(OP_FLAGS_ALL));
            assertEquals(NOTEOP_COUNT, hOp.getForegroundRejectCount(OP_FLAGS_ALL));
            assertEquals(0, hOp.getBackgroundAccessCount(OP_FLAGS_ALL));
            // denied access one time in background.
            assertEquals(NOTEOP_COUNT, hOp.getBackgroundRejectCount(OP_FLAGS_ALL)); }
        );
    }

    /**
     * Only FGS started by TOP app can have OP_CAMERA and OP_RECORD_AUDIO.
     * @throws Exception
     */
    @Test
    public void testCameraWithAppOps() throws Exception {
        startSimpleService();
        // Wait for state and capability change.
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
                new Integer(DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION));

        // Non-Top started FGS do not have while-in-use permission, camera/microphone access is
        // denied.
        assertEquals(MODE_IGNORED, noteOp(OPSTR_CAMERA));
        assertEquals(MODE_IGNORED, noteOp(OPSTR_RECORD_AUDIO));

        // Start an activity, put app in TOP.
        startSimpleActivity();
        // TOP process has all capabilities.
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP,
                new Integer(PROCESS_CAPABILITY_ALL));

        // Camera/microphone access is allowed because the app is TOP.
        assertEquals(MODE_ALLOWED, noteOp(OPSTR_CAMERA));
        assertEquals(MODE_ALLOWED, noteOp(OPSTR_RECORD_AUDIO));

        // Tell the activity to finalize.
        stopSimpleActivity();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_FG_SERVICE,
                new Integer(DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION));

        // App not in Top, camera/microphone access should be denied.
        assertEquals(MODE_IGNORED, noteOp(OPSTR_CAMERA));
        assertEquals(MODE_IGNORED, noteOp(OPSTR_RECORD_AUDIO));

        // Stop the foreground service.
        stopSimpleService();
        mUidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY,
                new Integer(PROCESS_CAPABILITY_NONE));

        assertEquals(MODE_IGNORED, noteOp(OPSTR_CAMERA));
        assertEquals(MODE_IGNORED, noteOp(OPSTR_RECORD_AUDIO));
    }

    private int noteOp(String opStr) throws Exception {
        return callWithShellPermissionIdentity(
                () -> sAppOps.noteOp(opStr, sUid, PACKAGE_NAME,
                        opStr, ""));
    }
}
