/*
 * Copyright (C) 2020 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.car.am;

import static android.car.test.mocks.AndroidMockitoHelper.mockAmGetCurrentUser;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.car.hardware.power.CarPowerManager;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.view.Display;

import com.android.car.CarLocalServices;
import com.android.car.CarServiceUtils;
import com.android.car.user.CarUserService;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.stubbing.OngoingStubbing;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public final class FixedActivityServiceTest extends AbstractExtendedMockitoTestCase {

    private static final long RECHECK_INTERVAL_MARGIN_MS = 600;

    private final int mValidDisplayId = 1;

    @Mock
    private Context mContext;
    @Mock
    private IActivityManager mActivityManager;
    @Mock
    private IActivityTaskManager mActivityTaskManager;
    @Mock
    private UserManager mUserManager;
    @Mock
    private DisplayManager mDisplayManager;
    @Mock
    private PackageManager mPackageManager;
    @Mock
    private CarUserService mCarUserService;
    @Mock
    private CarPowerManager mCarPowerManager;

    private FixedActivityService mFixedActivityService;

    @Override
    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
        builder
            .spyStatic(ActivityManager.class)
            .spyStatic(CarLocalServices.class);
    }

    @Before
    public void setUp() {
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        doReturn(mCarUserService).when(() -> CarLocalServices.getService(CarUserService.class));
        doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mContext));
        mFixedActivityService = new FixedActivityService(mContext, mActivityManager,
                mActivityTaskManager, mUserManager, mDisplayManager);
    }

    @After
    public void tearDown() {
        if (mFixedActivityService != null) {
            mFixedActivityService.release();
        }
        CarServiceUtils.finishAllHandlerTasks();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_noRunningActivity()
            throws Exception {
        int userId = 10;
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);
        expectNoActivityStack();

        // No running activities
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_alreadyRunningActivity()
            throws Exception {
        int userId = 10;
        int[] userIds = new int[] { userId };
        int[] taskIds = new int[] { 1234 };
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(
                createEmptyStackInfo(),
                createStackInfoList(intent, userIds, mValidDisplayId, taskIds)
        );

        // No running activities
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();

        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        // startActivityAsUser should not called at this time. So, total called count is 1.
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_runNewActivity() throws Exception {
        int userId = 10;
        int[] userIds = new int[] { userId };
        int[] taskIds = new int[] { 1234 };
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
                userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(
                createEmptyStackInfo(),
                createStackInfoList(intent, userIds, mValidDisplayId, taskIds)
        );

        // No running activities
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        assertThat(ret).isTrue();

        // Start activity with new package
        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
                options, mValidDisplayId, userId);
        verify(mContext).startActivityAsUser(eq(anotherIntent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();
    }

    @Test
    public void testStartFixedActivityModeForDisplay_relaunchWithPackageUpdated() throws Exception {
        int userId = 10;
        int[] userIds = new int[] { userId };
        int[] taskIds = new int[] { 1234 };
        String packageName = "test_package";
        String className = "com.test.dude";
        ActivityOptions options = new ActivityOptions(new Bundle());
        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        Intent intent = expectComponentAvailable(packageName, className, userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(
                createEmptyStackInfo(),
                createStackInfoList(intent, userIds, mValidDisplayId, taskIds)
        );

        // No running activities
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        verify(mContext).registerReceiverAsUser(receiverCaptor.capture(), eq(UserHandle.ALL),
                any(IntentFilter.class), eq(null), eq(null));
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();

        // Update package
        SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
        int appId = 987;
        BroadcastReceiver receiver = receiverCaptor.getValue();
        Intent packageIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
        packageIntent.setData(new Uri.Builder().path(packageName).build());
        packageIntent.putExtra(Intent.EXTRA_UID, UserHandle.getUid(userId, appId));
        receiver.onReceive(mContext, packageIntent);
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));

        SystemClock.sleep(RECHECK_INTERVAL_MARGIN_MS);
        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        // Activity should not be launched.
        verify(mContext).startActivityAsUser(eq(intent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();
    }


    @Test
    public void testStartFixedActivityModeForDisplayAndUser_runOnDifferentDisplay()
            throws Exception {
        int userId = 10;
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        Intent anotherIntent = expectComponentAvailable("test_package_II", "com.test.dude_II",
                userId);
        mockAmGetCurrentUser(userId);
        expectNoActivityStack();

        // No running activities
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        assertThat(ret).isTrue();

        int anotherValidDisplayId = mValidDisplayId + 1;
        ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(anotherIntent,
                options, anotherValidDisplayId, userId);
        verify(mContext).startActivityAsUser(eq(anotherIntent), any(Bundle.class),
                eq(UserHandle.of(userId)));
        assertThat(ret).isTrue();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_invalidDisplay() {
        int userId = 10;
        Intent intent = new Intent(Intent.ACTION_MAIN);
        ActivityOptions options = new ActivityOptions(new Bundle());
        int invalidDisplayId = Display.DEFAULT_DISPLAY;

        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
                invalidDisplayId, userId);
        assertThat(ret).isFalse();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_notAllowedUser() {
        int currentUserId = 10;
        int notAllowedUserId = 11;
        Intent intent = new Intent(Intent.ACTION_MAIN);
        ActivityOptions options = new ActivityOptions(new Bundle());
        int displayId = mValidDisplayId;
        mockAmGetCurrentUser(currentUserId);
        expectNoProfileUser(currentUserId);

        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent, options,
                displayId, notAllowedUserId);
        assertThat(ret).isFalse();
    }

    @Test
    public void testStartFixedActivityModeForDisplayAndUser_invalidComponent() throws Exception {
        int userId = 10;
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent invalidIntent = expectComponentUnavailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);

        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(invalidIntent,
                options, mValidDisplayId, userId);
        assertThat(ret).isFalse();
    }

    @Test
    public void testStopFixedActivityMode() throws Exception {
        int userId = 10;
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);
        expectNoActivityStack();

        // Start an activity
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        // To check if monitoring is started.
        verify(mActivityManager).registerTaskStackListener(any(TaskStackListener.class));
        assertThat(ret).isTrue();

        mFixedActivityService.stopFixedActivityMode(mValidDisplayId);
        verify(mActivityManager).unregisterTaskStackListener(any(TaskStackListener.class));
    }

    @Test
    public void testStopFixedActivityMode_invalidDisplayId() throws Exception {
        mFixedActivityService.stopFixedActivityMode(Display.DEFAULT_DISPLAY);
        verify(mActivityManager, never()).unregisterTaskStackListener(any(TaskStackListener.class));
    }

    @Test
    public void testHandleTaskFocusChanged_returnForcusBack() throws Exception {
        int userId = 10;
        int testTaskId = 1234;
        int[] userIds = new int[]{userId};
        int[] taskIds = new int[]{testTaskId};
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(createStackInfoList(intent, userIds, mValidDisplayId, taskIds));

        // Make FixedActivityService to update the taskIds.
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        assertThat(ret).isTrue();

        Intent homeIntent = expectComponentAvailable("home", "homeActivity", userId);
        int homeTaskId = 4567;
        when(mActivityTaskManager.getAllStackInfosOnDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
                createStackInfoList(
                        homeIntent, userIds, Display.DEFAULT_DISPLAY, new int[]{homeTaskId}));

        mFixedActivityService.handleTaskFocusChanged(testTaskId, true);

        verify(mActivityTaskManager).setFocusedTask(homeTaskId);
    }

    // If there are two tasks in one display id, then there is a bug to invalidate
    // RunningActivityInfo.taskId examining 2nd task and it prevents from checking FixedActivity
    // in handleTaskFocusChanged(). This test makes sure if the bug doesn't exist.
    @Test
    public void testHandleTaskFocusChanged_returnForcusBackInTwoStackInfos() throws Exception {
        int userId = 10;
        int testTaskId = 1234;
        int[] userIds = new int[]{userId};
        int[] taskIds = new int[]{testTaskId};
        int[] taskIds2 = new int[]{testTaskId + 1111};
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        Intent intent2 = expectComponentAvailable("test_package2", "com.test.others", userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(Arrays.asList(
                createStackInfo(intent, userIds, mValidDisplayId, taskIds),
                createStackInfo(intent2, userIds, mValidDisplayId, taskIds2)));

        // Make FixedActivityService to update the taskIds.
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        assertThat(ret).isTrue();

        Intent homeIntent = expectComponentAvailable("home", "homeActivity", userId);
        int homeTaskId = 4567;
        when(mActivityTaskManager.getAllStackInfosOnDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
                createStackInfoList(
                        homeIntent, userIds, Display.DEFAULT_DISPLAY, new int[]{homeTaskId}));

        mFixedActivityService.handleTaskFocusChanged(testTaskId, true);

        verify(mActivityTaskManager).setFocusedTask(homeTaskId);
    }

    @Test
    public void testHandleTaskFocusChanged_noForcusBack() throws Exception {
        int userId = 10;
        int testTaskId = 1234;
        int[] userIds = new int[]{userId};
        int[] taskIds = new int[]{testTaskId};
        ActivityOptions options = new ActivityOptions(new Bundle());
        Intent intent = expectComponentAvailable("test_package", "com.test.dude", userId);
        mockAmGetCurrentUser(userId);
        expectActivityStackInfo(createStackInfoList(intent, userIds, mValidDisplayId, taskIds));

        // Make FixedActivityService to update the taskIds.
        boolean ret = mFixedActivityService.startFixedActivityModeForDisplayAndUser(intent,
                options, mValidDisplayId, userId);
        assertThat(ret).isTrue();

        mFixedActivityService.handleTaskFocusChanged(testTaskId + 1, true);

        verify(mActivityTaskManager, never()).setFocusedTask(anyInt());
    }

    private void expectNoProfileUser(@UserIdInt int userId) {
        when(mUserManager.getEnabledProfileIds(userId)).thenReturn(new int[0]);
    }

    private Intent expectComponentUnavailable(String pkgName, String className,
            @UserIdInt int userId) throws Exception {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        ComponentName component = new ComponentName(pkgName, className);
        intent.setComponent(component);
        ActivityInfo activityInfo = new ActivityInfo();
        // To make sure there is no matched activity
        activityInfo.name = component.getClassName() + ".unavailable";
        PackageInfo packageInfo = new PackageInfo();
        packageInfo.activities = new ActivityInfo[] { activityInfo };
        when(mPackageManager.getPackageInfoAsUser(component.getPackageName(),
                PackageManager.GET_ACTIVITIES, userId)).thenReturn(packageInfo);
        return intent;
    }

    private Intent expectComponentAvailable(String pkgName, String className, @UserIdInt int userId)
            throws Exception {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        ComponentName component = new ComponentName(pkgName, className);
        intent.setComponent(component);
        ActivityInfo activityInfo = new ActivityInfo();
        activityInfo.name = component.getClassName();
        PackageInfo packageInfo = new PackageInfo();
        packageInfo.activities = new ActivityInfo[] { activityInfo };
        when(mPackageManager.getPackageInfoAsUser(component.getPackageName(),
                PackageManager.GET_ACTIVITIES, userId)).thenReturn(packageInfo);
        return intent;
    }

    private void expectNoActivityStack() throws Exception {
        when(mActivityManager.getAllStackInfos()).thenReturn(createEmptyStackInfo());
    }

    private void expectActivityStackInfo(List<StackInfo> ...stackInfos) throws Exception {
        OngoingStubbing<List<StackInfo>> stub = when(mActivityManager.getAllStackInfos());
        for (List<StackInfo> stackInfo : stackInfos) {
            stub = stub.thenReturn(stackInfo);
        }
    }

    private List<StackInfo> createEmptyStackInfo() {
        return new ArrayList<StackInfo>();
    }

    private StackInfo createStackInfo(Intent intent, @UserIdInt int[] userIds, int displayId,
            int[] taskIds) {
        StackInfo stackInfo = new StackInfo();
        stackInfo.taskUserIds = userIds;
        stackInfo.topActivity = intent.getComponent().clone();
        stackInfo.visible = true;
        stackInfo.displayId = displayId;
        stackInfo.taskIds = taskIds;
        return stackInfo;
    }

    private List<StackInfo> createStackInfoList(Intent intent, @UserIdInt int[] userIds,
            int displayId, int[] taskIds) {
        return Arrays.asList(createStackInfo(intent, userIds, displayId, taskIds));
    }
}
