• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package android.server.wm;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
20 import static android.server.wm.WindowManagerState.STATE_RESUMED;
21 import static android.server.wm.WindowManagerState.STATE_STOPPED;
22 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
23 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
24 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 import static com.google.common.truth.Truth.assertWithMessage;
28 
29 import android.app.Activity;
30 import android.content.ComponentName;
31 import android.content.Intent;
32 import android.graphics.Rect;
33 import android.os.Binder;
34 import android.os.Bundle;
35 import android.os.IBinder;
36 import android.platform.test.annotations.Presubmit;
37 import android.server.wm.WindowManagerState.Task;
38 import android.server.wm.WindowManagerState.TaskFragment;
39 import android.window.TaskFragmentCreationParams;
40 import android.window.TaskFragmentInfo;
41 import android.window.TaskFragmentOrganizer;
42 import android.window.WindowContainerTransaction;
43 
44 import com.android.compatibility.common.util.ApiTest;
45 
46 import org.junit.Test;
47 
48 /**
49  * Tests that verify the behavior of {@link TaskFragmentOrganizer}.
50  *
51  * Build/Install/Run:
52  *     atest CtsWindowManagerDeviceTestCases:TaskFragmentOrganizerTest
53  */
54 @Presubmit
55 @android.server.wm.annotation.Group2
56 public class TaskFragmentOrganizerTest extends TaskFragmentOrganizerTestBase {
57     private final ComponentName mLaunchingActivity = new ComponentName(mContext,
58             WindowMetricsActivityTests.MetricsActivity.class);
59 
60     /**
61      * Verifies the behavior of
62      * {@link WindowContainerTransaction#createTaskFragment(TaskFragmentCreationParams)} to create
63      * TaskFragment.
64      */
65     @Test
testCreateTaskFragment()66     public void testCreateTaskFragment() {
67         mWmState.computeState(mOwnerActivityName);
68         Task parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
69         final int originalTaskFragCount = parentTask.getTaskFragments().size();
70 
71         final IBinder taskFragToken = new Binder();
72         final Rect bounds = new Rect(0, 0, 1000, 1000);
73         final int windowingMode = WINDOWING_MODE_MULTI_WINDOW;
74         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
75                 mTaskFragmentOrganizer.getOrganizerToken(), taskFragToken, mOwnerToken)
76                 .setInitialRelativeBounds(bounds)
77                 .setWindowingMode(windowingMode)
78                 .build();
79         final WindowContainerTransaction wct = new WindowContainerTransaction()
80                 .createTaskFragment(params);
81         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_OPEN,
82                 false /* shouldApplyIndependently */);
83 
84         mTaskFragmentOrganizer.waitForTaskFragmentCreated();
85 
86         final TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
87 
88         assertEmptyTaskFragment(info, taskFragToken);
89         assertThat(info.getConfiguration().windowConfiguration.getBounds()).isEqualTo(bounds);
90         assertThat(info.getWindowingMode()).isEqualTo(windowingMode);
91 
92         mWmState.computeState(mOwnerActivityName);
93         parentTask = mWmState.getRootTask(mOwnerActivity.getTaskId());
94         final int curTaskFragCount = parentTask.getTaskFragments().size();
95 
96         assertWithMessage("There must be a TaskFragment created under Task#"
97                 + mOwnerTaskId).that(curTaskFragCount - originalTaskFragCount)
98                 .isEqualTo(1);
99     }
100 
101     /**
102      * Verifies the behavior of
103      * {@link WindowContainerTransaction#reparentActivityToTaskFragment(IBinder, IBinder)} to
104      * reparent {@link Activity} to TaskFragment.
105      */
106     @Test
testReparentActivity()107     public void testReparentActivity() {
108         mWmState.computeState(mOwnerActivityName);
109 
110         final TaskFragmentCreationParams params = generateTaskFragCreationParams();
111         final IBinder taskFragToken = params.getFragmentToken();
112         final WindowContainerTransaction wct = new WindowContainerTransaction()
113                 .createTaskFragment(params)
114                 .reparentActivityToTaskFragment(taskFragToken, mOwnerToken);
115         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_CHANGE,
116                 false /* shouldApplyIndependently */);
117 
118         mTaskFragmentOrganizer.waitForTaskFragmentCreated();
119 
120         assertNotEmptyTaskFragment(mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken),
121                 taskFragToken, mOwnerToken);
122 
123         mWmState.waitForActivityState(mOwnerActivityName, STATE_RESUMED);
124 
125         final Task parentTask = mWmState.getTaskByActivity(mOwnerActivityName);
126         final TaskFragment taskFragment = mWmState.getTaskFragmentByActivity(mOwnerActivityName);
127 
128         // Assert window hierarchy must be as follows
129         // - owner Activity's Task (parentTask)
130         //   - taskFragment
131         //     - owner Activity
132         assertWindowHierarchy(parentTask, taskFragment, mWmState.getActivity(mOwnerActivityName));
133     }
134 
135     /**
136      * Verifies the behavior of
137      * {@link WindowContainerTransaction#startActivityInTaskFragment(IBinder, IBinder, Intent,
138      * Bundle)} to start Activity in TaskFragment without creating new Task.
139      */
140     @Test
testStartActivityInTaskFragment_reuseTask()141     public void testStartActivityInTaskFragment_reuseTask() {
142         final TaskFragmentCreationParams params = generateTaskFragCreationParams();
143         final IBinder taskFragToken = params.getFragmentToken();
144         final WindowContainerTransaction wct = new WindowContainerTransaction()
145                 .createTaskFragment(params)
146                 .startActivityInTaskFragment(taskFragToken, mOwnerToken,
147                         new Intent().setComponent(mLaunchingActivity), null /* activityOptions */);
148         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_OPEN,
149                 false /* shouldApplyIndependently */);
150 
151         mTaskFragmentOrganizer.waitForTaskFragmentCreated();
152 
153         TaskFragmentInfo info = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken);
154         assertNotEmptyTaskFragment(info, taskFragToken);
155 
156         mWmState.waitForActivityState(mLaunchingActivity, STATE_RESUMED);
157 
158         Task parentTask = mWmState.getTaskByActivity(mOwnerActivityName);
159         TaskFragment taskFragment = mWmState.getTaskFragmentByActivity(mLaunchingActivity);
160 
161         // Assert window hierarchy must be as follows
162         // - owner Activity's Task (parentTask)
163         //   - taskFragment
164         //     - LAUNCHING_ACTIVITY
165         //   - owner Activity
166         assertWindowHierarchy(parentTask, taskFragment, mWmState.getActivity(mLaunchingActivity));
167         assertWindowHierarchy(parentTask, mWmState.getActivity(mOwnerActivityName));
168         assertWithMessage("The owner Activity's Task must be reused as"
169                 + " the launching Activity's Task.").that(parentTask)
170                 .isEqualTo(mWmState.getTaskByActivity(mLaunchingActivity));
171     }
172 
173     /**
174      * Verifies the behavior of {@link WindowContainerTransaction#deleteTaskFragment} to remove the
175      * organized TaskFragment.
176      */
177     @Test
178     @ApiTest(apis = {
179             "android.window.WindowContainerTransaction#deleteTaskFragment"})
testDeleteTaskFragment()180     public void testDeleteTaskFragment() {
181         final TaskFragmentInfo taskFragmentInfo = createTaskFragment(null);
182         final IBinder taskFragToken = taskFragmentInfo.getFragmentToken();
183         assertEmptyTaskFragment(taskFragmentInfo, taskFragmentInfo.getFragmentToken());
184 
185         mWmState.computeState(mOwnerActivityName);
186         final int originalTaskFragCount = mWmState.getTaskByActivity(mOwnerActivityName)
187                 .getTaskFragments().size();
188 
189         WindowContainerTransaction wct = new WindowContainerTransaction()
190                 .deleteTaskFragment(taskFragToken);
191         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_CLOSE,
192                 false /* shouldApplyIndependently */);
193 
194         mTaskFragmentOrganizer.waitForTaskFragmentRemoved();
195 
196         assertEmptyTaskFragment(mTaskFragmentOrganizer.getRemovedTaskFragmentInfo(taskFragToken),
197                 taskFragToken);
198 
199         mWmState.computeState(mOwnerActivityName);
200         final int currTaskFragCount = mWmState.getTaskByActivity(mOwnerActivityName)
201                 .getTaskFragments().size();
202         assertWithMessage("TaskFragment with token " + taskFragToken + " must be"
203                 + " removed.").that(originalTaskFragCount - currTaskFragCount).isEqualTo(1);
204     }
205 
206     /**
207      * Verifies the behavior of {@link WindowContainerTransaction#deleteTaskFragment} to remove the
208      * organized TaskFragment with activity embedded.
209      */
210     @Test
211     @ApiTest(apis = {
212             "android.window.WindowContainerTransaction#deleteTaskFragment",
213             "android.window.TaskFragmentOrganizer#onTransactionReady"})
testDeleteTaskFragmentWithActivity()214     public void testDeleteTaskFragmentWithActivity() {
215         final TaskFragmentInfo taskFragmentInfo = createTaskFragment(mLaunchingActivity);
216         final IBinder taskFragToken = taskFragmentInfo.getFragmentToken();
217         assertNotEmptyTaskFragment(taskFragmentInfo, taskFragmentInfo.getFragmentToken());
218 
219         mWmState.computeState(mOwnerActivityName);
220         final int originalTaskFragCount = mWmState.getTaskByActivity(mOwnerActivityName)
221                 .getTaskFragments().size();
222 
223         WindowContainerTransaction wct = new WindowContainerTransaction()
224                 .deleteTaskFragment(taskFragToken);
225         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_CLOSE,
226                 false /* shouldApplyIndependently */);
227 
228         mTaskFragmentOrganizer.waitForTaskFragmentRemoved();
229 
230         assertEmptyTaskFragment(mTaskFragmentOrganizer.getRemovedTaskFragmentInfo(taskFragToken),
231                 taskFragToken);
232 
233         mWmState.computeState(mOwnerActivityName);
234         final int currTaskFragCount = mWmState.getTaskByActivity(mOwnerActivityName)
235                 .getTaskFragments().size();
236         assertWithMessage("TaskFragment with token " + taskFragToken + " must be"
237                 + " removed.").that(originalTaskFragCount - currTaskFragCount).isEqualTo(1);
238     }
239 
240     /**
241      * Verifies the behavior of {@link WindowContainerTransaction#finishActivity(IBinder)} to finish
242      * an Activity.
243      */
244     @Test
245     @ApiTest(apis = {
246             "android.window.TaskFragmentOrganizer#applyTransaction",
247             "android.window.WindowContainerTransaction#finishActivity"})
testFinishActivity()248     public void testFinishActivity() {
249         final Activity activity = startNewActivity(
250                 WindowMetricsActivityTests.MetricsActivity.class);
251         // Make sure mLaunchingActivity is mapping to the correct component that is started.
252         mWmState.waitAndAssertActivityState(mLaunchingActivity, STATE_RESUMED);
253 
254         final WindowContainerTransaction wct = new WindowContainerTransaction()
255                 .finishActivity(getActivityToken(activity));
256         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_CLOSE,
257                 false /* shouldApplyIndependently */);
258 
259         mWmState.waitAndAssertActivityRemoved(mLaunchingActivity);
260     }
261 
262     /**
263      * Verifies the visibility of an activity behind a TaskFragment that has the same
264      * bounds of the host Task.
265      */
266     @Test
testActivityVisibilityBehindTaskFragment()267     public void testActivityVisibilityBehindTaskFragment() {
268         // Start an activity and reparent it to a TaskFragment.
269         final Activity embeddedActivity =
270                 startActivity(WindowMetricsActivityTests.MetricsActivity.class);
271         final IBinder embeddedActivityToken = getActivityToken(embeddedActivity);
272         final TaskFragmentCreationParams params = generateTaskFragCreationParams();
273         final IBinder taskFragToken = params.getFragmentToken();
274         final WindowContainerTransaction wct = new WindowContainerTransaction()
275                 .createTaskFragment(params)
276                 .reparentActivityToTaskFragment(taskFragToken, embeddedActivityToken);
277         mTaskFragmentOrganizer.applyTransaction(wct, TASK_FRAGMENT_TRANSIT_CHANGE,
278                 false /* shouldApplyIndependently */);
279         mTaskFragmentOrganizer.waitForTaskFragmentCreated();
280         // The activity below must be occluded and stopped.
281         waitAndAssertActivityState(mOwnerActivityName, STATE_STOPPED,
282                 "Activity must be stopped");
283 
284         // Finishing the top activity and remain the TaskFragment on top. The next top activity
285         // must be resumed.
286         embeddedActivity.finish();
287         waitAndAssertResumedActivity(mOwnerActivityName, "Activity must be resumed");
288     }
289 }
290