1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.am;
18
19import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
20import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertTrue;
24
25import android.content.ComponentName;
26import android.graphics.Rect;
27import android.platform.test.annotations.Presubmit;
28import android.support.test.filters.MediumTest;
29import android.support.test.runner.AndroidJUnit4;
30
31import org.junit.runner.RunWith;
32import org.junit.Test;
33
34import java.util.ArrayList;
35import java.util.Arrays;
36import java.util.List;
37
38import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
39
40/**
41 * Tests for the {@link ActivityStackSupervisor} class.
42 *
43 * Build/Install/Run:
44 *  bit FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests
45 */
46@MediumTest
47@Presubmit
48@RunWith(AndroidJUnit4.class)
49public class ActivityStackSupervisorTests extends ActivityTestsBase {
50    private final ComponentName testActivityComponent =
51            ComponentName.unflattenFromString("com.foo/.BarActivity");
52
53    /**
54     * This test ensures that we do not try to restore a task based off an invalid task id. The
55     * stack supervisor is a test version so there will be no tasks present. We should expect
56     * {@code null} to be returned in this case.
57     */
58    @Test
59    public void testRestoringInvalidTask() throws Exception {
60        final ActivityManagerService service = createActivityManagerService();
61        TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/,
62                MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/);
63        assertNull(task);
64    }
65
66    /**
67     * This test ensures that an existing task in the pinned stack is moved to the fullscreen
68     * activity stack when a new task is added.
69     */
70    @Test
71    public void testReplacingTaskInPinnedStack() throws Exception {
72        final ActivityManagerService service = createActivityManagerService();
73        final TaskRecord firstTask = createTask(service, testActivityComponent,
74                FULLSCREEN_WORKSPACE_STACK_ID);
75        final ActivityRecord firstActivity = createActivity(service, testActivityComponent,
76                firstTask);
77        // Create a new task on the full screen stack
78        final TaskRecord secondTask = createTask(service, testActivityComponent,
79                FULLSCREEN_WORKSPACE_STACK_ID);
80        final ActivityRecord secondActivity = createActivity(service, testActivityComponent,
81                secondTask);
82        service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack",
83                service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID));
84
85        // Ensure full screen stack has both tasks.
86        ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask,
87                secondTask);
88
89        // Move first activity to pinned stack.
90        service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity,
91                new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove");
92
93        // Ensure a task has moved over.
94        ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask);
95        ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask);
96
97        // Move second activity to pinned stack.
98        service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity,
99                new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove");
100
101        // Ensure stacks have swapped tasks.
102        ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask);
103        ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask);
104    }
105
106    private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId,
107            TaskRecord... tasks) {
108        final ActivityStack stack = supervisor.getStack(stackId);
109        final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
110        assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
111
112        if (tasks == null) {
113            return;
114        }
115
116        for (TaskRecord task : tasks) {
117            assertTrue(stackTasks.contains(task));
118        }
119    }
120}
121