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.wm.shell.common; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 import static android.view.InsetsSource.ID_IME; 21 import static android.view.Surface.ROTATION_0; 22 import static android.view.WindowInsets.Type.ime; 23 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertNotNull; 26 import static org.junit.Assert.assertNull; 27 import static org.junit.Assert.assertTrue; 28 import static org.mockito.ArgumentMatchers.any; 29 import static org.mockito.ArgumentMatchers.anyInt; 30 import static org.mockito.ArgumentMatchers.eq; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.spy; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.verifyZeroInteractions; 36 37 import android.graphics.Insets; 38 import android.graphics.Point; 39 import android.os.Looper; 40 import android.platform.test.annotations.RequiresFlagsDisabled; 41 import android.platform.test.annotations.RequiresFlagsEnabled; 42 import android.platform.test.flag.junit.CheckFlagsRule; 43 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 44 import android.view.IWindowManager; 45 import android.view.InsetsSource; 46 import android.view.InsetsSourceControl; 47 import android.view.InsetsState; 48 import android.view.SurfaceControl; 49 import android.view.inputmethod.ImeTracker; 50 51 import androidx.test.filters.SmallTest; 52 53 import com.android.wm.shell.ShellTestCase; 54 import com.android.wm.shell.shared.TransactionPool; 55 import com.android.wm.shell.sysui.ShellInit; 56 57 import org.junit.Before; 58 import org.junit.Rule; 59 import org.junit.Test; 60 import org.mockito.Mock; 61 import org.mockito.MockitoAnnotations; 62 63 import java.util.concurrent.Executor; 64 65 /** 66 * Tests for the display IME controller. 67 * 68 * <p> Build/Install/Run: 69 * atest WMShellUnitTests:DisplayImeControllerTest 70 */ 71 @SmallTest 72 public class DisplayImeControllerTest extends ShellTestCase { 73 @Rule 74 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 75 76 @Mock 77 private SurfaceControl.Transaction mT; 78 @Mock 79 private ShellInit mShellInit; 80 @Mock 81 private IWindowManager mWm; 82 private DisplayImeController mDisplayImeController; 83 private DisplayImeController.PerDisplay mPerDisplay; 84 private Executor mExecutor; 85 86 @Before setUp()87 public void setUp() throws Exception { 88 MockitoAnnotations.initMocks(this); 89 mExecutor = spy(Runnable::run); 90 mDisplayImeController = new DisplayImeController(mWm, mShellInit, null, null, 91 new TransactionPool() { 92 @Override 93 public SurfaceControl.Transaction acquire() { 94 return mT; 95 } 96 97 @Override 98 public void release(SurfaceControl.Transaction t) { 99 } 100 }, mExecutor) { 101 @Override 102 void removeImeSurface(int displayId) { 103 } 104 }; 105 mPerDisplay = mDisplayImeController.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0); 106 } 107 108 @Test instantiateController_addInitCallback()109 public void instantiateController_addInitCallback() { 110 verify(mShellInit, times(1)).addInitCallback(any(), any()); 111 } 112 113 @Test insetsControlChanged_schedulesNoWorkOnExecutor()114 public void insetsControlChanged_schedulesNoWorkOnExecutor() { 115 Looper.prepare(); 116 mPerDisplay.insetsControlChanged(insetsStateWithIme(false), insetsSourceControl()); 117 verifyZeroInteractions(mExecutor); 118 } 119 120 @Test insetsChanged_schedulesNoWorkOnExecutor()121 public void insetsChanged_schedulesNoWorkOnExecutor() { 122 Looper.prepare(); 123 mPerDisplay.insetsChanged(insetsStateWithIme(false)); 124 verifyZeroInteractions(mExecutor); 125 } 126 127 @Test showInsets_schedulesNoWorkOnExecutor()128 public void showInsets_schedulesNoWorkOnExecutor() { 129 mPerDisplay.showInsets(ime(), true /* fromIme */, ImeTracker.Token.empty()); 130 verifyZeroInteractions(mExecutor); 131 } 132 133 @Test hideInsets_schedulesNoWorkOnExecutor()134 public void hideInsets_schedulesNoWorkOnExecutor() { 135 mPerDisplay.hideInsets(ime(), true /* fromIme */, ImeTracker.Token.empty()); 136 verifyZeroInteractions(mExecutor); 137 } 138 139 // With the refactor, the control's isInitiallyVisible is used to apply to the IME, therefore 140 // this test is obsolete 141 @Test 142 @RequiresFlagsDisabled(android.view.inputmethod.Flags.FLAG_REFACTOR_INSETS_CONTROLLER) reappliesVisibilityToChangedLeash()143 public void reappliesVisibilityToChangedLeash() { 144 verifyZeroInteractions(mT); 145 mPerDisplay.mImeShowing = false; 146 147 mPerDisplay.insetsControlChanged(insetsStateWithIme(false), insetsSourceControl()); 148 149 assertFalse(mPerDisplay.mImeShowing); 150 verify(mT).hide(any()); 151 152 mPerDisplay.mImeShowing = true; 153 mPerDisplay.insetsControlChanged(insetsStateWithIme(true), insetsSourceControl()); 154 155 assertTrue(mPerDisplay.mImeShowing); 156 verify(mT).show(any()); 157 } 158 159 @Test insetsControlChanged_updateImeSourceControl()160 public void insetsControlChanged_updateImeSourceControl() { 161 Looper.prepare(); 162 mPerDisplay.insetsControlChanged(insetsStateWithIme(false), insetsSourceControl()); 163 assertNotNull(mPerDisplay.mImeSourceControl); 164 165 mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[]{}); 166 assertNull(mPerDisplay.mImeSourceControl); 167 } 168 169 @Test 170 @RequiresFlagsEnabled(android.view.inputmethod.Flags.FLAG_REFACTOR_INSETS_CONTROLLER) setImeInputTargetRequestedVisibility_invokeOnImeRequested()171 public void setImeInputTargetRequestedVisibility_invokeOnImeRequested() { 172 var mockPp = mock(DisplayImeController.ImePositionProcessor.class); 173 mDisplayImeController.addPositionProcessor(mockPp); 174 175 mPerDisplay.setImeInputTargetRequestedVisibility(true, null /* statsToken */); 176 verify(mockPp).onImeRequested(anyInt(), eq(true)); 177 178 mPerDisplay.setImeInputTargetRequestedVisibility(false, null /* statsToken */); 179 verify(mockPp).onImeRequested(anyInt(), eq(false)); 180 } 181 insetsSourceControl()182 private InsetsSourceControl[] insetsSourceControl() { 183 return new InsetsSourceControl[]{ 184 new InsetsSourceControl( 185 ID_IME, ime(), mock(SurfaceControl.class), false, new Point(0, 0), 186 Insets.NONE) 187 }; 188 } 189 insetsStateWithIme(boolean visible)190 private InsetsState insetsStateWithIme(boolean visible) { 191 InsetsState state = new InsetsState(); 192 state.addSource(new InsetsSource(ID_IME, ime())); 193 state.setSourceVisible(ID_IME, visible); 194 return state; 195 } 196 197 } 198