1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.am;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
23 import static android.view.Display.DEFAULT_DISPLAY;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.doNothing;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.any;
28 import static org.mockito.Mockito.anyBoolean;
29 import static org.mockito.Mockito.anyInt;
30 import static org.mockito.Mockito.doAnswer;
31 import static org.mockito.Mockito.spy;
32 
33 import android.app.ActivityOptions;
34 import com.android.server.wm.DisplayWindowController;
35 
36 import org.junit.Rule;
37 import org.mockito.invocation.InvocationOnMock;
38 
39 import android.app.IApplicationThread;
40 import android.content.ComponentName;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.pm.ActivityInfo;
44 import android.content.pm.ApplicationInfo;
45 import android.content.pm.IPackageManager;
46 import android.content.res.Configuration;
47 import android.graphics.Rect;
48 import android.hardware.display.DisplayManager;
49 import android.os.HandlerThread;
50 import android.os.Looper;
51 import android.service.voice.IVoiceInteractionSession;
52 import android.support.test.InstrumentationRegistry;
53 import android.testing.DexmakerShareClassLoaderRule;
54 
55 
56 import com.android.internal.app.IVoiceInteractor;
57 
58 import com.android.server.AttributeCache;
59 import com.android.server.wm.AppWindowContainerController;
60 import com.android.server.wm.PinnedStackWindowController;
61 import com.android.server.wm.StackWindowController;
62 import com.android.server.wm.TaskWindowContainerController;
63 import com.android.server.wm.WindowManagerService;
64 import com.android.server.wm.WindowTestUtils;
65 import org.junit.After;
66 import org.junit.Before;
67 import org.mockito.MockitoAnnotations;
68 
69 
70 /**
71  * A base class to handle common operations in activity related unit tests.
72  */
73 public class ActivityTestsBase {
74     private static boolean sOneTimeSetupDone = false;
75 
76     @Rule
77     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
78             new DexmakerShareClassLoaderRule();
79 
80     private final Context mContext = InstrumentationRegistry.getContext();
81     private HandlerThread mHandlerThread;
82 
83     // Default package name
84     static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
85 
86     // Default base activity name
87     private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
88 
89     @Before
setUp()90     public void setUp() throws Exception {
91         if (!sOneTimeSetupDone) {
92             sOneTimeSetupDone = true;
93             MockitoAnnotations.initMocks(this);
94         }
95         mHandlerThread = new HandlerThread("ActivityTestsBaseThread");
96         mHandlerThread.start();
97     }
98 
99     @After
tearDown()100     public void tearDown() {
101         mHandlerThread.quitSafely();
102     }
103 
createActivityManagerService()104     protected ActivityManagerService createActivityManagerService() {
105         final ActivityManagerService service =
106                 setupActivityManagerService(new TestActivityManagerService(mContext));
107         AttributeCache.init(mContext);
108         return service;
109     }
110 
setupActivityManagerService(ActivityManagerService service)111     protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) {
112         service = spy(service);
113         doReturn(mock(IPackageManager.class)).when(service).getPackageManager();
114         doNothing().when(service).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
115         service.mWindowManager = prepareMockWindowManager();
116         return service;
117     }
118 
119     /**
120      * Builder for creating new activities.
121      */
122     protected static class ActivityBuilder {
123         // An id appended to the end of the component name to make it unique
124         private static int sCurrentActivityId = 0;
125 
126 
127 
128         private final ActivityManagerService mService;
129 
130         private ComponentName mComponent;
131         private TaskRecord mTaskRecord;
132         private int mUid;
133         private boolean mCreateTask;
134         private ActivityStack mStack;
135         private int mActivityFlags;
136 
ActivityBuilder(ActivityManagerService service)137         ActivityBuilder(ActivityManagerService service) {
138             mService = service;
139         }
140 
setComponent(ComponentName component)141         ActivityBuilder setComponent(ComponentName component) {
142             mComponent = component;
143             return this;
144         }
145 
getDefaultComponent()146         static ComponentName getDefaultComponent() {
147             return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
148                     DEFAULT_COMPONENT_PACKAGE_NAME);
149         }
150 
setTask(TaskRecord task)151         ActivityBuilder setTask(TaskRecord task) {
152             mTaskRecord = task;
153             return this;
154         }
155 
setActivityFlags(int flags)156         ActivityBuilder setActivityFlags(int flags) {
157             mActivityFlags = flags;
158             return this;
159         }
160 
setStack(ActivityStack stack)161         ActivityBuilder setStack(ActivityStack stack) {
162             mStack = stack;
163             return this;
164         }
165 
setCreateTask(boolean createTask)166         ActivityBuilder setCreateTask(boolean createTask) {
167             mCreateTask = createTask;
168             return this;
169         }
170 
setUid(int uid)171         ActivityBuilder setUid(int uid) {
172             mUid = uid;
173             return this;
174         }
175 
build()176         ActivityRecord build() {
177             if (mComponent == null) {
178                 final int id = sCurrentActivityId++;
179                 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
180                         DEFAULT_COMPONENT_CLASS_NAME + id);
181             }
182 
183             if (mCreateTask) {
184                 mTaskRecord = new TaskBuilder(mService.mStackSupervisor)
185                         .setComponent(mComponent)
186                         .setStack(mStack).build();
187             }
188 
189             Intent intent = new Intent();
190             intent.setComponent(mComponent);
191             final ActivityInfo aInfo = new ActivityInfo();
192             aInfo.applicationInfo = new ApplicationInfo();
193             aInfo.applicationInfo.packageName = mComponent.getPackageName();
194             aInfo.applicationInfo.uid = mUid;
195             aInfo.flags |= mActivityFlags;
196 
197             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
198                     0 /* launchedFromPid */, 0, null, intent, null,
199                     aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
200                     0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
201                     mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
202             activity.mWindowContainerController = mock(AppWindowContainerController.class);
203 
204             if (mTaskRecord != null) {
205                 mTaskRecord.addActivityToTop(activity);
206             }
207 
208             activity.setProcess(new ProcessRecord(null, null,
209                     mService.mContext.getApplicationInfo(), "name", 12345));
210             activity.app.thread = mock(IApplicationThread.class);
211 
212             return activity;
213         }
214     }
215 
216     /**
217      * Builder for creating new tasks.
218      */
219     protected static class TaskBuilder {
220         // Default package name
221         static final String DEFAULT_PACKAGE = "com.bar";
222 
223         private final ActivityStackSupervisor mSupervisor;
224 
225         private ComponentName mComponent;
226         private String mPackage;
227         private int mFlags = 0;
228         private int mTaskId = 0;
229         private int mUserId = 0;
230         private IVoiceInteractionSession mVoiceSession;
231         private boolean mCreateStack = true;
232 
233         private ActivityStack mStack;
234 
TaskBuilder(ActivityStackSupervisor supervisor)235         TaskBuilder(ActivityStackSupervisor supervisor) {
236             mSupervisor = supervisor;
237         }
238 
setComponent(ComponentName component)239         TaskBuilder setComponent(ComponentName component) {
240             mComponent = component;
241             return this;
242         }
243 
setPackage(String packageName)244         TaskBuilder setPackage(String packageName) {
245             mPackage = packageName;
246             return this;
247         }
248 
249         /**
250          * Set to {@code true} by default, set to {@code false} to prevent the task from
251          * automatically creating a parent stack.
252          */
setCreateStack(boolean createStack)253         TaskBuilder setCreateStack(boolean createStack) {
254             mCreateStack = createStack;
255             return this;
256         }
257 
setVoiceSession(IVoiceInteractionSession session)258         TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
259             mVoiceSession = session;
260             return this;
261         }
262 
setFlags(int flags)263         TaskBuilder setFlags(int flags) {
264             mFlags = flags;
265             return this;
266         }
267 
setTaskId(int taskId)268         TaskBuilder setTaskId(int taskId) {
269             mTaskId = taskId;
270             return this;
271         }
272 
setUserId(int userId)273         TaskBuilder setUserId(int userId) {
274             mUserId = userId;
275             return this;
276         }
277 
setStack(ActivityStack stack)278         TaskBuilder setStack(ActivityStack stack) {
279             mStack = stack;
280             return this;
281         }
282 
build()283         TaskRecord build() {
284             if (mStack == null && mCreateStack) {
285                 mStack = mSupervisor.getDefaultDisplay().createStack(
286                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
287             }
288 
289             final ActivityInfo aInfo = new ActivityInfo();
290             aInfo.applicationInfo = new ApplicationInfo();
291             aInfo.applicationInfo.packageName = mPackage;
292 
293             Intent intent = new Intent();
294             if (mComponent == null) {
295                 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
296                         DEFAULT_COMPONENT_CLASS_NAME);
297             }
298 
299             intent.setComponent(mComponent);
300             intent.setFlags(mFlags);
301 
302             final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo,
303                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
304             task.userId = mUserId;
305 
306             if (mStack != null) {
307                 mSupervisor.setFocusStackUnchecked("test", mStack);
308                 mStack.addTask(task, true, "creating test task");
309                 task.setStack(mStack);
310                 task.setWindowContainerController();
311             }
312 
313             task.touchActiveTime();
314 
315             return task;
316         }
317 
318         private static class TestTaskRecord extends TaskRecord {
TestTaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor)319             TestTaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info,
320                        Intent _intent, IVoiceInteractionSession _voiceSession,
321                        IVoiceInteractor _voiceInteractor) {
322                 super(service, _taskId, info, _intent, _voiceSession, _voiceInteractor);
323             }
324 
325             @Override
createWindowContainer(boolean onTop, boolean showForAllUsers)326             void createWindowContainer(boolean onTop, boolean showForAllUsers) {
327                 setWindowContainerController();
328             }
329 
setWindowContainerController()330             private void setWindowContainerController() {
331                 setWindowContainerController(mock(TaskWindowContainerController.class));
332             }
333         }
334     }
335 
336     /**
337      * An {@link ActivityManagerService} subclass which provides a test
338      * {@link ActivityStackSupervisor}.
339      */
340     protected static class TestActivityManagerService extends ActivityManagerService {
341         private ClientLifecycleManager mLifecycleManager;
342         private LockTaskController mLockTaskController;
343 
TestActivityManagerService(Context context)344         TestActivityManagerService(Context context) {
345             super(context);
346             mSupportsMultiWindow = true;
347             mSupportsMultiDisplay = true;
348             mSupportsSplitScreenMultiWindow = true;
349             mSupportsFreeformWindowManagement = true;
350             mSupportsPictureInPicture = true;
351             mWindowManager = WindowTestUtils.getMockWindowManagerService();
352         }
353 
354         @Override
getLifecycleManager()355         public ClientLifecycleManager getLifecycleManager() {
356             if (mLifecycleManager == null) {
357                 return super.getLifecycleManager();
358             }
359             return mLifecycleManager;
360         }
361 
getLockTaskController()362         public LockTaskController getLockTaskController() {
363             if (mLockTaskController == null) {
364                 mLockTaskController = spy(super.getLockTaskController());
365             }
366 
367             return mLockTaskController;
368         }
369 
setLifecycleManager(ClientLifecycleManager manager)370         void setLifecycleManager(ClientLifecycleManager manager) {
371             mLifecycleManager = manager;
372         }
373 
374         @Override
createStackSupervisor()375         final protected ActivityStackSupervisor createStackSupervisor() {
376             final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
377             final KeyguardController keyguardController = mock(KeyguardController.class);
378 
379             // No home stack is set.
380             doNothing().when(supervisor).moveHomeStackToFront(any());
381             doReturn(true).when(supervisor).moveHomeStackTaskToTop(any());
382             // Invoked during {@link ActivityStack} creation.
383             doNothing().when(supervisor).updateUIDsPresentOnDisplay();
384             // Always keep things awake.
385             doReturn(true).when(supervisor).hasAwakeDisplay();
386             // Called when moving activity to pinned stack.
387             doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean());
388             // Do not schedule idle timeouts
389             doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
390             // unit test version does not handle launch wake lock
391             doNothing().when(supervisor).acquireLaunchWakelock();
392             doReturn(keyguardController).when(supervisor).getKeyguardController();
393 
394             supervisor.initialize();
395 
396             return supervisor;
397         }
398 
createTestSupervisor()399         protected ActivityStackSupervisor createTestSupervisor() {
400             return new TestActivityStackSupervisor(this, mHandlerThread.getLooper());
401         }
402 
403         @Override
updateUsageStats(ActivityRecord component, boolean resumed)404         void updateUsageStats(ActivityRecord component, boolean resumed) {
405         }
406     }
407 
408     /**
409      * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
410      * setup not available in the test environment. Also specifies an injector for
411      */
412     protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
413         private ActivityDisplay mDisplay;
414         private KeyguardController mKeyguardController;
415 
TestActivityStackSupervisor(ActivityManagerService service, Looper looper)416         public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
417             super(service, looper);
418             mDisplayManager =
419                     (DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
420             mWindowManager = prepareMockWindowManager();
421             mKeyguardController = mock(KeyguardController.class);
422         }
423 
424         @Override
initialize()425         public void initialize() {
426             super.initialize();
427             mDisplay = spy(new TestActivityDisplay(this, DEFAULT_DISPLAY));
428             attachDisplay(mDisplay);
429         }
430 
431         @Override
getKeyguardController()432         public KeyguardController getKeyguardController() {
433             return mKeyguardController;
434         }
435 
436         @Override
getDefaultDisplay()437         ActivityDisplay getDefaultDisplay() {
438             return mDisplay;
439         }
440 
441         // Just return the current front task. This is called internally so we cannot use spy to mock this out.
442         @Override
getNextFocusableStackLocked(ActivityStack currentFocus, boolean ignoreCurrent)443         ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus,
444                 boolean ignoreCurrent) {
445             return mFocusedStack;
446         }
447     }
448 
449     protected static class TestActivityDisplay extends ActivityDisplay {
450 
451         private final ActivityStackSupervisor mSupervisor;
TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId)452         TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
453             super(supervisor, displayId);
454             mSupervisor = supervisor;
455         }
456 
457         @Override
createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop)458         <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
459                 int stackId, boolean onTop) {
460             if (windowingMode == WINDOWING_MODE_PINNED) {
461                 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop) {
462                     @Override
463                     Rect getDefaultPictureInPictureBounds(float aspectRatio) {
464                         return new Rect(50, 50, 100, 100);
465                     }
466 
467                     @Override
468                     PinnedStackWindowController createStackWindowController(int displayId,
469                             boolean onTop, Rect outBounds) {
470                         return mock(PinnedStackWindowController.class);
471                     }
472                 };
473             } else {
474                 return (T) new TestActivityStack(
475                         this, stackId, mSupervisor, windowingMode, activityType, onTop);
476             }
477         }
478 
479         @Override
createWindowContainerController()480         protected DisplayWindowController createWindowContainerController() {
481             return mock(DisplayWindowController.class);
482         }
483     }
484 
485     private static WindowManagerService prepareMockWindowManager() {
486         final WindowManagerService service = WindowTestUtils.getMockWindowManagerService();
487 
488         doAnswer((InvocationOnMock invocationOnMock) -> {
489             final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
490             if (runnable != null) {
491                 runnable.run();
492             }
493             return null;
494         }).when(service).inSurfaceTransaction(any());
495 
496         return service;
497     }
498 
499     /**
500      * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a
501      * method is called. Note that its functionality depends on the implementations of the
502      * construction arguments.
503      */
504     protected static class TestActivityStack<T extends StackWindowController>
505             extends ActivityStack<T> {
506         private int mOnActivityRemovedFromStackCount = 0;
507         private T mContainerController;
508 
509         static final int IS_TRANSLUCENT_UNSET = 0;
510         static final int IS_TRANSLUCENT_FALSE = 1;
511         static final int IS_TRANSLUCENT_TRUE = 2;
512         private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
513 
514         static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0;
515         static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1;
516         static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2;
517         private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET;
518 
519         TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
520                 int windowingMode, int activityType, boolean onTop) {
521             super(display, stackId, supervisor, windowingMode, activityType, onTop);
522         }
523 
524         @Override
525         void onActivityRemovedFromStack(ActivityRecord r) {
526             mOnActivityRemovedFromStackCount++;
527             super.onActivityRemovedFromStack(r);
528         }
529 
530         // Returns the number of times {@link #onActivityRemovedFromStack} has been called
531         int onActivityRemovedFromStackInvocationCount() {
532             return mOnActivityRemovedFromStackCount;
533         }
534 
535         @Override
536         protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
537             mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
538 
539             // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
540             // will be moved to the full screen stack.
541             if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
542                 outBounds.set(0, 0, 100, 100);
543             }
544             return mContainerController;
545         }
546 
547         @Override
548         T getWindowContainerController() {
549             return mContainerController;
550         }
551 
552         void setIsTranslucent(boolean isTranslucent) {
553             mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE;
554         }
555 
556         @Override
557         boolean isStackTranslucent(ActivityRecord starting) {
558             switch (mIsTranslucent) {
559                 case IS_TRANSLUCENT_TRUE:
560                     return true;
561                 case IS_TRANSLUCENT_FALSE:
562                     return false;
563                 case IS_TRANSLUCENT_UNSET:
564                 default:
565                     return super.isStackTranslucent(starting);
566             }
567         }
568 
569         void setSupportsSplitScreen(boolean supportsSplitScreen) {
570             mSupportsSplitScreen = supportsSplitScreen
571                     ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE;
572         }
573 
574         @Override
575         public boolean supportsSplitScreenWindowingMode() {
576             switch (mSupportsSplitScreen) {
577                 case SUPPORTS_SPLIT_SCREEN_TRUE:
578                     return true;
579                 case SUPPORTS_SPLIT_SCREEN_FALSE:
580                     return false;
581                 case SUPPORTS_SPLIT_SCREEN_UNSET:
582                 default:
583                     return super.supportsSplitScreenWindowingMode();
584             }
585         }
586 
587         @Override
588         void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
589                                  boolean newTask, boolean keepCurTransition,
590                                  ActivityOptions options) {
591         }
592     }
593 }
594