1 /*
2  * Copyright (C) 2020 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.view.Display.DEFAULT_DISPLAY;
20 import static android.view.Display.STATE_ON;
21 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
22 
23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.junit.Assert.assertNotNull;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.anyInt;
32 import static org.mockito.ArgumentMatchers.eq;
33 import static org.mockito.Mockito.clearInvocations;
34 import static org.mockito.Mockito.reset;
35 import static org.mockito.Mockito.timeout;
36 import static org.mockito.Mockito.verify;
37 
38 import android.app.ActivityThread;
39 import android.content.Context;
40 import android.content.res.Resources;
41 import android.graphics.Rect;
42 import android.hardware.display.DisplayManagerGlobal;
43 import android.os.IBinder;
44 import android.platform.test.annotations.Presubmit;
45 import android.view.Display;
46 import android.view.IWindowManager;
47 import android.view.WindowManager;
48 import android.view.WindowManagerGlobal;
49 import android.window.WindowTokenClient;
50 
51 import com.android.server.inputmethod.InputMethodDialogWindowContext;
52 
53 import org.junit.After;
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.Mockito;
58 
59 // TODO(b/157888351): Move the test to inputmethod package once we find the way to test the
60 //  scenario there.
61 /**
62  * Build/Install/Run:
63  *  atest WmTests:InputMethodDialogWindowContextTest
64  */
65 @Presubmit
66 @RunWith(WindowTestRunner.class)
67 public class InputMethodDialogWindowContextTest extends WindowTestsBase {
68 
69     private InputMethodDialogWindowContext mWindowContext;
70     private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay;
71 
72     private IWindowManager mIWindowManager;
73     private DisplayManagerGlobal mDisplayManagerGlobal;
74 
75     private static final int WAIT_TIMEOUT_MS = 1000;
76 
77     @Before
setUp()78     public void setUp() throws Exception {
79         // Let the Display be created with the DualDisplay policy.
80         final DisplayAreaPolicy.Provider policyProvider =
81                 new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(mWm);
82         Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
83 
84         mWindowContext = new InputMethodDialogWindowContext();
85         mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
86                 .Builder(mAtm, 1000, 1000).build();
87         mSecondaryDisplay.getDisplayInfo().state = STATE_ON;
88 
89         // Mock addWindowTokenWithOptions to create a test window token.
90         mIWindowManager = WindowManagerGlobal.getWindowManagerService();
91         spyOn(mIWindowManager);
92         doAnswer(invocation -> {
93             Object[] args = invocation.getArguments();
94             IBinder clientToken = (IBinder) args[0];
95             int displayId = (int) args[2];
96             DisplayContent dc = mWm.mRoot.getDisplayContent(displayId);
97             mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken,
98                     dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
99                     null /* options */);
100             return dc.getImeContainer().getConfiguration();
101         }).when(mIWindowManager).attachWindowContextToDisplayArea(any(),
102                 eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any());
103         mDisplayManagerGlobal = DisplayManagerGlobal.getInstance();
104         spyOn(mDisplayManagerGlobal);
105         final int displayId = mSecondaryDisplay.getDisplayId();
106         final Display display = mSecondaryDisplay.getDisplay();
107         doReturn(display).when(mDisplayManagerGlobal).getCompatibleDisplay(eq(displayId),
108                 (Resources) any());
109         Context systemUiContext = ActivityThread.currentActivityThread()
110                 .getSystemUiContext(displayId);
111         spyOn(systemUiContext);
112         doReturn(display).when(systemUiContext).getDisplay();
113     }
114 
115     @After
tearDown()116     public void tearDown() {
117         reset(mIWindowManager);
118         reset(mDisplayManagerGlobal);
119     }
120 
121     @Test
testGetSettingsContext()122     public void testGetSettingsContext() {
123         final Context contextOnDefaultDisplay = mWindowContext.get(DEFAULT_DISPLAY);
124 
125         assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay);
126 
127         // Obtain the context again and check if the window metrics match the IME container bounds
128         // of the secondary display.
129         final Context contextOnSecondaryDisplay =
130                 mWindowContext.get(mSecondaryDisplay.getDisplayId());
131 
132         assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay);
133     }
134 
135     @Test
testGetSettingsContextOnDualDisplayContent()136     public void testGetSettingsContextOnDualDisplayContent() {
137         final Context context = mWindowContext.get(mSecondaryDisplay.getDisplayId());
138         final WindowTokenClient tokenClient = (WindowTokenClient) context.getWindowContextToken();
139         assertNotNull(tokenClient);
140         spyOn(tokenClient);
141 
142         final DisplayArea.Tokens imeContainer = mSecondaryDisplay.getImeContainer();
143         spyOn(imeContainer);
144         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay);
145 
146         mSecondaryDisplay.mFirstRoot.placeImeContainer(imeContainer);
147 
148         verify(imeContainer, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
149                 eq(mSecondaryDisplay.mFirstRoot.getConfiguration()));
150         verify(tokenClient, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
151                 eq(mSecondaryDisplay.mFirstRoot.getConfiguration()),
152                 eq(mSecondaryDisplay.mDisplayId));
153         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mFirstRoot);
154         assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
155 
156         // Clear the previous invocation histories in case we may count the previous
157         // onConfigurationChanged invocation into the next verification.
158         clearInvocations(tokenClient, imeContainer);
159         mSecondaryDisplay.mSecondRoot.placeImeContainer(imeContainer);
160 
161         verify(imeContainer, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
162                 eq(mSecondaryDisplay.mSecondRoot.getConfiguration()));
163         verify(tokenClient, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
164                 eq(mSecondaryDisplay.mSecondRoot.getConfiguration()),
165                 eq(mSecondaryDisplay.mDisplayId));
166         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mSecondRoot);
167         assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
168     }
169 
assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc)170     private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {
171         assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId());
172 
173         final Rect contextBounds = context.getSystemService(WindowManager.class)
174                 .getMaximumWindowMetrics().getBounds();
175         final Rect imeContainerBounds = dc.getImeContainer().getBounds();
176         assertThat(contextBounds).isEqualTo(imeContainerBounds);
177     }
178 }
179