Home | History | Annotate | Download | only in wm
      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.wm;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.Context;
     21 import android.content.res.Configuration;
     22 import android.graphics.Rect;
     23 import android.os.Binder;
     24 import android.os.IBinder;
     25 import android.view.IApplicationToken;
     26 import android.view.IWindow;
     27 import android.view.WindowManager;
     28 
     29 import static android.app.AppOpsManager.OP_NONE;
     30 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
     31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     32 
     33 import static com.android.server.wm.WindowContainer.POSITION_TOP;
     34 import static org.mockito.Mockito.any;
     35 import static org.mockito.Mockito.anyBoolean;
     36 import static org.mockito.Mockito.anyFloat;
     37 import static org.mockito.Mockito.anyInt;
     38 import static org.mockito.Mockito.doAnswer;
     39 import static org.mockito.Mockito.mock;
     40 import static org.mockito.Mockito.when;
     41 
     42 import org.mockito.invocation.InvocationOnMock;
     43 
     44 /**
     45  * A collection of static functions that can be referenced by other test packages to provide access
     46  * to WindowManager related test functionality.
     47  */
     48 public class WindowTestUtils {
     49     public static int sNextTaskId = 0;
     50 
     51     /**
     52      * Retrieves an instance of a mock {@link WindowManagerService}.
     53      */
     54     public static WindowManagerService getMockWindowManagerService() {
     55         final WindowManagerService service = mock(WindowManagerService.class);
     56         final WindowHashMap windowMap = new WindowHashMap();
     57         when(service.getWindowManagerLock()).thenReturn(windowMap);
     58         return service;
     59     }
     60 
     61     /**
     62      * Creates a mock instance of {@link StackWindowController}.
     63      */
     64     public static StackWindowController createMockStackWindowContainerController() {
     65         StackWindowController controller = mock(StackWindowController.class);
     66         controller.mContainer = mock(TestTaskStack.class);
     67 
     68         // many components rely on the {@link StackWindowController#adjustConfigurationForBounds}
     69         // to properly set bounds values in the configuration. We must mimick those actions here.
     70         doAnswer((InvocationOnMock invocationOnMock) -> {
     71             final Configuration config = invocationOnMock.<Configuration>getArgument(7);
     72             final Rect bounds = invocationOnMock.<Rect>getArgument(0);
     73             config.windowConfiguration.setBounds(bounds);
     74             return null;
     75         }).when(controller).adjustConfigurationForBounds(any(), any(), any(), any(),
     76                 anyBoolean(), anyBoolean(), anyFloat(), any(), any(), anyInt());
     77 
     78         return controller;
     79     }
     80 
     81     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     82     public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
     83             int userId) {
     84         synchronized (service.mWindowMap) {
     85             final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
     86                     new ActivityManager.TaskDescription(), null);
     87             stack.addTask(newTask, POSITION_TOP);
     88             return newTask;
     89         }
     90     }
     91 
     92     /**
     93      * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not
     94      * normally be mocked out.
     95      */
     96     public static class TestTaskStack extends TaskStack {
     97         TestTaskStack(WindowManagerService service, int stackId) {
     98             super(service, stackId, null);
     99         }
    100 
    101         @Override
    102         void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
    103             // Do nothing.
    104         }
    105     }
    106 
    107     static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
    108         synchronized (dc.mService.mWindowMap) {
    109             return new TestAppWindowToken(dc);
    110         }
    111     }
    112 
    113     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
    114     public static class TestAppWindowToken extends AppWindowToken {
    115         boolean mOnTop = false;
    116 
    117         private TestAppWindowToken(DisplayContent dc) {
    118             super(dc.mService, new IApplicationToken.Stub() {
    119                 public String getName() {return null;}
    120                 }, false, dc, true /* fillsParent */);
    121         }
    122 
    123         TestAppWindowToken(WindowManagerService service, IApplicationToken token,
    124                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
    125                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
    126                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
    127                 boolean alwaysFocusable, AppWindowContainerController controller) {
    128             super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
    129                     showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
    130                     launchTaskBehind, alwaysFocusable, controller);
    131         }
    132 
    133         int getWindowsCount() {
    134             return mChildren.size();
    135         }
    136 
    137         boolean hasWindow(WindowState w) {
    138             return mChildren.contains(w);
    139         }
    140 
    141         WindowState getFirstChild() {
    142             return mChildren.peekFirst();
    143         }
    144 
    145         WindowState getLastChild() {
    146             return mChildren.peekLast();
    147         }
    148 
    149         int positionInParent() {
    150             return getParent().mChildren.indexOf(this);
    151         }
    152 
    153         void setIsOnTop(boolean onTop) {
    154             mOnTop = onTop;
    155         }
    156 
    157         @Override
    158         boolean isOnTop() {
    159             return mOnTop;
    160         }
    161     }
    162 
    163     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
    164         return createTestWindowToken(type, dc, false /* persistOnEmpty */);
    165     }
    166 
    167     static TestWindowToken createTestWindowToken(int type, DisplayContent dc,
    168             boolean persistOnEmpty) {
    169         synchronized (dc.mService.mWindowMap) {
    170             return new TestWindowToken(type, dc, persistOnEmpty);
    171         }
    172     }
    173 
    174     /* Used so we can gain access to some protected members of the {@link WindowToken} class */
    175     public static class TestWindowToken extends WindowToken {
    176 
    177         private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
    178             super(dc.mService, mock(IBinder.class), type, persistOnEmpty, dc,
    179                     false /* ownerCanManageAppTokens */);
    180         }
    181 
    182         int getWindowsCount() {
    183             return mChildren.size();
    184         }
    185 
    186         boolean hasWindow(WindowState w) {
    187             return mChildren.contains(w);
    188         }
    189     }
    190 
    191     /* Used so we can gain access to some protected members of the {@link Task} class */
    192     public static class TestTask extends Task {
    193         boolean mShouldDeferRemoval = false;
    194         boolean mOnDisplayChangedCalled = false;
    195         private boolean mIsAnimating = false;
    196 
    197         TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
    198                 int resizeMode, boolean supportsPictureInPicture,
    199                 TaskWindowContainerController controller) {
    200             super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture,
    201                     new ActivityManager.TaskDescription(), controller);
    202         }
    203 
    204         boolean shouldDeferRemoval() {
    205             return mShouldDeferRemoval;
    206         }
    207 
    208         int positionInParent() {
    209             return getParent().mChildren.indexOf(this);
    210         }
    211 
    212         @Override
    213         void onDisplayChanged(DisplayContent dc) {
    214             super.onDisplayChanged(dc);
    215             mOnDisplayChangedCalled = true;
    216         }
    217 
    218         @Override
    219         boolean isSelfAnimating() {
    220             return mIsAnimating;
    221         }
    222 
    223         void setLocalIsAnimating(boolean isAnimating) {
    224             mIsAnimating = isAnimating;
    225         }
    226     }
    227 
    228     /**
    229      * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
    230      * class.
    231      */
    232     public static class TestTaskWindowContainerController extends TaskWindowContainerController {
    233 
    234         TestTaskWindowContainerController(WindowTestsBase testsBase) {
    235             this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent));
    236         }
    237 
    238         TestTaskWindowContainerController(StackWindowController stackController) {
    239             super(sNextTaskId++, new TaskWindowContainerListener() {
    240                         @Override
    241                         public void registerConfigurationChangeListener(
    242                                 ConfigurationContainerListener listener) {
    243 
    244                         }
    245 
    246                         @Override
    247                         public void unregisterConfigurationChangeListener(
    248                                 ConfigurationContainerListener listener) {
    249 
    250                         }
    251 
    252                         @Override
    253                         public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
    254 
    255                         }
    256 
    257                         @Override
    258                         public void requestResize(Rect bounds, int resizeMode) {
    259 
    260                         }
    261                     }, stackController, 0 /* userId */, null /* bounds */, RESIZE_MODE_UNRESIZEABLE,
    262                     false /* supportsPictureInPicture */, true /* toTop*/,
    263                     true /* showForAllUsers */, new ActivityManager.TaskDescription(),
    264                     stackController.mService);
    265         }
    266 
    267         @Override
    268         TestTask createTask(int taskId, TaskStack stack, int userId, int resizeMode,
    269                 boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription) {
    270             return new TestTask(taskId, stack, userId, mService, resizeMode,
    271                     supportsPictureInPicture, this);
    272         }
    273     }
    274 
    275     public static class TestAppWindowContainerController extends AppWindowContainerController {
    276 
    277         final IApplicationToken mToken;
    278 
    279         TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
    280             this(taskController, new TestIApplicationToken());
    281         }
    282 
    283         TestAppWindowContainerController(TestTaskWindowContainerController taskController,
    284                 IApplicationToken token) {
    285             super(taskController, token, null /* listener */, 0 /* index */,
    286                     SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
    287                     true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
    288                     false /* launchTaskBehind */, false /* alwaysFocusable */,
    289                     0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
    290                     0 /* inputDispatchingTimeoutNanos */, taskController.mService);
    291             mToken = token;
    292         }
    293 
    294         @Override
    295         AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
    296                 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
    297                 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
    298                 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
    299                 boolean alwaysFocusable, AppWindowContainerController controller) {
    300             return new TestAppWindowToken(service, token, voiceInteraction, dc,
    301                     inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
    302                     orientation,
    303                     rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
    304                     controller);
    305         }
    306 
    307         AppWindowToken getAppWindowToken(DisplayContent dc) {
    308             return (AppWindowToken) dc.getWindowToken(mToken.asBinder());
    309         }
    310     }
    311 
    312     public static class TestIApplicationToken implements IApplicationToken {
    313 
    314         private final Binder mBinder = new Binder();
    315         @Override
    316         public IBinder asBinder() {
    317             return mBinder;
    318         }
    319         @Override
    320         public String getName() {
    321             return null;
    322         }
    323     }
    324 
    325     /** Used to track resize reports. */
    326     public static class TestWindowState extends WindowState {
    327         boolean resizeReported;
    328 
    329         TestWindowState(WindowManagerService service, Session session, IWindow window,
    330                 WindowManager.LayoutParams attrs, WindowToken token) {
    331             super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0,
    332                     false /* ownerCanAddInternalSystemWindow */);
    333         }
    334 
    335         @Override
    336         void reportResized() {
    337             super.reportResized();
    338             resizeReported = true;
    339         }
    340 
    341         @Override
    342         public boolean isGoneForLayoutLw() {
    343             return false;
    344         }
    345 
    346         @Override
    347         void updateResizingWindowIfNeeded() {
    348             // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
    349             // the system that it can actually update the window.
    350             boolean hadSurface = mHasSurface;
    351             mHasSurface = true;
    352 
    353             super.updateResizingWindowIfNeeded();
    354 
    355             mHasSurface = hadSurface;
    356         }
    357     }
    358 }
    359