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