ActivityTestsBase.java revision 9c844410572cd432f589d3e1c5a8ea5b67647775
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.am;
18
19import static org.mockito.Mockito.mock;
20import static org.mockito.Mockito.doReturn;
21import static org.mockito.Mockito.any;
22import static org.mockito.Mockito.doAnswer;
23
24import org.mockito.invocation.InvocationOnMock;
25
26import android.app.ActivityManager;
27import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
30import android.content.pm.ActivityInfo;
31import android.content.pm.ApplicationInfo;
32import android.content.res.Configuration;
33import android.graphics.Rect;
34import android.os.HandlerThread;
35import android.os.Looper;
36import android.support.test.InstrumentationRegistry;
37import com.android.server.AttributeCache;
38import com.android.server.wm.AppWindowContainerController;
39import com.android.server.wm.StackWindowController;
40
41import com.android.server.wm.TaskWindowContainerController;
42import com.android.server.wm.WindowManagerService;
43import com.android.server.wm.WindowTestUtils;
44import org.junit.After;
45import org.junit.Before;
46import org.mockito.MockitoAnnotations;
47
48/**
49 * A base class to handle common operations in activity related unit tests.
50 */
51public class ActivityTestsBase {
52    private final Context mContext = InstrumentationRegistry.getContext();
53    private HandlerThread mHandlerThread;
54
55    // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must
56    // be called at before any tests.
57    private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext);
58
59    @Before
60    public void setUp() throws Exception {
61        MockitoAnnotations.initMocks(this);
62        mHandlerThread = new HandlerThread("ActivityTestsBaseThread");
63        mHandlerThread.start();
64    }
65
66    @After
67    public void tearDown() {
68        mHandlerThread.quitSafely();
69    }
70
71    protected ActivityManagerService createActivityManagerService() {
72        final ActivityManagerService service = new TestActivityManagerService(mContext);
73        service.mWindowManager = WindowTestUtils.getMockWindowManagerService();
74        return service;
75    }
76
77    protected static ActivityStack createActivityStack(ActivityManagerService service,
78            int stackId, int displayId, boolean onTop) {
79        if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
80            return ((TestActivityStackSupervisor) service.mStackSupervisor)
81                    .createTestStack(service, stackId, onTop);
82        }
83
84        return null;
85    }
86
87    protected static ActivityRecord createActivity(ActivityManagerService service,
88            ComponentName component, TaskRecord task) {
89        Intent intent = new Intent();
90        intent.setComponent(component);
91        final ActivityInfo aInfo = new ActivityInfo();
92        aInfo.applicationInfo = new ApplicationInfo();
93        aInfo.applicationInfo.packageName = component.getPackageName();
94        AttributeCache.init(service.mContext);
95        final ActivityRecord activity = new ActivityRecord(service, null /* caller */,
96                0 /* launchedFromPid */, 0, null, intent, null,
97                aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
98                0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
99                service.mStackSupervisor, null /* container */, null /* options */,
100                null /* sourceRecord */);
101        activity.mWindowContainerController = mock(AppWindowContainerController.class);
102
103        if (task != null) {
104            task.addActivityToTop(activity);
105        }
106
107        return activity;
108    }
109
110    protected static TaskRecord createTask(ActivityManagerService service,
111            ComponentName component, int stackId) {
112        final ActivityInfo aInfo = new ActivityInfo();
113        aInfo.applicationInfo = new ApplicationInfo();
114        aInfo.applicationInfo.packageName = component.getPackageName();
115
116        Intent intent = new Intent();
117        intent.setComponent(component);
118
119        final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
120                null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo());
121        final ActivityStack stack = service.mStackSupervisor.getStack(stackId,
122                true /*createStaticStackIfNeeded*/, true /*onTop*/);
123        stack.addTask(task, true, "creating test task");
124        task.setStack(stack);
125        task.setWindowContainerController(mock(TaskWindowContainerController.class));
126
127        return task;
128    }
129
130
131    /**
132     * An {@link ActivityManagerService} subclass which provides a test
133     * {@link ActivityStackSupervisor}.
134     */
135    protected static class TestActivityManagerService extends ActivityManagerService {
136        public TestActivityManagerService(Context context) {
137            super(context);
138            mSupportsMultiWindow = true;
139            mSupportsMultiDisplay = true;
140            mWindowManager = WindowTestUtils.getWindowManagerService(context);
141        }
142
143        @Override
144        protected ActivityStackSupervisor createStackSupervisor() {
145            return new TestActivityStackSupervisor(this, mHandlerThread.getLooper());
146        }
147    }
148
149    /**
150     * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
151     * setup not available in the test environment. Also specifies an injector for
152     */
153    protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
154        public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
155            super(service, looper);
156            mWindowManager = prepareMockWindowManager();
157        }
158
159        // No home stack is set.
160        @Override
161        void moveHomeStackToFront(String reason) {
162        }
163
164        @Override
165        boolean moveHomeStackTaskToTop(String reason) {
166            return true;
167        }
168
169        // Invoked during {@link ActivityStack} creation.
170        @Override
171        void updateUIDsPresentOnDisplay() {
172        }
173
174        // Just return the current front task.
175        @Override
176        ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
177            return mFocusedStack;
178        }
179
180        // Called when moving activity to pinned stack.
181        @Override
182        void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
183                boolean preserveWindows) {
184        }
185
186        public <T extends ActivityStack> T createTestStack(ActivityManagerService service,
187                int stackId, boolean onTop) {
188            final ActivityDisplay display = new ActivityDisplay();
189            final TestActivityContainer container =
190                    new TestActivityContainer(service, stackId, display, onTop);
191            mActivityContainers.put(stackId, container);
192            return (T) container.getStack();
193        }
194
195        @Override
196        protected <T extends ActivityStack> T getStack(int stackId,
197                boolean createStaticStackIfNeeded, boolean createOnTop) {
198            final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop);
199
200            if (stack != null || !createStaticStackIfNeeded) {
201                return stack;
202            }
203
204            return createTestStack(mService, stackId, createOnTop);
205        }
206
207        private class TestActivityContainer extends ActivityContainer {
208            private final ActivityManagerService mService;
209
210            private boolean mOnTop;
211            private int mStackId;
212            private ActivityStack mStack;
213
214            TestActivityContainer(ActivityManagerService service, int stackId,
215                    ActivityDisplay activityDisplay, boolean onTop) {
216                super(stackId, activityDisplay, onTop);
217                mService = service;
218            }
219
220            @Override
221            protected void createStack(int stackId, boolean onTop) {
222                // normally stack creation is done here. However we need to do it on demand since
223                // we cannot set {@link mService} by the time the super constructor calling this
224                // method is invoked.
225                mOnTop = onTop;
226                mStackId = stackId;
227            }
228
229            public ActivityStack getStack() {
230                if (mStack == null) {
231                    final RecentTasks recents =
232                            new RecentTasks(mService, mService.mStackSupervisor);
233                    if (mStackId == ActivityManager.StackId.PINNED_STACK_ID) {
234                        mStack = new PinnedActivityStack(this, recents, mOnTop) {
235                            @Override
236                            Rect getPictureInPictureBounds(float aspectRatio,
237                                    boolean useExistingStackBounds) {
238                                return new Rect(50, 50, 100, 100);
239                            }
240                        };
241                    } else {
242                        mStack = new TestActivityStack(this, recents, mOnTop);
243                    }
244                }
245
246                return mStack;
247            }
248        }
249    }
250
251    private static WindowManagerService prepareMockWindowManager() {
252        final WindowManagerService service = mock(WindowManagerService.class);
253
254        doAnswer((InvocationOnMock invocationOnMock) -> {
255            final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
256            if (runnable != null) {
257                runnable.run();
258            }
259            return null;
260        }).when(service).inSurfaceTransaction(any());
261
262        return service;
263    }
264
265    protected interface ActivityStackReporter {
266        int onActivityRemovedFromStackInvocationCount();
267    }
268
269    /**
270     * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a
271     * method is called. Note that its functionality depends on the implementations of the
272     * construction arguments.
273     */
274    protected static class TestActivityStack<T extends StackWindowController>
275            extends ActivityStack<T> implements ActivityStackReporter {
276        private int mOnActivityRemovedFromStackCount = 0;
277        private T mContainerController;
278        TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
279                RecentTasks recentTasks, boolean onTop) {
280            super(activityContainer, recentTasks, onTop);
281        }
282
283        @Override
284        void onActivityRemovedFromStack(ActivityRecord r) {
285            mOnActivityRemovedFromStackCount++;
286            super.onActivityRemovedFromStack(r);
287        }
288
289        // Returns the number of times {@link #onActivityRemovedFromStack} has been called
290        @Override
291        public int onActivityRemovedFromStackInvocationCount() {
292            return mOnActivityRemovedFromStackCount;
293        }
294
295        @Override
296        protected T createStackWindowController(int displayId, boolean onTop,
297                Rect outBounds) {
298            mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
299            return mContainerController;
300        }
301
302        @Override
303        T getWindowContainerController() {
304            return mContainerController;
305        }
306    }
307
308
309    protected static class ActivityStackBuilder {
310        private boolean mOnTop = true;
311        private int mStackId = 0;
312        private int mDisplayId = 1;
313
314        private final ActivityManagerService mService;
315
316        public ActivityStackBuilder(ActivityManagerService ams) {
317            mService = ams;
318        }
319
320        public ActivityStackBuilder setOnTop(boolean onTop) {
321            mOnTop = onTop;
322            return this;
323        }
324
325        public ActivityStackBuilder setStackId(int id) {
326            mStackId = id;
327            return this;
328        }
329
330        public ActivityStackBuilder setDisplayId(int id) {
331            mDisplayId = id;
332            return this;
333        }
334
335        public ActivityStack build() {
336            return createActivityStack(mService, mStackId, mDisplayId, mOnTop);
337        }
338    }
339}
340