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 com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
22 import static android.view.Display.DEFAULT_DISPLAY;
23 import static android.view.WindowManager.TRANSIT_CHANGE;
24 import static android.view.WindowManager.TRANSIT_CLOSE;
25 import static android.view.WindowManager.TRANSIT_NONE;
26 import static android.view.WindowManager.TRANSIT_OPEN;
27 import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
28 import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
29 import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
30 import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
31 import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
32 import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
33 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
34 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
35 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
36 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
37 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE;
38 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_NONE;
39 import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN;
40 import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
41 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
42 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
43 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
44 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
45 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
46 
47 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
48 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
49 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
50 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
51 import static com.android.server.wm.WindowContainer.POSITION_TOP;
52 import static com.android.server.wm.testing.Assert.assertThrows;
53 
54 import static com.google.common.truth.Truth.assertWithMessage;
55 
56 import static org.junit.Assert.assertEquals;
57 import static org.junit.Assert.assertFalse;
58 import static org.junit.Assert.assertNotEquals;
59 import static org.junit.Assert.assertNotNull;
60 import static org.junit.Assert.assertNull;
61 import static org.junit.Assert.assertTrue;
62 import static org.mockito.ArgumentMatchers.any;
63 import static org.mockito.ArgumentMatchers.anyBoolean;
64 import static org.mockito.ArgumentMatchers.anyInt;
65 import static org.mockito.ArgumentMatchers.eq;
66 import static org.mockito.Mockito.clearInvocations;
67 import static org.mockito.Mockito.doAnswer;
68 import static org.mockito.Mockito.mock;
69 import static org.mockito.Mockito.never;
70 import static org.mockito.Mockito.verify;
71 
72 import android.annotation.NonNull;
73 import android.content.ComponentName;
74 import android.content.Intent;
75 import android.content.pm.ActivityInfo;
76 import android.content.res.Configuration;
77 import android.graphics.Color;
78 import android.graphics.Rect;
79 import android.net.Uri;
80 import android.os.Binder;
81 import android.os.Bundle;
82 import android.os.IBinder;
83 import android.os.RemoteException;
84 import android.platform.test.annotations.Presubmit;
85 import android.view.RemoteAnimationDefinition;
86 import android.view.SurfaceControl;
87 import android.window.ITaskFragmentOrganizer;
88 import android.window.TaskFragmentAnimationParams;
89 import android.window.TaskFragmentCreationParams;
90 import android.window.TaskFragmentInfo;
91 import android.window.TaskFragmentOperation;
92 import android.window.TaskFragmentOrganizer;
93 import android.window.TaskFragmentOrganizerToken;
94 import android.window.TaskFragmentParentInfo;
95 import android.window.TaskFragmentTransaction;
96 import android.window.WindowContainerToken;
97 import android.window.WindowContainerTransaction;
98 
99 import androidx.test.filters.SmallTest;
100 
101 import org.junit.Before;
102 import org.junit.Test;
103 import org.junit.runner.RunWith;
104 import org.mockito.ArgumentCaptor;
105 import org.mockito.Captor;
106 import org.mockito.Mock;
107 import org.mockito.MockitoAnnotations;
108 import org.mockito.stubbing.Answer;
109 
110 import java.util.List;
111 
112 /**
113  * Build/Install/Run:
114  *  atest WmTests:TaskFragmentOrganizerControllerTest
115  */
116 @SmallTest
117 @Presubmit
118 @RunWith(WindowTestRunner.class)
119 public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
120     private static final int TASK_ID = 10;
121 
122     private TaskFragmentOrganizerController mController;
123     private WindowOrganizerController mWindowOrganizerController;
124     private TransitionController mTransitionController;
125     private TaskFragmentOrganizer mOrganizer;
126     private TaskFragmentOrganizerToken mOrganizerToken;
127     private ITaskFragmentOrganizer mIOrganizer;
128     private TaskFragment mTaskFragment;
129     private IBinder mFragmentToken;
130     private WindowContainerTransaction mTransaction;
131     private WindowContainerToken mFragmentWindowToken;
132     private RemoteAnimationDefinition mDefinition;
133     private IBinder mErrorToken;
134     private Rect mTaskFragBounds;
135 
136     @Mock
137     private TaskFragmentInfo mTaskFragmentInfo;
138     @Mock
139     private Task mTask;
140     @Captor
141     private ArgumentCaptor<TaskFragmentTransaction> mTransactionCaptor;
142 
143     @Before
setup()144     public void setup() throws RemoteException {
145         MockitoAnnotations.initMocks(this);
146         mWindowOrganizerController = mAtm.mWindowOrganizerController;
147         mTransitionController = mWindowOrganizerController.mTransitionController;
148         mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
149         mOrganizer = new TaskFragmentOrganizer(Runnable::run);
150         mOrganizerToken = mOrganizer.getOrganizerToken();
151         mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
152         mFragmentToken = new Binder();
153         mTaskFragment =
154                 new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
155         mTransaction = new WindowContainerTransaction();
156         mTransaction.setTaskFragmentOrganizer(mIOrganizer);
157         mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
158         mDefinition = new RemoteAnimationDefinition();
159         mErrorToken = new Binder();
160         final Rect displayBounds = mDisplayContent.getBounds();
161         mTaskFragBounds = new Rect(displayBounds.left, displayBounds.top, displayBounds.centerX(),
162                 displayBounds.centerY());
163 
164         spyOn(mController);
165         spyOn(mOrganizer);
166         spyOn(mTaskFragment);
167         spyOn(mWindowOrganizerController);
168         spyOn(mTransitionController);
169         doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer();
170         doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo();
171         doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl();
172         doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken();
173         doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
174 
175         // To prevent it from calling the real server.
176         doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean());
177         doNothing().when(mOrganizer).onTransactionHandled(any(), any(), anyInt(), anyBoolean());
178 
179         mController.registerOrganizer(mIOrganizer);
180     }
181 
182     @Test
testCallTaskFragmentCallbackWithoutRegister_throwsException()183     public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
184         mController.unregisterOrganizer(mIOrganizer);
185 
186         doReturn(mTask).when(mTaskFragment).getTask();
187 
188         assertThrows(IllegalArgumentException.class, () -> mController
189                 .onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
190 
191         assertThrows(IllegalArgumentException.class, () -> mController
192                 .onTaskFragmentInfoChanged(
193                         mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
194 
195         assertThrows(IllegalArgumentException.class, () -> mController
196                 .onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
197     }
198 
199     @Test
testOnTaskFragmentAppeared()200     public void testOnTaskFragmentAppeared() {
201         // No-op when the TaskFragment is not attached.
202         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
203         mController.dispatchPendingEvents();
204 
205         verify(mOrganizer, never()).onTransactionReady(any());
206 
207         // Send callback when the TaskFragment is attached.
208         setupMockParent(mTaskFragment, mTask);
209 
210         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
211         mController.dispatchPendingEvents();
212 
213         assertTaskFragmentParentInfoChangedTransaction(mTask);
214         assertTaskFragmentAppearedTransaction();
215     }
216 
217     @Test
testOnTaskFragmentInfoChanged()218     public void testOnTaskFragmentInfoChanged() {
219         setupMockParent(mTaskFragment, mTask);
220 
221         // No-op if onTaskFragmentAppeared is not called yet.
222         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
223                 mTaskFragment);
224         mController.dispatchPendingEvents();
225 
226         verify(mOrganizer, never()).onTransactionReady(any());
227 
228         // Call onTaskFragmentAppeared first.
229         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
230         mController.dispatchPendingEvents();
231 
232         verify(mOrganizer).onTransactionReady(any());
233 
234         // No callback if the info is not changed.
235         clearInvocations(mOrganizer);
236         doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
237         doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
238 
239         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
240                 mTaskFragment);
241         mController.dispatchPendingEvents();
242 
243         verify(mOrganizer, never()).onTransactionReady(any());
244 
245         // Trigger callback if the info is changed.
246         doReturn(false).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
247 
248         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
249                 mTaskFragment);
250         mController.dispatchPendingEvents();
251 
252         assertTaskFragmentInfoChangedTransaction();
253     }
254 
255     @Test
testOnTaskFragmentVanished()256     public void testOnTaskFragmentVanished() {
257         mTaskFragment.mTaskFragmentAppearedSent = true;
258         mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
259         mController.dispatchPendingEvents();
260 
261         assertTrue(mTaskFragment.mTaskFragmentVanishedSent);
262         assertTaskFragmentVanishedTransaction();
263     }
264 
265     @Test
testOnTaskFragmentVanished_clearUpRemaining()266     public void testOnTaskFragmentVanished_clearUpRemaining() {
267         setupMockParent(mTaskFragment, mTask);
268 
269         // Not trigger onTaskFragmentAppeared.
270         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
271         mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
272         mController.dispatchPendingEvents();
273 
274         assertTrue(mTaskFragment.mTaskFragmentVanishedSent);
275         assertTaskFragmentVanishedTransaction();
276 
277         // Not trigger onTaskFragmentInfoChanged.
278         // Call onTaskFragmentAppeared before calling onTaskFragmentInfoChanged.
279         mTaskFragment.mTaskFragmentVanishedSent = false;
280         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
281         mController.dispatchPendingEvents();
282         clearInvocations(mOrganizer);
283         doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
284         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
285                 mTaskFragment);
286         mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
287         mController.dispatchPendingEvents();
288 
289         assertTaskFragmentVanishedTransaction();
290     }
291 
292     @Test
testOnTaskFragmentParentInfoChanged()293     public void testOnTaskFragmentParentInfoChanged() {
294         setupMockParent(mTaskFragment, mTask);
295         mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 10;
296 
297         mController.onTaskFragmentAppeared(
298                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
299         mController.dispatchPendingEvents();
300 
301         assertTaskFragmentParentInfoChangedTransaction(mTask);
302 
303         // No extra parent info changed callback if the info is not changed.
304         clearInvocations(mOrganizer);
305 
306         mController.onTaskFragmentInfoChanged(
307                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
308         mController.dispatchPendingEvents();
309 
310         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
311         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
312         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
313         assertEquals(1, changes.size());
314         final TaskFragmentTransaction.Change change = changes.get(0);
315         assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, change.getType());
316 
317         // Trigger callback if the size is changed.
318         clearInvocations(mOrganizer);
319         mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 100;
320         mController.onTaskFragmentInfoChanged(
321                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
322         mController.dispatchPendingEvents();
323 
324         assertTaskFragmentParentInfoChangedTransaction(mTask);
325 
326         // Trigger callback if the windowing mode is changed.
327         clearInvocations(mOrganizer);
328         mTask.getTaskFragmentParentInfo().getConfiguration().windowConfiguration
329                 .setWindowingMode(WINDOWING_MODE_PINNED);
330         mController.onTaskFragmentInfoChanged(
331                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
332         mController.dispatchPendingEvents();
333 
334         assertTaskFragmentParentInfoChangedTransaction(mTask);
335     }
336 
337     @Test
testOnTaskFragmentError()338     public void testOnTaskFragmentError() {
339         final Throwable exception = new IllegalArgumentException("Test exception");
340 
341         mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
342                 mErrorToken, null /* taskFragment */, OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
343                 exception);
344         mController.dispatchPendingEvents();
345 
346         assertTaskFragmentErrorTransaction(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
347                 exception.getClass());
348     }
349 
350     @Test
testOnActivityReparentedToTask_activityInOrganizerProcess_useActivityToken()351     public void testOnActivityReparentedToTask_activityInOrganizerProcess_useActivityToken() {
352         // Make sure the activity pid/uid is the same as the organizer caller.
353         final int pid = Binder.getCallingPid();
354         final int uid = Binder.getCallingUid();
355         final ActivityRecord activity = createActivityRecord(mDisplayContent);
356         // Flush EVENT_APPEARED.
357         mController.dispatchPendingEvents();
358         final Task task = activity.getTask();
359         activity.info.applicationInfo.uid = uid;
360         doReturn(pid).when(activity).getPid();
361         task.effectiveUid = uid;
362 
363         // No need to notify organizer if it is not embedded.
364         mController.onActivityReparentedToTask(activity);
365         mController.dispatchPendingEvents();
366 
367         verify(mOrganizer, never()).onTransactionReady(any());
368 
369         // Notify organizer if it was embedded before entered Pip.
370         activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
371         mController.onActivityReparentedToTask(activity);
372         mController.dispatchPendingEvents();
373 
374         assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token);
375 
376         // Notify organizer if there is any embedded in the Task.
377         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
378                 .setParentTask(task)
379                 .setOrganizer(mOrganizer)
380                 .build();
381         taskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
382                 DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
383         activity.reparent(taskFragment, POSITION_TOP);
384         activity.mLastTaskFragmentOrganizerBeforePip = null;
385         // Flush EVENT_INFO_CHANGED.
386         mController.dispatchPendingEvents();
387 
388         // Clear invocations now because there will be another transaction for the TaskFragment
389         // change above, triggered by the reparent. We only want to test onActivityReparentedToTask
390         // here.
391         clearInvocations(mOrganizer);
392         mController.onActivityReparentedToTask(activity);
393         mController.dispatchPendingEvents();
394 
395         assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token);
396     }
397 
398     @Test
testOnActivityReparentedToTask_activityNotInOrganizerProcess_useTemporaryToken()399     public void testOnActivityReparentedToTask_activityNotInOrganizerProcess_useTemporaryToken() {
400         final int pid = Binder.getCallingPid();
401         final int uid = Binder.getCallingUid();
402         final WindowProcessController organizerProc = mSystemServicesTestRule.addProcess(
403                 "pkg.organizer", DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME, pid, uid);
404         mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
405                 DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
406         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
407         final Task task = createTask(mDisplayContent);
408         task.addChild(mTaskFragment, POSITION_TOP);
409         final ActivityRecord activity = createActivityRecord(task);
410         // Flush EVENT_APPEARED.
411         mController.dispatchPendingEvents();
412 
413         // Make sure the activity belongs to the same app, but it is in a different pid.
414         activity.info.applicationInfo.uid = uid;
415         doReturn(pid + 1).when(activity).getPid();
416         task.effectiveUid = uid;
417 
418         // Notify organizer if it was embedded before entered Pip.
419         // Create a temporary token since the activity doesn't belong to the same process.
420         clearInvocations(mOrganizer);
421         activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
422         mController.onActivityReparentedToTask(activity);
423         mController.dispatchPendingEvents();
424 
425         // Allow organizer to reparent activity in other process using the temporary token.
426         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
427         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
428         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
429         assertFalse(changes.isEmpty());
430         final TaskFragmentTransaction.Change change = changes.get(0);
431         assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType());
432         assertEquals(task.mTaskId, change.getTaskId());
433         assertIntentsEqualForOrganizer(activity.intent, change.getActivityIntent());
434         assertNotEquals(activity.token, change.getActivityToken());
435         mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
436         assertApplyTransactionAllowed(mTransaction);
437 
438         assertEquals(mTaskFragment, activity.getTaskFragment());
439         // The temporary token can only be used once.
440         assertNull(mController.getReparentActivityFromTemporaryToken(mIOrganizer,
441                 change.getActivityToken()));
442 
443         // The organizer process should also have visible state by the visible activity in a
444         // different process.
445         activity.setVisibleRequested(true);
446         activity.setState(ActivityRecord.State.RESUMED, "test");
447         assertTrue(organizerProc.hasVisibleActivities());
448         activity.setVisibleRequested(false);
449         activity.setState(ActivityRecord.State.STOPPED, "test");
450         assertFalse(organizerProc.hasVisibleActivities());
451     }
452 
453     @Test
testOnActivityReparentedToTask_untrustedEmbed_notReported()454     public void testOnActivityReparentedToTask_untrustedEmbed_notReported() {
455         final int pid = Binder.getCallingPid();
456         final int uid = Binder.getCallingUid();
457         mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
458                 DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
459         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
460         final Task task = createTask(mDisplayContent);
461         task.addChild(mTaskFragment, POSITION_TOP);
462         final ActivityRecord activity = createActivityRecord(task);
463         // Flush EVENT_APPEARED.
464         mController.dispatchPendingEvents();
465 
466         // Make sure the activity is embedded in untrusted mode.
467         activity.info.applicationInfo.uid = uid + 1;
468         doReturn(pid + 1).when(activity).getPid();
469         task.effectiveUid = uid;
470         doReturn(EMBEDDING_ALLOWED).when(task).isAllowedToEmbedActivity(activity, uid);
471         doReturn(false).when(task).isAllowedToEmbedActivityInTrustedMode(activity, uid);
472         doReturn(true).when(task).isAllowedToEmbedActivityInUntrustedMode(activity);
473 
474         // Notify organizer if it was embedded before entered Pip.
475         // Create a temporary token since the activity doesn't belong to the same process.
476         clearInvocations(mOrganizer);
477         activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
478         mController.onActivityReparentedToTask(activity);
479         mController.dispatchPendingEvents();
480 
481         // Disallow organizer to reparent activity that is untrusted embedded.
482         verify(mOrganizer, never()).onTransactionReady(mTransactionCaptor.capture());
483     }
484 
485     @Test
testOnActivityReparentedToTask_trimReportedIntent()486     public void testOnActivityReparentedToTask_trimReportedIntent() {
487         // Make sure the activity pid/uid is the same as the organizer caller.
488         final int pid = Binder.getCallingPid();
489         final int uid = Binder.getCallingUid();
490         final ActivityRecord activity = createActivityRecord(mDisplayContent);
491         final Task task = activity.getTask();
492         activity.info.applicationInfo.uid = uid;
493         doReturn(pid).when(activity).getPid();
494         task.effectiveUid = uid;
495         activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
496 
497         // Test the Intent trim in #assertIntentTrimmed
498         activity.intent.setComponent(new ComponentName("TestPackage", "TestClass"))
499                 .setPackage("TestPackage")
500                 .setAction("TestAction")
501                 .setData(mock(Uri.class))
502                 .putExtra("Test", 123)
503                 .setFlags(10);
504 
505         mController.onActivityReparentedToTask(activity);
506         mController.dispatchPendingEvents();
507 
508         assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token);
509     }
510 
511     @Test
testRegisterRemoteAnimations()512     public void testRegisterRemoteAnimations() {
513         mController.registerRemoteAnimations(mIOrganizer, mDefinition);
514 
515         assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
516 
517         mController.unregisterRemoteAnimations(mIOrganizer);
518 
519         assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
520     }
521 
522     @Test
testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment()523     public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() {
524         // Throw exception if the transaction is trying to change a window that is not organized by
525         // the organizer.
526         mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
527 
528         assertApplyTransactionDisallowed(mTransaction);
529 
530         // Allow transaction to change a TaskFragment created by the organizer.
531         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
532                 "Test:TaskFragmentOrganizer" /* processName */);
533 
534         assertApplyTransactionAllowed(mTransaction);
535     }
536 
537     @Test
testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()538     public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
539         doReturn(true).when(mTaskFragment).isAttached();
540         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
541 
542         // Throw exception if the transaction is trying to change a window that is not organized by
543         // the organizer.
544         mTransaction.deleteTaskFragment(mFragmentToken);
545 
546         assertApplyTransactionDisallowed(mTransaction);
547 
548         // Allow transaction to change a TaskFragment created by the organizer.
549         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
550                 "Test:TaskFragmentOrganizer" /* processName */);
551         clearInvocations(mAtm.mRootWindowContainer);
552 
553         assertApplyTransactionAllowed(mTransaction);
554         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
555     }
556 
557     @Test
testApplyTransaction_enforceHierarchyChange_createTaskFragment()558     public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
559         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
560 
561         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
562         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, mFragmentToken);
563         mTransaction.startActivityInTaskFragment(
564                 mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
565         mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
566         mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
567                 null /* options */);
568         mTransaction.clearAdjacentTaskFragments(mFragmentToken);
569         assertApplyTransactionAllowed(mTransaction);
570 
571         // Successfully created a TaskFragment.
572         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
573                 mFragmentToken);
574         assertNotNull(taskFragment);
575         assertEquals(ownerActivity.getTask(), taskFragment.getTask());
576     }
577 
578     @Test
testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment()579     public void testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment() {
580         final Task task = createTask(mDisplayContent);
581         final ActivityRecord ownerActivity = createActivityRecord(task);
582         mTaskFragment = new TaskFragmentBuilder(mAtm)
583                 .setParentTask(task)
584                 .setFragmentToken(mFragmentToken)
585                 .build();
586         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
587         mTransaction.startActivityInTaskFragment(
588                 mFragmentToken, ownerActivity.token, new Intent(), null /* activityOptions */);
589         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_OPEN,
590                 false /* shouldApplyIndependently */);
591 
592         // Not allowed because TaskFragment is not organized by the caller organizer.
593         assertApplyTransactionDisallowed(mTransaction);
594 
595         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
596                 "Test:TaskFragmentOrganizer" /* processName */);
597 
598         assertApplyTransactionAllowed(mTransaction);
599     }
600 
601     @Test
testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment()602     public void testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment() {
603         final Task task = createTask(mDisplayContent);
604         final ActivityRecord activity = createActivityRecord(task);
605         mTaskFragment = new TaskFragmentBuilder(mAtm)
606                 .setParentTask(task)
607                 .setFragmentToken(mFragmentToken)
608                 .build();
609         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
610         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
611         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
612                 false /* shouldApplyIndependently */);
613 
614         // Not allowed because TaskFragment is not organized by the caller organizer.
615         assertApplyTransactionDisallowed(mTransaction);
616 
617         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
618                 "Test:TaskFragmentOrganizer" /* processName */);
619 
620         assertApplyTransactionAllowed(mTransaction);
621     }
622 
623     @Test
testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments()624     public void testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments() {
625         final Task task = createTask(mDisplayContent);
626         mTaskFragment = new TaskFragmentBuilder(mAtm)
627                 .setParentTask(task)
628                 .setFragmentToken(mFragmentToken)
629                 .build();
630         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
631         final IBinder fragmentToken2 = new Binder();
632         final TaskFragment taskFragment2 = new TaskFragmentBuilder(mAtm)
633                 .setParentTask(task)
634                 .setFragmentToken(fragmentToken2)
635                 .build();
636         mWindowOrganizerController.mLaunchTaskFragments.put(fragmentToken2, taskFragment2);
637         mTransaction.setAdjacentTaskFragments(mFragmentToken, fragmentToken2, null /* params */);
638         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
639                 false /* shouldApplyIndependently */);
640 
641         // Not allowed because TaskFragments are not organized by the caller organizer.
642         assertApplyTransactionDisallowed(mTransaction);
643         assertNull(mTaskFragment.getAdjacentTaskFragment());
644         assertNull(taskFragment2.getAdjacentTaskFragment());
645 
646         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
647                 "Test:TaskFragmentOrganizer" /* processName */);
648 
649         // Not allowed because TaskFragment2 is not organized by the caller organizer.
650         assertApplyTransactionDisallowed(mTransaction);
651         assertNull(mTaskFragment.getAdjacentTaskFragment());
652         assertNull(taskFragment2.getAdjacentTaskFragment());
653 
654         mTaskFragment.onTaskFragmentOrganizerRemoved();
655         taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
656                 "Test:TaskFragmentOrganizer" /* processName */);
657 
658         // Not allowed because mTaskFragment is not organized by the caller organizer.
659         assertApplyTransactionDisallowed(mTransaction);
660         assertNull(mTaskFragment.getAdjacentTaskFragment());
661         assertNull(taskFragment2.getAdjacentTaskFragment());
662 
663         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
664                 "Test:TaskFragmentOrganizer" /* processName */);
665 
666         assertApplyTransactionAllowed(mTransaction);
667         assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment());
668     }
669 
670     @Test
testApplyTransaction_enforceTaskFragmentOrganized_clearAdjacentTaskFragments()671     public void testApplyTransaction_enforceTaskFragmentOrganized_clearAdjacentTaskFragments() {
672         final Task task = createTask(mDisplayContent);
673         mTaskFragment = new TaskFragmentBuilder(mAtm)
674                 .setParentTask(task)
675                 .setFragmentToken(mFragmentToken)
676                 .build();
677         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
678         final IBinder fragmentToken2 = new Binder();
679         final TaskFragment taskFragment2 = new TaskFragmentBuilder(mAtm)
680                 .setParentTask(task)
681                 .setFragmentToken(fragmentToken2)
682                 .build();
683         mWindowOrganizerController.mLaunchTaskFragments.put(fragmentToken2, taskFragment2);
684         mTaskFragment.setAdjacentTaskFragment(taskFragment2);
685 
686         mTransaction.clearAdjacentTaskFragments(mFragmentToken);
687         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
688                 false /* shouldApplyIndependently */);
689 
690         // Not allowed because TaskFragment is not organized by the caller organizer.
691         assertApplyTransactionDisallowed(mTransaction);
692         assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment());
693 
694         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
695                 "Test:TaskFragmentOrganizer" /* processName */);
696 
697         assertApplyTransactionAllowed(mTransaction);
698         assertNull(mTaskFragment.getAdjacentTaskFragment());
699         assertNull(taskFragment2.getAdjacentTaskFragment());
700     }
701 
702     @Test
testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment()703     public void testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment() {
704         final Task task = createTask(mDisplayContent);
705         mTaskFragment = new TaskFragmentBuilder(mAtm)
706                 .setParentTask(task)
707                 .setFragmentToken(mFragmentToken)
708                 .build();
709         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
710         mTransaction.requestFocusOnTaskFragment(mFragmentToken);
711         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
712                 false /* shouldApplyIndependently */);
713 
714         // Not allowed because TaskFragment is not organized by the caller organizer.
715         assertApplyTransactionDisallowed(mTransaction);
716 
717         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
718                 "Test:TaskFragmentOrganizer" /* processName */);
719 
720         assertApplyTransactionAllowed(mTransaction);
721     }
722 
723     @Test
testApplyTransaction_enforceTaskFragmentOrganized_addTaskFragmentOperation()724     public void testApplyTransaction_enforceTaskFragmentOrganized_addTaskFragmentOperation() {
725         final Task task = createTask(mDisplayContent);
726         mTaskFragment = new TaskFragmentBuilder(mAtm)
727                 .setParentTask(task)
728                 .setFragmentToken(mFragmentToken)
729                 .build();
730         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
731         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
732                 OP_TYPE_SET_ANIMATION_PARAMS)
733                 .setAnimationParams(TaskFragmentAnimationParams.DEFAULT)
734                 .build();
735         mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
736         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
737                 false /* shouldApplyIndependently */);
738 
739         // Not allowed because TaskFragment is not organized by the caller organizer.
740         assertApplyTransactionDisallowed(mTransaction);
741 
742         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
743                 "Test:TaskFragmentOrganizer" /* processName */);
744 
745         assertApplyTransactionAllowed(mTransaction);
746     }
747 
748     @Test
testAddTaskFragmentOperation()749     public void testAddTaskFragmentOperation() {
750         final Task task = createTask(mDisplayContent);
751         mTaskFragment = new TaskFragmentBuilder(mAtm)
752                 .setParentTask(task)
753                 .setOrganizer(mOrganizer)
754                 .setFragmentToken(mFragmentToken)
755                 .build();
756         assertEquals(TaskFragmentAnimationParams.DEFAULT, mTaskFragment.getAnimationParams());
757 
758         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
759         final TaskFragmentAnimationParams animationParams =
760                 new TaskFragmentAnimationParams.Builder()
761                         .setAnimationBackgroundColor(Color.GREEN)
762                         .build();
763         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
764                 OP_TYPE_SET_ANIMATION_PARAMS)
765                 .setAnimationParams(animationParams)
766                 .build();
767         mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
768         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
769                 false /* shouldApplyIndependently */);
770         assertApplyTransactionAllowed(mTransaction);
771 
772         assertEquals(animationParams, mTaskFragment.getAnimationParams());
773         assertEquals(Color.GREEN, mTaskFragment.getAnimationParams().getAnimationBackgroundColor());
774     }
775 
776     @Test
testApplyTransaction_createTaskFragment_failForDifferentUid()777     public void testApplyTransaction_createTaskFragment_failForDifferentUid() {
778         final ActivityRecord activity = createActivityRecord(mDisplayContent);
779         final int uid = Binder.getCallingUid();
780         final IBinder fragmentToken = new Binder();
781         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
782                 mOrganizerToken, fragmentToken, activity.token).build();
783         mTransaction.createTaskFragment(params);
784 
785         // Fail to create TaskFragment when the task uid is different from caller.
786         activity.info.applicationInfo.uid = uid;
787         activity.getTask().effectiveUid = uid + 1;
788         assertApplyTransactionAllowed(mTransaction);
789 
790         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
791 
792         // Fail to create TaskFragment when the task uid is different from owner activity.
793         activity.info.applicationInfo.uid = uid + 1;
794         activity.getTask().effectiveUid = uid;
795         assertApplyTransactionAllowed(mTransaction);
796 
797         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
798 
799         // Successfully created a TaskFragment for same uid.
800         activity.info.applicationInfo.uid = uid;
801         activity.getTask().effectiveUid = uid;
802         assertApplyTransactionAllowed(mTransaction);
803 
804         assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
805     }
806 
807     @Test
testApplyTransaction_createTaskFragment_withPairedPrimaryFragmentToken()808     public void testApplyTransaction_createTaskFragment_withPairedPrimaryFragmentToken() {
809         final Task task = createTask(mDisplayContent);
810         mTaskFragment = new TaskFragmentBuilder(mAtm)
811                 .setParentTask(task)
812                 .setFragmentToken(mFragmentToken)
813                 .createActivityCount(1)
814                 .build();
815         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
816         final ActivityRecord activityOnTop = createActivityRecord(task);
817         final int uid = Binder.getCallingUid();
818         activityOnTop.info.applicationInfo.uid = uid;
819         activityOnTop.getTask().effectiveUid = uid;
820         final IBinder fragmentToken1 = new Binder();
821         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
822                 mOrganizerToken, fragmentToken1, activityOnTop.token)
823                 .setPairedPrimaryFragmentToken(mFragmentToken)
824                 .build();
825         mTransaction.setTaskFragmentOrganizer(mIOrganizer);
826         mTransaction.createTaskFragment(params);
827         assertApplyTransactionAllowed(mTransaction);
828 
829         // Successfully created a TaskFragment.
830         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
831                 fragmentToken1);
832         assertNotNull(taskFragment);
833         // The new TaskFragment should be positioned right above the paired TaskFragment.
834         assertEquals(task.mChildren.indexOf(mTaskFragment) + 1,
835                 task.mChildren.indexOf(taskFragment));
836         // The top activity should remain on top.
837         assertEquals(task.mChildren.indexOf(taskFragment) + 1,
838                 task.mChildren.indexOf(activityOnTop));
839     }
840 
841     @Test
testApplyTransaction_createTaskFragment_overrideBounds()842     public void testApplyTransaction_createTaskFragment_overrideBounds() {
843         final Task task = createTask(mDisplayContent);
844         final ActivityRecord activityAtBottom = createActivityRecord(task);
845         final int uid = Binder.getCallingUid();
846         activityAtBottom.info.applicationInfo.uid = uid;
847         activityAtBottom.getTask().effectiveUid = uid;
848         mTaskFragment = new TaskFragmentBuilder(mAtm)
849                 .setParentTask(task)
850                 .setFragmentToken(mFragmentToken)
851                 .createActivityCount(1)
852                 .build();
853         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
854         final IBinder fragmentToken1 = new Binder();
855         final Rect bounds = new Rect(100, 100, 500, 1000);
856         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
857                 mOrganizerToken, fragmentToken1, activityAtBottom.token)
858                 .setPairedActivityToken(activityAtBottom.token)
859                 .setInitialRelativeBounds(bounds)
860                 .build();
861         mTransaction.setTaskFragmentOrganizer(mIOrganizer);
862         mTransaction.createTaskFragment(params);
863         assertApplyTransactionAllowed(mTransaction);
864 
865         // Successfully created a TaskFragment.
866         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
867                 fragmentToken1);
868         assertNotNull(taskFragment);
869         // The relative embedded bounds is updated to the initial requested bounds.
870         assertEquals(bounds, taskFragment.getRelativeEmbeddedBounds());
871     }
872 
873     @Test
testApplyTransaction_createTaskFragment_withPairedActivityToken()874     public void testApplyTransaction_createTaskFragment_withPairedActivityToken() {
875         final Task task = createTask(mDisplayContent);
876         final ActivityRecord activityAtBottom = createActivityRecord(task);
877         final int uid = Binder.getCallingUid();
878         activityAtBottom.info.applicationInfo.uid = uid;
879         activityAtBottom.getTask().effectiveUid = uid;
880         mTaskFragment = new TaskFragmentBuilder(mAtm)
881                 .setParentTask(task)
882                 .setFragmentToken(mFragmentToken)
883                 .createActivityCount(1)
884                 .build();
885         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
886         final IBinder fragmentToken1 = new Binder();
887         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
888                 mOrganizerToken, fragmentToken1, activityAtBottom.token)
889                 .setPairedActivityToken(activityAtBottom.token)
890                 .build();
891         mTransaction.setTaskFragmentOrganizer(mIOrganizer);
892         mTransaction.createTaskFragment(params);
893         assertApplyTransactionAllowed(mTransaction);
894 
895         // Successfully created a TaskFragment.
896         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
897                 fragmentToken1);
898         assertNotNull(taskFragment);
899         // The new TaskFragment should be positioned right above the paired activity.
900         assertEquals(task.mChildren.indexOf(activityAtBottom) + 1,
901                 task.mChildren.indexOf(taskFragment));
902         // The top TaskFragment should remain on top.
903         assertEquals(task.mChildren.indexOf(taskFragment) + 1,
904                 task.mChildren.indexOf(mTaskFragment));
905     }
906 
907     @Test
testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()908     public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate() {
909         final Task task = createTask(mDisplayContent);
910         final ActivityRecord activity = createActivityRecord(task);
911         // Skip manipulate the SurfaceControl.
912         doNothing().when(activity).setDropInputMode(anyInt());
913         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
914                 false /* shouldApplyIndependently */);
915         mTaskFragment = new TaskFragmentBuilder(mAtm)
916                 .setParentTask(task)
917                 .setFragmentToken(mFragmentToken)
918                 .setOrganizer(mOrganizer)
919                 .build();
920         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
921         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
922         doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
923         clearInvocations(mAtm.mRootWindowContainer);
924 
925         assertApplyTransactionAllowed(mTransaction);
926 
927         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
928     }
929 
930     @Test
testApplyTransaction_requestFocusOnTaskFragment()931     public void testApplyTransaction_requestFocusOnTaskFragment() {
932         final Task task = createTask(mDisplayContent);
933         final IBinder token0 = new Binder();
934         final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
935                 .setParentTask(task)
936                 .setFragmentToken(token0)
937                 .setOrganizer(mOrganizer)
938                 .createActivityCount(1)
939                 .build();
940         final IBinder token1 = new Binder();
941         final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
942                 .setParentTask(task)
943                 .setFragmentToken(token1)
944                 .setOrganizer(mOrganizer)
945                 .createActivityCount(1)
946                 .build();
947         mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
948         mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
949         final ActivityRecord activity0 = tf0.getTopMostActivity();
950         final ActivityRecord activity1 = tf1.getTopMostActivity();
951 
952         // No effect if the current focus is in a different Task.
953         final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
954         mDisplayContent.setFocusedApp(activityInOtherTask);
955         mTransaction.requestFocusOnTaskFragment(token0);
956         assertApplyTransactionAllowed(mTransaction);
957 
958         assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
959 
960         // No effect if there is no resumed activity in the request TaskFragment.
961         activity0.setState(ActivityRecord.State.PAUSED, "test");
962         activity1.setState(ActivityRecord.State.RESUMED, "test");
963         mDisplayContent.setFocusedApp(activity1);
964         assertApplyTransactionAllowed(mTransaction);
965 
966         assertEquals(activity1, mDisplayContent.mFocusedApp);
967 
968         // Set focus to the request TaskFragment when the current focus is in the same Task, and it
969         // has a resumed activity.
970         activity0.setState(ActivityRecord.State.RESUMED, "test");
971         mDisplayContent.setFocusedApp(activity1);
972         assertApplyTransactionAllowed(mTransaction);
973 
974         assertEquals(activity0, mDisplayContent.mFocusedApp);
975     }
976 
977     @Test
testApplyTransaction_finishActivity()978     public void testApplyTransaction_finishActivity() {
979         final ActivityRecord activity = createActivityRecord(mDisplayContent);
980 
981         mTransaction.finishActivity(activity.token);
982         assertApplyTransactionAllowed(mTransaction);
983 
984         assertTrue(activity.finishing);
985     }
986 
987     @Test
testApplyTransaction_skipTransactionForUnregisterOrganizer()988     public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
989         mController.unregisterOrganizer(mIOrganizer);
990         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
991         final IBinder fragmentToken = new Binder();
992 
993         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
994         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
995         assertApplyTransactionAllowed(mTransaction);
996 
997         // Nothing should happen as the organizer is not registered.
998         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
999 
1000         mController.registerOrganizer(mIOrganizer);
1001         assertApplyTransactionAllowed(mTransaction);
1002 
1003         // Successfully created when the organizer is registered.
1004         assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
1005     }
1006 
1007     @Test
testOnTransactionHandled_skipTransactionForUnregisterOrganizer()1008     public void testOnTransactionHandled_skipTransactionForUnregisterOrganizer() {
1009         mController.unregisterOrganizer(mIOrganizer);
1010         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
1011         final IBinder fragmentToken = new Binder();
1012 
1013         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
1014         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
1015         mController.onTransactionHandled(new Binder(), mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
1016                 false /* shouldApplyIndependently */);
1017 
1018         // Nothing should happen as the organizer is not registered.
1019         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
1020     }
1021 
1022     @Test
testOrganizerRemovedWithPendingEvents()1023     public void testOrganizerRemovedWithPendingEvents() {
1024         final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
1025                 .setCreateParentTask()
1026                 .setOrganizer(mOrganizer)
1027                 .setFragmentToken(mFragmentToken)
1028                 .build();
1029         final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
1030                 .setCreateParentTask()
1031                 .setOrganizer(mOrganizer)
1032                 .setFragmentToken(new Binder())
1033                 .build();
1034         assertTrue(tf0.isOrganizedTaskFragment());
1035         assertTrue(tf1.isOrganizedTaskFragment());
1036         assertTrue(tf0.isAttached());
1037         assertTrue(tf0.isAttached());
1038 
1039         // Mock the behavior that remove TaskFragment can trigger event dispatch.
1040         final Answer<Void> removeImmediately = invocation -> {
1041             invocation.callRealMethod();
1042             mController.dispatchPendingEvents();
1043             return null;
1044         };
1045         doAnswer(removeImmediately).when(tf0).removeImmediately();
1046         doAnswer(removeImmediately).when(tf1).removeImmediately();
1047 
1048         // Add pending events.
1049         mController.onTaskFragmentAppeared(mIOrganizer, tf0);
1050         mController.onTaskFragmentAppeared(mIOrganizer, tf1);
1051 
1052         // Remove organizer.
1053         mController.unregisterOrganizer(mIOrganizer);
1054         mController.dispatchPendingEvents();
1055 
1056         // Nothing should happen after the organizer is removed.
1057         verify(mOrganizer, never()).onTransactionReady(any());
1058 
1059         // TaskFragments should be removed.
1060         assertFalse(tf0.isOrganizedTaskFragment());
1061         assertFalse(tf1.isOrganizedTaskFragment());
1062         assertFalse(tf0.isAttached());
1063         assertFalse(tf0.isAttached());
1064     }
1065 
1066     @Test
testTaskFragmentInPip_startActivityInTaskFragment()1067     public void testTaskFragmentInPip_startActivityInTaskFragment() {
1068         setupTaskFragmentInPip();
1069         final ActivityRecord activity = mTaskFragment.getTopMostActivity();
1070         spyOn(mAtm.getActivityStartController());
1071         spyOn(mWindowOrganizerController);
1072 
1073         // Not allow to start activity in a TaskFragment that is in a PIP Task.
1074         mTransaction.startActivityInTaskFragment(
1075                         mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
1076                 .setErrorCallbackToken(mErrorToken);
1077         assertApplyTransactionAllowed(mTransaction);
1078 
1079         verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
1080                 any(), any(), anyInt(), anyInt(), any());
1081         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
1082                 eq(mErrorToken), eq(mTaskFragment),
1083                 eq(OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
1084                 any(IllegalArgumentException.class));
1085     }
1086 
1087     @Test
testTaskFragmentInPip_reparentActivityToTaskFragment()1088     public void testTaskFragmentInPip_reparentActivityToTaskFragment() {
1089         setupTaskFragmentInPip();
1090         final ActivityRecord activity = createActivityRecord(mDisplayContent);
1091         spyOn(mWindowOrganizerController);
1092 
1093         // Not allow to reparent activity to a TaskFragment that is in a PIP Task.
1094         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
1095                 .setErrorCallbackToken(mErrorToken);
1096         assertApplyTransactionAllowed(mTransaction);
1097 
1098         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
1099                 eq(mErrorToken), eq(mTaskFragment),
1100                 eq(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
1101                 any(IllegalArgumentException.class));
1102         assertNull(activity.getOrganizedTaskFragment());
1103     }
1104 
1105     @Test
testTaskFragmentInPip_setAdjacentTaskFragment()1106     public void testTaskFragmentInPip_setAdjacentTaskFragment() {
1107         setupTaskFragmentInPip();
1108         spyOn(mWindowOrganizerController);
1109 
1110         // Not allow to set adjacent on a TaskFragment that is in a PIP Task.
1111         mTransaction.setAdjacentTaskFragments(mFragmentToken, new Binder(), null /* options */)
1112                 .setErrorCallbackToken(mErrorToken);
1113         assertApplyTransactionAllowed(mTransaction);
1114 
1115         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
1116                 eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
1117                 any(IllegalArgumentException.class));
1118         verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
1119     }
1120 
1121     @Test
testTaskFragmentInPip_createTaskFragment()1122     public void testTaskFragmentInPip_createTaskFragment() {
1123         final Task pipTask = createTask(mDisplayContent, WINDOWING_MODE_PINNED,
1124                 ACTIVITY_TYPE_STANDARD);
1125         final ActivityRecord activity = createActivityRecord(pipTask);
1126         final IBinder fragmentToken = new Binder();
1127         spyOn(mWindowOrganizerController);
1128 
1129         // Not allow to create TaskFragment in a PIP Task.
1130         createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
1131         mTransaction.setErrorCallbackToken(mErrorToken);
1132         assertApplyTransactionAllowed(mTransaction);
1133 
1134         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
1135                 eq(mErrorToken), eq(null), eq(OP_TYPE_CREATE_TASK_FRAGMENT),
1136                 any(IllegalArgumentException.class));
1137         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
1138     }
1139 
1140     @Test
testTaskFragmentInPip_deleteTaskFragment()1141     public void testTaskFragmentInPip_deleteTaskFragment() {
1142         setupTaskFragmentInPip();
1143         spyOn(mWindowOrganizerController);
1144 
1145         // Not allow to delete a TaskFragment that is in a PIP Task.
1146         mTransaction.deleteTaskFragment(mFragmentToken)
1147                 .setErrorCallbackToken(mErrorToken);
1148         assertApplyTransactionAllowed(mTransaction);
1149 
1150         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
1151                 eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_DELETE_TASK_FRAGMENT),
1152                 any(IllegalArgumentException.class));
1153         assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
1154 
1155         // Allow organizer to delete empty TaskFragment for cleanup.
1156         final Task task = mTaskFragment.getTask();
1157         mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
1158         assertApplyTransactionAllowed(mTransaction);
1159 
1160         assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
1161         assertNull(task.getTopChild());
1162     }
1163 
1164     @Test
testTaskFragmentInPip_setConfig()1165     public void testTaskFragmentInPip_setConfig() {
1166         setupTaskFragmentInPip();
1167         spyOn(mWindowOrganizerController);
1168 
1169         // Set relative bounds is ignored on a TaskFragment that is in a PIP Task.
1170         mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
1171 
1172         assertApplyTransactionAllowed(mTransaction);
1173 
1174         verify(mTaskFragment, never()).setRelativeEmbeddedBounds(any());
1175     }
1176 
1177     @Test
testDeferPendingTaskFragmentEventsOfInvisibleTask()1178     public void testDeferPendingTaskFragmentEventsOfInvisibleTask() {
1179         final Task task = createTask(mDisplayContent);
1180         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1181                 .setParentTask(task)
1182                 .setOrganizer(mOrganizer)
1183                 .setFragmentToken(mFragmentToken)
1184                 .build();
1185         doReturn(false).when(task).shouldBeVisible(any());
1186 
1187         // Dispatch the initial event in the Task to update the Task visibility to the organizer.
1188         mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
1189         mController.dispatchPendingEvents();
1190         verify(mOrganizer).onTransactionReady(any());
1191 
1192         // Verify that events were not sent when the Task is in background.
1193         clearInvocations(mOrganizer);
1194         final Rect bounds = new Rect(0, 0, 500, 1000);
1195         task.setBoundsUnchecked(bounds);
1196         mController.onTaskFragmentParentInfoChanged(mIOrganizer, task);
1197         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
1198         mController.dispatchPendingEvents();
1199         verify(mOrganizer, never()).onTransactionReady(any());
1200 
1201         // Verify that the events were sent when the Task becomes visible.
1202         doReturn(true).when(task).shouldBeVisible(any());
1203         task.lastActiveTime++;
1204         mController.dispatchPendingEvents();
1205         verify(mOrganizer).onTransactionReady(any());
1206     }
1207 
1208     @Test
testSendAllPendingTaskFragmentEventsWhenAnyTaskIsVisible()1209     public void testSendAllPendingTaskFragmentEventsWhenAnyTaskIsVisible() {
1210         // Invisible Task.
1211         final Task invisibleTask = createTask(mDisplayContent);
1212         final TaskFragment invisibleTaskFragment = new TaskFragmentBuilder(mAtm)
1213                 .setParentTask(invisibleTask)
1214                 .setOrganizer(mOrganizer)
1215                 .setFragmentToken(mFragmentToken)
1216                 .build();
1217         doReturn(false).when(invisibleTask).shouldBeVisible(any());
1218 
1219         // Visible Task.
1220         final IBinder fragmentToken = new Binder();
1221         final Task visibleTask = createTask(mDisplayContent);
1222         final TaskFragment visibleTaskFragment = new TaskFragmentBuilder(mAtm)
1223                 .setParentTask(visibleTask)
1224                 .setOrganizer(mOrganizer)
1225                 .setFragmentToken(fragmentToken)
1226                 .build();
1227         doReturn(true).when(invisibleTask).shouldBeVisible(any());
1228 
1229         // Sending events
1230         invisibleTaskFragment.mTaskFragmentAppearedSent = true;
1231         visibleTaskFragment.mTaskFragmentAppearedSent = true;
1232         mController.onTaskFragmentInfoChanged(mIOrganizer, invisibleTaskFragment);
1233         mController.onTaskFragmentInfoChanged(mIOrganizer, visibleTaskFragment);
1234         mController.dispatchPendingEvents();
1235 
1236         // Verify that both events are sent.
1237         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1238         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1239         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1240 
1241         // There should be two Task info changed with two TaskFragment info changed.
1242         assertEquals(4, changes.size());
1243         // Invisible Task info changed
1244         assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, changes.get(0).getType());
1245         assertEquals(invisibleTask.mTaskId, changes.get(0).getTaskId());
1246         // Invisible TaskFragment info changed
1247         assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, changes.get(1).getType());
1248         assertEquals(invisibleTaskFragment.getFragmentToken(),
1249                 changes.get(1).getTaskFragmentToken());
1250         // Visible Task info changed
1251         assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, changes.get(2).getType());
1252         assertEquals(visibleTask.mTaskId, changes.get(2).getTaskId());
1253         // Visible TaskFragment info changed
1254         assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, changes.get(3).getType());
1255         assertEquals(visibleTaskFragment.getFragmentToken(), changes.get(3).getTaskFragmentToken());
1256     }
1257 
1258     @Test
testCanSendPendingTaskFragmentEventsAfterActivityResumed()1259     public void testCanSendPendingTaskFragmentEventsAfterActivityResumed() {
1260         final Task task = createTask(mDisplayContent);
1261         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1262                 .setParentTask(task)
1263                 .setOrganizer(mOrganizer)
1264                 .setFragmentToken(mFragmentToken)
1265                 .createActivityCount(1)
1266                 .build();
1267         final ActivityRecord activity = taskFragment.getTopMostActivity();
1268         doReturn(false).when(task).shouldBeVisible(any());
1269         taskFragment.setResumedActivity(null, "test");
1270 
1271         // Dispatch the initial event in the Task to update the Task visibility to the organizer.
1272         mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
1273         mController.dispatchPendingEvents();
1274         verify(mOrganizer).onTransactionReady(any());
1275 
1276         // Verify the info changed event is not sent because the Task is invisible
1277         clearInvocations(mOrganizer);
1278         final Rect bounds = new Rect(0, 0, 500, 1000);
1279         task.setBoundsUnchecked(bounds);
1280         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
1281         mController.dispatchPendingEvents();
1282         verify(mOrganizer, never()).onTransactionReady(any());
1283 
1284         // Mock the task becomes visible, and activity resumed. Verify the info changed event is
1285         // sent.
1286         doReturn(true).when(task).shouldBeVisible(any());
1287         taskFragment.setResumedActivity(activity, "test");
1288         mController.dispatchPendingEvents();
1289         verify(mOrganizer).onTransactionReady(any());
1290     }
1291 
1292     /**
1293      * Tests that a task fragment info changed event is still sent if the task is invisible only
1294      * when the info changed event is because of the last activity in a task finishing.
1295      */
1296     @Test
testLastPendingTaskFragmentInfoChangedEventOfInvisibleTaskSent()1297     public void testLastPendingTaskFragmentInfoChangedEventOfInvisibleTaskSent() {
1298         // Create a TaskFragment with an activity, all within a parent task
1299         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1300                 .setOrganizer(mOrganizer)
1301                 .setFragmentToken(mFragmentToken)
1302                 .setCreateParentTask()
1303                 .createActivityCount(1)
1304                 .build();
1305         final Task parentTask = taskFragment.getTask();
1306         final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
1307         assertTrue(parentTask.shouldBeVisible(null));
1308 
1309         // Dispatch pending info changed event from creating the activity
1310         taskFragment.mTaskFragmentAppearedSent = true;
1311         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
1312         mController.dispatchPendingEvents();
1313 
1314         // Finish the activity and verify that the task is invisible
1315         activity.finishing = true;
1316         assertFalse(parentTask.shouldBeVisible(null));
1317 
1318         // Verify the info changed callback still occurred despite the task being invisible
1319         clearInvocations(mOrganizer);
1320         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
1321         mController.dispatchPendingEvents();
1322         verify(mOrganizer).onTransactionReady(any());
1323     }
1324 
1325     /**
1326      * Tests that a task fragment info changed event is sent if the TaskFragment becomes empty
1327      * even if the Task is invisible.
1328      */
1329     @Test
testPendingTaskFragmentInfoChangedEvent_emptyTaskFragment()1330     public void testPendingTaskFragmentInfoChangedEvent_emptyTaskFragment() {
1331         // Create a TaskFragment with an activity, all within a parent task
1332         final Task task = createTask(mDisplayContent);
1333         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1334                 .setParentTask(task)
1335                 .setOrganizer(mOrganizer)
1336                 .setFragmentToken(mFragmentToken)
1337                 .createActivityCount(1)
1338                 .build();
1339         final ActivityRecord embeddedActivity = taskFragment.getTopNonFinishingActivity();
1340         // Add another activity in the Task so that it always contains a non-finishing activity.
1341         createActivityRecord(task);
1342         doReturn(false).when(task).shouldBeVisible(any());
1343 
1344         // Dispatch the initial event in the Task to update the Task visibility to the organizer.
1345         clearInvocations(mOrganizer);
1346         mController.onTaskFragmentAppeared(mIOrganizer, taskFragment);
1347         mController.dispatchPendingEvents();
1348         verify(mOrganizer).onTransactionReady(any());
1349 
1350         // Verify the info changed event is not sent because the Task is invisible
1351         clearInvocations(mOrganizer);
1352         final Rect bounds = new Rect(0, 0, 500, 1000);
1353         task.setBoundsUnchecked(bounds);
1354         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
1355         mController.dispatchPendingEvents();
1356         verify(mOrganizer, never()).onTransactionReady(any());
1357 
1358         // Finish the embedded activity, and verify the info changed event is sent because the
1359         // TaskFragment is becoming empty.
1360         embeddedActivity.finishing = true;
1361         mController.dispatchPendingEvents();
1362         verify(mOrganizer).onTransactionReady(any());
1363     }
1364 
1365     /**
1366      * When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
1367      * {@link WindowOrganizerController}.
1368      */
1369     @Test
testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()1370     public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment() {
1371         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
1372         final IBinder fragmentToken = new Binder();
1373         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
1374         assertApplyTransactionAllowed(mTransaction);
1375         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
1376 
1377         assertNotNull(taskFragment);
1378 
1379         taskFragment.removeImmediately();
1380 
1381         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
1382     }
1383 
1384     /**
1385      * For config change to untrusted embedded TaskFragment, the bounds should be always within
1386      * its parent bounds.
1387      */
1388     @Test
testUntrustedEmbedding_configChange()1389     public void testUntrustedEmbedding_configChange() {
1390         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
1391                 "Test:TaskFragmentOrganizer" /* processName */);
1392         doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
1393         final Task task = createTask(mDisplayContent);
1394         final Rect taskBounds = new Rect(task.getBounds());
1395         task.addChild(mTaskFragment, POSITION_TOP);
1396 
1397         // When set a relative bounds outside of its parent's, it is allowed, but the actual
1398         // TaskFragment bounds will be updated to be fit the parent's bounds.
1399         final Rect tfBounds = new Rect(taskBounds);
1400         tfBounds.right++;
1401         mTransaction.setRelativeBounds(mFragmentWindowToken, tfBounds);
1402         assertApplyTransactionAllowed(mTransaction);
1403 
1404         assertEquals(tfBounds, mTaskFragment.getRelativeEmbeddedBounds());
1405         assertEquals(taskBounds, mTaskFragment.getBounds());
1406     }
1407 
1408     // TODO(b/232871351): add test for minimum dimension violation in startActivityInTaskFragment
1409     @Test
testMinDimensionViolation_ReparentActivityToTaskFragment()1410     public void testMinDimensionViolation_ReparentActivityToTaskFragment() {
1411         final Task task = createTask(mDisplayContent);
1412         final ActivityRecord activity = createActivityRecord(task);
1413         // Make minWidth/minHeight exceeds the TaskFragment bounds.
1414         activity.info.windowLayout = new ActivityInfo.WindowLayout(
1415                 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
1416         mTaskFragment = new TaskFragmentBuilder(mAtm)
1417                 .setParentTask(task)
1418                 .setFragmentToken(mFragmentToken)
1419                 .setOrganizer(mOrganizer)
1420                 .setBounds(mTaskFragBounds)
1421                 .build();
1422         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
1423 
1424         // Reparent activity to mTaskFragment, which is smaller than activity's
1425         // minimum dimensions.
1426         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
1427                 .setErrorCallbackToken(mErrorToken);
1428         assertApplyTransactionAllowed(mTransaction);
1429         // The pending event will be dispatched on the handler (from requestTraversal).
1430         waitHandlerIdle(mWm.mAnimationHandler);
1431 
1432         assertTaskFragmentErrorTransaction(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
1433                 SecurityException.class);
1434     }
1435 
1436     @Test
testMinDimensionViolation_setRelativeBounds()1437     public void testMinDimensionViolation_setRelativeBounds() {
1438         final Task task = createTask(mDisplayContent);
1439         mTaskFragment = new TaskFragmentBuilder(mAtm)
1440                 .setParentTask(task)
1441                 .createActivityCount(1)
1442                 .setFragmentToken(mFragmentToken)
1443                 .setOrganizer(mOrganizer)
1444                 .setBounds(new Rect(0, 0, mTaskFragBounds.right * 2, mTaskFragBounds.bottom * 2))
1445                 .build();
1446         final ActivityRecord activity = mTaskFragment.getTopMostActivity();
1447         // Make minWidth/minHeight exceeds the TaskFragment bounds.
1448         activity.info.windowLayout = new ActivityInfo.WindowLayout(
1449                 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
1450         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
1451         clearInvocations(mAtm.mRootWindowContainer);
1452 
1453         // Shrink the TaskFragment to mTaskFragBounds to make its bounds smaller than activity's
1454         // minimum dimensions.
1455         mTransaction.setRelativeBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(),
1456                         mTaskFragBounds)
1457                 .setErrorCallbackToken(mErrorToken);
1458         assertApplyTransactionAllowed(mTransaction);
1459 
1460         // When the requested bounds do not satisfy the min dimension, it will be reset to empty.
1461         assertWithMessage("setRelativeBounds must not be performed.")
1462                 .that(mTaskFragment.getRelativeEmbeddedBounds()).isEqualTo(new Rect());
1463     }
1464 
1465     @Test
testOnTransactionReady_invokeOnTransactionHandled()1466     public void testOnTransactionReady_invokeOnTransactionHandled() {
1467         final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
1468         mOrganizer.onTransactionReady(transaction);
1469 
1470         // Organizer should always trigger #onTransactionHandled when receives #onTransactionReady
1471         verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
1472                 anyInt(), anyBoolean());
1473         verify(mOrganizer, never()).applyTransaction(any(), anyInt(), anyBoolean());
1474     }
1475 
1476     @Test
testDispatchTransaction_deferTransitionReady()1477     public void testDispatchTransaction_deferTransitionReady() {
1478         setupMockParent(mTaskFragment, mTask);
1479         final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
1480         final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
1481                 ArgumentCaptor.forClass(WindowContainerTransaction.class);
1482         doReturn(true).when(mTransitionController).isCollecting();
1483         doReturn(10).when(mTransitionController).getCollectingTransitionId();
1484 
1485         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
1486         mController.dispatchPendingEvents();
1487 
1488         // Defer transition when send TaskFragment transaction during transition collection.
1489         verify(mTransitionController).deferTransitionReady();
1490         verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture(),
1491                 anyInt(), anyBoolean());
1492 
1493         final IBinder transactionToken = tokenCaptor.getValue();
1494         final WindowContainerTransaction wct = wctCaptor.getValue();
1495         wct.setTaskFragmentOrganizer(mIOrganizer);
1496         mController.onTransactionHandled(transactionToken, wct, TASK_FRAGMENT_TRANSIT_CHANGE,
1497                 false /* shouldApplyIndependently */);
1498 
1499         verify(mTransitionController).continueTransitionReady();
1500     }
1501 
1502     @Test
testWindowOrganizerApplyTransaction_throwException()1503     public void testWindowOrganizerApplyTransaction_throwException() {
1504         // Not allow to use #applyTransaction(WindowContainerTransaction).
1505         assertThrows(RuntimeException.class, () -> mOrganizer.applyTransaction(mTransaction));
1506 
1507         // Allow to use the overload method.
1508         mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
1509                 false /* shouldApplyIndependently */);
1510     }
1511 
1512     @Test
testTaskFragmentTransitionType()1513     public void testTaskFragmentTransitionType() {
1514         // 1-1 relationship with WindowManager.TransitionType
1515         assertEquals(TRANSIT_NONE, TASK_FRAGMENT_TRANSIT_NONE);
1516         assertEquals(TRANSIT_OPEN, TASK_FRAGMENT_TRANSIT_OPEN);
1517         assertEquals(TRANSIT_CLOSE, TASK_FRAGMENT_TRANSIT_CLOSE);
1518         assertEquals(TRANSIT_CHANGE, TASK_FRAGMENT_TRANSIT_CHANGE);
1519     }
1520 
1521     @Test
testApplyTransaction_setRelativeBounds()1522     public void testApplyTransaction_setRelativeBounds() {
1523         final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
1524                 ACTIVITY_TYPE_STANDARD);
1525         mTaskFragment = new TaskFragmentBuilder(mAtm)
1526                 .setParentTask(task)
1527                 .setFragmentToken(mFragmentToken)
1528                 .build();
1529         final WindowContainerToken token = mTaskFragment.mRemoteToken.toWindowContainerToken();
1530         final Rect relBounds = new Rect(0, 0, 100, 1000);
1531         mTransaction.setRelativeBounds(token, relBounds);
1532 
1533         // Not allowed because TaskFragment is not organized by the caller organizer.
1534         assertApplyTransactionDisallowed(mTransaction);
1535 
1536         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
1537                 "Test:TaskFragmentOrganizer" /* processName */);
1538 
1539         assertApplyTransactionAllowed(mTransaction);
1540         assertEquals(relBounds, mTaskFragment.getRelativeEmbeddedBounds());
1541         assertEquals(relBounds, mTaskFragment.getBounds());
1542 
1543         // TaskFragment bounds should be updated to the same relative bounds.
1544         final Rect taskBounds = new Rect(200, 200, 700, 1500);
1545         task.setBoundsUnchecked(taskBounds);
1546         assertEquals(taskBounds, task.getBounds());
1547         assertEquals(relBounds, mTaskFragment.getRelativeEmbeddedBounds());
1548         assertEquals(mTaskFragment.translateRelativeBoundsToAbsoluteBounds(relBounds, taskBounds),
1549                 mTaskFragment.getBounds());
1550         assertEquals(new Rect(200, 200, 300, 1200), mTaskFragment.getBounds());
1551 
1552         // Set TaskFragment to fill Task
1553         mTransaction.setRelativeBounds(token, new Rect());
1554 
1555         assertApplyTransactionAllowed(mTransaction);
1556         assertEquals(new Rect(), mTaskFragment.getRelativeEmbeddedBounds());
1557         assertEquals(taskBounds, mTaskFragment.getBounds());
1558     }
1559 
1560     @Test
testUntrustedEmbedding_setRelativeBounds_adjustToTaskBounds()1561     public void testUntrustedEmbedding_setRelativeBounds_adjustToTaskBounds() {
1562         final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
1563                 ACTIVITY_TYPE_STANDARD);
1564         mTaskFragment = new TaskFragmentBuilder(mAtm)
1565                 .setParentTask(task)
1566                 .setFragmentToken(mFragmentToken)
1567                 .build();
1568         final WindowContainerToken token = mTaskFragment.mRemoteToken.toWindowContainerToken();
1569         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
1570                 "Test:TaskFragmentOrganizer" /* processName */);
1571         // Untrusted embedded
1572         doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
1573 
1574         final Rect taskBounds = new Rect(0, 0, 500, 1000);
1575         task.setBoundsUnchecked(taskBounds);
1576 
1577         final Rect taskFragmentBounds = new Rect(250, 0, 750, 1000);
1578         mTransaction.setRelativeBounds(token, taskFragmentBounds);
1579 
1580         // Allow operation in case the Task is also resizing.
1581         // Adjust the relBounds to the intersection.
1582         assertApplyTransactionAllowed(mTransaction);
1583         // Relative bounds is correctly set.
1584         assertEquals(taskFragmentBounds, mTaskFragment.getRelativeEmbeddedBounds());
1585         // The actual window bounds is adjusted to fit the Task bounds.
1586         assertEquals(new Rect(250, 0, 500, 1000), mTaskFragment.getBounds());
1587 
1588         // Adjust to the full requested bounds when the Task is resized.
1589         taskBounds.set(0, 0, 750, 1000);
1590         task.setBoundsUnchecked(taskBounds);
1591         assertEquals(taskFragmentBounds, mTaskFragment.getBounds());
1592     }
1593 
1594     @Test
testApplyTransaction_reorderTaskFragmentToFront()1595     public void testApplyTransaction_reorderTaskFragmentToFront() {
1596         final Task task = createTask(mDisplayContent);
1597         // Create a TaskFragment.
1598         final IBinder token0 = new Binder();
1599         final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
1600                 .setParentTask(task)
1601                 .setFragmentToken(token0)
1602                 .setOrganizer(mOrganizer)
1603                 .createActivityCount(1)
1604                 .build();
1605         // Create another TaskFragment
1606         final IBinder token1 = new Binder();
1607         final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
1608                 .setParentTask(task)
1609                 .setFragmentToken(token1)
1610                 .setOrganizer(mOrganizer)
1611                 .createActivityCount(1)
1612                 .build();
1613         // Create a non-embedded Activity on top.
1614         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1615                 .setTask(task)
1616                 .build();
1617         mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
1618         mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
1619 
1620         // Reorder TaskFragment to front
1621         final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
1622                 OP_TYPE_REORDER_TO_FRONT).build();
1623         mTransaction.addTaskFragmentOperation(token0, operation);
1624         assertApplyTransactionAllowed(mTransaction);
1625 
1626         // Ensure the non-embedded activity still on top.
1627         assertEquals(topActivity, task.getTopChild().asActivityRecord());
1628 
1629         // Ensure the TaskFragment is moved to front.
1630         final TaskFragment frontMostTaskFragment = task.getTaskFragment(tf -> tf.asTask() == null);
1631         assertEquals(frontMostTaskFragment, tf0);
1632     }
1633 
1634     /**
1635      * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
1636      * {@link WindowOrganizerController#applyTransaction(WindowContainerTransaction)} to apply the
1637      * transaction,
1638      */
createTaskFragmentFromOrganizer(WindowContainerTransaction wct, ActivityRecord ownerActivity, IBinder fragmentToken)1639     private void createTaskFragmentFromOrganizer(WindowContainerTransaction wct,
1640             ActivityRecord ownerActivity, IBinder fragmentToken) {
1641         final int uid = Binder.getCallingUid();
1642         ownerActivity.info.applicationInfo.uid = uid;
1643         ownerActivity.getTask().effectiveUid = uid;
1644         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
1645                 mOrganizerToken, fragmentToken, ownerActivity.token).build();
1646         wct.setTaskFragmentOrganizer(mIOrganizer);
1647 
1648         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
1649         wct.createTaskFragment(params);
1650     }
1651 
1652     /** Asserts that applying the given transaction will throw a {@link SecurityException}. */
assertApplyTransactionDisallowed(WindowContainerTransaction t)1653     private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
1654         assertThrows(SecurityException.class, () ->
1655                 mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE,
1656                         false /* shouldApplyIndependently */));
1657     }
1658 
1659     /** Asserts that applying the given transaction will not throw any exception. */
assertApplyTransactionAllowed(WindowContainerTransaction t)1660     private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
1661         mController.applyTransaction(t, TASK_FRAGMENT_TRANSIT_CHANGE,
1662                 false /* shouldApplyIndependently */);
1663     }
1664 
1665     /** Asserts that there will be a transaction for TaskFragment appeared. */
assertTaskFragmentAppearedTransaction()1666     private void assertTaskFragmentAppearedTransaction() {
1667         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1668         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1669         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1670         assertFalse(changes.isEmpty());
1671 
1672         // Use remove to verify multiple transaction changes.
1673         final TaskFragmentTransaction.Change change = changes.remove(0);
1674         assertEquals(TYPE_TASK_FRAGMENT_APPEARED, change.getType());
1675         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
1676         assertEquals(mFragmentToken, change.getTaskFragmentToken());
1677     }
1678 
1679     /** Asserts that there will be a transaction for TaskFragment info changed. */
assertTaskFragmentInfoChangedTransaction()1680     private void assertTaskFragmentInfoChangedTransaction() {
1681         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1682         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1683         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1684         assertFalse(changes.isEmpty());
1685 
1686         // Use remove to verify multiple transaction changes.
1687         final TaskFragmentTransaction.Change change = changes.remove(0);
1688         assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, change.getType());
1689         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
1690         assertEquals(mFragmentToken, change.getTaskFragmentToken());
1691     }
1692 
1693     /** Asserts that there will be a transaction for TaskFragment vanished. */
assertTaskFragmentVanishedTransaction()1694     private void assertTaskFragmentVanishedTransaction() {
1695         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1696         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1697         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1698         assertFalse(changes.isEmpty());
1699 
1700         // Use remove to verify multiple transaction changes.
1701         final TaskFragmentTransaction.Change change = changes.remove(0);
1702         assertEquals(TYPE_TASK_FRAGMENT_VANISHED, change.getType());
1703         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
1704         assertEquals(mFragmentToken, change.getTaskFragmentToken());
1705     }
1706 
1707     /** Asserts that there will be a transaction for TaskFragment vanished. */
assertTaskFragmentParentInfoChangedTransaction(@onNull Task task)1708     private void assertTaskFragmentParentInfoChangedTransaction(@NonNull Task task) {
1709         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1710         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1711         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1712         assertFalse(changes.isEmpty());
1713 
1714         // Use remove to verify multiple transaction changes.
1715         final TaskFragmentTransaction.Change change = changes.remove(0);
1716         assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, change.getType());
1717         assertEquals(task.mTaskId, change.getTaskId());
1718         assertEquals(task.getTaskFragmentParentInfo(), change.getTaskFragmentParentInfo());
1719     }
1720 
1721     /** Asserts that there will be a transaction for TaskFragment error. */
assertTaskFragmentErrorTransaction(@askFragmentOperation.OperationType int opType, @NonNull Class<?> exceptionClass)1722     private void assertTaskFragmentErrorTransaction(@TaskFragmentOperation.OperationType int opType,
1723             @NonNull Class<?> exceptionClass) {
1724         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1725         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1726         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1727         assertFalse(changes.isEmpty());
1728 
1729         // Use remove to verify multiple transaction changes.
1730         final TaskFragmentTransaction.Change change = changes.remove(0);
1731         assertEquals(TYPE_TASK_FRAGMENT_ERROR, change.getType());
1732         assertEquals(mErrorToken, change.getErrorCallbackToken());
1733         final Bundle errorBundle = change.getErrorBundle();
1734         assertEquals(opType, errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE));
1735         assertEquals(exceptionClass, errorBundle.getSerializable(
1736                 KEY_ERROR_CALLBACK_THROWABLE, Throwable.class).getClass());
1737     }
1738 
1739     /** Asserts that there will be a transaction for activity reparented to Task. */
assertActivityReparentedToTaskTransaction(int taskId, @NonNull Intent intent, @NonNull IBinder activityToken)1740     private void assertActivityReparentedToTaskTransaction(int taskId, @NonNull Intent intent,
1741             @NonNull IBinder activityToken) {
1742         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
1743         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
1744         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
1745         assertFalse(changes.isEmpty());
1746 
1747         // Use remove to verify multiple transaction changes.
1748         final TaskFragmentTransaction.Change change = changes.remove(0);
1749         assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType());
1750         assertEquals(taskId, change.getTaskId());
1751         assertIntentsEqualForOrganizer(intent, change.getActivityIntent());
1752         assertIntentTrimmed(change.getActivityIntent());
1753         assertEquals(activityToken, change.getActivityToken());
1754     }
1755 
1756     /** Setups an embedded TaskFragment in a PIP Task. */
setupTaskFragmentInPip()1757     private void setupTaskFragmentInPip() {
1758         mTaskFragment = new TaskFragmentBuilder(mAtm)
1759                 .setCreateParentTask()
1760                 .setFragmentToken(mFragmentToken)
1761                 .setOrganizer(mOrganizer)
1762                 .createActivityCount(1)
1763                 .build();
1764         mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
1765         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
1766         mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
1767     }
1768 
1769     /** Setups the mock Task as the parent of the given TaskFragment. */
setupMockParent(TaskFragment taskFragment, Task mockParent)1770     private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
1771         doReturn(mockParent).when(taskFragment).getTask();
1772         doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true))
1773                 .when(mockParent).getTaskFragmentParentInfo();
1774 
1775         // Task needs to be visible
1776         mockParent.lastActiveTime = 100;
1777         doReturn(true).when(mockParent).shouldBeVisible(any());
1778     }
1779 
assertIntentsEqualForOrganizer(@onNull Intent expected, @NonNull Intent actual)1780     private static void assertIntentsEqualForOrganizer(@NonNull Intent expected,
1781             @NonNull Intent actual) {
1782         assertEquals(expected.getComponent(), actual.getComponent());
1783         assertEquals(expected.getPackage(), actual.getPackage());
1784         assertEquals(expected.getAction(), actual.getAction());
1785     }
1786 
assertIntentTrimmed(@onNull Intent intent)1787     private static void assertIntentTrimmed(@NonNull Intent intent) {
1788         assertNull(intent.getData());
1789         assertNull(intent.getExtras());
1790         assertEquals(0, intent.getFlags());
1791     }
1792 }
1793