Home | History | Annotate | Download | only in am
      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
     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
    100     public void tearDown() {
    101         mHandlerThread.quitSafely();
    102     }
    103 
    104     protected ActivityManagerService createActivityManagerService() {
    105         final ActivityManagerService service =
    106                 setupActivityManagerService(new TestActivityManagerService(mContext));
    107         AttributeCache.init(mContext);
    108         return service;
    109     }
    110 
    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 
    137         ActivityBuilder(ActivityManagerService service) {
    138             mService = service;
    139         }
    140 
    141         ActivityBuilder setComponent(ComponentName component) {
    142             mComponent = component;
    143             return this;
    144         }
    145 
    146         static ComponentName getDefaultComponent() {
    147             return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
    148                     DEFAULT_COMPONENT_PACKAGE_NAME);
    149         }
    150 
    151         ActivityBuilder setTask(TaskRecord task) {
    152             mTaskRecord = task;
    153             return this;
    154         }
    155 
    156         ActivityBuilder setActivityFlags(int flags) {
    157             mActivityFlags = flags;
    158             return this;
    159         }
    160 
    161         ActivityBuilder setStack(ActivityStack stack) {
    162             mStack = stack;
    163             return this;
    164         }
    165 
    166         ActivityBuilder setCreateTask(boolean createTask) {
    167             mCreateTask = createTask;
    168             return this;
    169         }
    170 
    171         ActivityBuilder setUid(int uid) {
    172             mUid = uid;
    173             return this;
    174         }
    175 
    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 
    235         TaskBuilder(ActivityStackSupervisor supervisor) {
    236             mSupervisor = supervisor;
    237         }
    238 
    239         TaskBuilder setComponent(ComponentName component) {
    240             mComponent = component;
    241             return this;
    242         }
    243 
    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          */
    253         TaskBuilder setCreateStack(boolean createStack) {
    254             mCreateStack = createStack;
    255             return this;
    256         }
    257 
    258         TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
    259             mVoiceSession = session;
    260             return this;
    261         }
    262 
    263         TaskBuilder setFlags(int flags) {
    264             mFlags = flags;
    265             return this;
    266         }
    267 
    268         TaskBuilder setTaskId(int taskId) {
    269             mTaskId = taskId;
    270             return this;
    271         }
    272 
    273         TaskBuilder setUserId(int userId) {
    274             mUserId = userId;
    275             return this;
    276         }
    277 
    278         TaskBuilder setStack(ActivityStack stack) {
    279             mStack = stack;
    280             return this;
    281         }
    282 
    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 {
    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
    326             void createWindowContainer(boolean onTop, boolean showForAllUsers) {
    327                 setWindowContainerController();
    328             }
    329 
    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 
    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
    355         public ClientLifecycleManager getLifecycleManager() {
    356             if (mLifecycleManager == null) {
    357                 return super.getLifecycleManager();
    358             }
    359             return mLifecycleManager;
    360         }
    361 
    362         public LockTaskController getLockTaskController() {
    363             if (mLockTaskController == null) {
    364                 mLockTaskController = spy(super.getLockTaskController());
    365             }
    366 
    367             return mLockTaskController;
    368         }
    369 
    370         void setLifecycleManager(ClientLifecycleManager manager) {
    371             mLifecycleManager = manager;
    372         }
    373 
    374         @Override
    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 
    399         protected ActivityStackSupervisor createTestSupervisor() {
    400             return new TestActivityStackSupervisor(this, mHandlerThread.getLooper());
    401         }
    402 
    403         @Override
    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 
    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
    425         public void initialize() {
    426             super.initialize();
    427             mDisplay = spy(new TestActivityDisplay(this, DEFAULT_DISPLAY));
    428             attachDisplay(mDisplay);
    429         }
    430 
    431         @Override
    432         public KeyguardController getKeyguardController() {
    433             return mKeyguardController;
    434         }
    435 
    436         @Override
    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
    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;
    452         TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
    453             super(supervisor, displayId);
    454             mSupervisor = supervisor;
    455         }
    456 
    457         @Override
    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
    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