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