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 android.inputmethodservice.cts.hostside; 18 19 import static android.inputmethodservice.cts.common.DeviceEventConstants.ACTION_DEVICE_EVENT; 20 import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.TEST_START; 21 import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_SENDER; 22 import static android.inputmethodservice.cts.common.DeviceEventConstants.EXTRA_EVENT_TYPE; 23 import static android.inputmethodservice.cts.common.DeviceEventConstants.RECEIVER_COMPONENT; 24 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assume.assumeTrue; 27 28 import android.inputmethodservice.cts.common.EditTextAppConstants; 29 import android.inputmethodservice.cts.common.EventProviderConstants.EventTableConstants; 30 import android.inputmethodservice.cts.common.Ime1Constants; 31 import android.inputmethodservice.cts.common.Ime2Constants; 32 import android.inputmethodservice.cts.common.test.DeviceTestConstants; 33 import android.inputmethodservice.cts.common.test.ShellCommandUtils; 34 import android.inputmethodservice.cts.common.test.TestInfo; 35 import android.platform.test.annotations.AppModeFull; 36 import android.platform.test.annotations.AppModeInstant; 37 38 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 39 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 import java.util.concurrent.TimeUnit; 47 import java.util.concurrent.TimeoutException; 48 49 @RunWith(DeviceJUnit4ClassRunner.class) 50 public class InputMethodServiceLifecycleTest extends BaseHostJUnit4Test { 51 52 private static final long TIMEOUT = TimeUnit.MICROSECONDS.toMillis(20000); 53 private static final long POLLING_INTERVAL = TimeUnit.MICROSECONDS.toMillis(200); 54 55 @Before 56 public void setUp() throws Exception { 57 // Skip whole tests when DUT has no android.software.input_methods feature. 58 assumeTrue(hasDeviceFeature(ShellCommandUtils.FEATURE_INPUT_METHODS)); 59 cleanUpTestImes(); 60 shell(ShellCommandUtils.deleteContent(EventTableConstants.CONTENT_URI)); 61 } 62 63 @After 64 public void tearDown() throws Exception { 65 shell(ShellCommandUtils.resetImes()); 66 } 67 68 private void installPossibleInstantPackage(String apkFileName, boolean instant) 69 throws Exception { 70 if (instant) { 71 installPackage(apkFileName, "-r", "--instant"); 72 } else { 73 installPackage(apkFileName, "-r"); 74 } 75 } 76 77 private void testSwitchIme(boolean instant) throws Exception { 78 final TestInfo testSwitchIme1ToIme2 = new TestInfo(DeviceTestConstants.PACKAGE, 79 DeviceTestConstants.TEST_CLASS, DeviceTestConstants.TEST_SWITCH_IME1_TO_IME2); 80 sendTestStartEvent(testSwitchIme1ToIme2); 81 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 82 installPackage(Ime1Constants.APK, "-r"); 83 installPackage(Ime2Constants.APK, "-r"); 84 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 85 shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID)); 86 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 87 88 assertTrue(runDeviceTestMethod(testSwitchIme1ToIme2)); 89 } 90 91 @AppModeFull 92 @Test 93 public void testSwitchImeull() throws Exception { 94 testSwitchIme(false); 95 } 96 97 @AppModeInstant 98 @Test 99 public void testSwitchImeInstant() throws Exception { 100 testSwitchIme(true); 101 } 102 103 private void testUninstallCurrentIme(boolean instant) throws Exception { 104 final TestInfo testCreateIme1 = new TestInfo(DeviceTestConstants.PACKAGE, 105 DeviceTestConstants.TEST_CLASS, DeviceTestConstants.TEST_CREATE_IME1); 106 sendTestStartEvent(testCreateIme1); 107 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 108 installPackage(Ime1Constants.APK, "-r"); 109 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 110 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 111 assertTrue(runDeviceTestMethod(testCreateIme1)); 112 113 uninstallPackageIfExists(Ime1Constants.PACKAGE); 114 assertImeNotSelectedInSecureSettings(Ime1Constants.IME_ID, TIMEOUT); 115 } 116 117 @AppModeFull 118 @Test 119 public void testUninstallCurrentImeFull() throws Exception { 120 testUninstallCurrentIme(false); 121 } 122 123 @AppModeInstant 124 @Test 125 public void testUninstallCurrentImeInstant() throws Exception { 126 testUninstallCurrentIme(true); 127 } 128 129 private void testDisableCurrentIme(boolean instant) throws Exception { 130 final TestInfo testCreateIme1 = new TestInfo(DeviceTestConstants.PACKAGE, 131 DeviceTestConstants.TEST_CLASS, DeviceTestConstants.TEST_CREATE_IME1); 132 sendTestStartEvent(testCreateIme1); 133 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 134 installPackage(Ime1Constants.APK, "-r"); 135 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 136 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 137 assertTrue(runDeviceTestMethod(testCreateIme1)); 138 139 shell(ShellCommandUtils.disableIme(Ime1Constants.IME_ID)); 140 assertImeNotSelectedInSecureSettings(Ime1Constants.IME_ID, TIMEOUT); 141 } 142 143 @AppModeFull 144 @Test 145 public void testDisableCurrentImeFull() throws Exception { 146 testDisableCurrentIme(false); 147 } 148 149 @AppModeInstant 150 @Test 151 public void testDisableCurrentImeInstant() throws Exception { 152 testDisableCurrentIme(true); 153 } 154 155 private void testSwitchInputMethod(boolean instant) throws Exception { 156 final TestInfo testSetInputMethod = new TestInfo( 157 DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS, 158 DeviceTestConstants.TEST_SWITCH_INPUTMETHOD); 159 sendTestStartEvent(testSetInputMethod); 160 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 161 installPackage(Ime1Constants.APK, "-r"); 162 installPackage(Ime2Constants.APK, "-r"); 163 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 164 shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID)); 165 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 166 167 assertTrue(runDeviceTestMethod(testSetInputMethod)); 168 } 169 170 @AppModeFull 171 @Test 172 public void testSwitchInputMethodFull() throws Exception { 173 testSwitchInputMethod(false); 174 } 175 176 @AppModeInstant 177 @Test 178 public void testSwitchInputMethodInstant() throws Exception { 179 testSwitchInputMethod(true); 180 } 181 182 private void testSwitchToNextInput(boolean instant) throws Exception { 183 final TestInfo testSwitchInputs = new TestInfo( 184 DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS, 185 DeviceTestConstants.TEST_SWITCH_NEXT_INPUT); 186 sendTestStartEvent(testSwitchInputs); 187 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 188 installPackage(Ime1Constants.APK, "-r"); 189 installPackage(Ime2Constants.APK, "-r"); 190 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 191 // Make sure that there is at least one more IME that specifies 192 // supportsSwitchingToNextInputMethod="true" 193 shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID)); 194 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 195 196 assertTrue(runDeviceTestMethod(testSwitchInputs)); 197 } 198 199 @AppModeFull 200 @Test 201 public void testSwitchToNextInputFull() throws Exception { 202 testSwitchToNextInput(false); 203 } 204 205 @AppModeInstant 206 @Test 207 public void testSwitchToNextInputInstant() throws Exception { 208 testSwitchToNextInput(true); 209 } 210 211 private void testSwitchToPreviousInput(boolean instant) throws Exception { 212 final TestInfo testSwitchInputs = new TestInfo( 213 DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS, 214 DeviceTestConstants.TEST_SWITCH_PREVIOUS_INPUT); 215 sendTestStartEvent(testSwitchInputs); 216 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 217 installPackage(Ime1Constants.APK, "-r"); 218 installPackage(Ime2Constants.APK, "-r"); 219 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 220 shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID)); 221 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 222 223 assertTrue(runDeviceTestMethod(testSwitchInputs)); 224 } 225 226 @AppModeFull 227 @Test 228 public void testSwitchToPreviousInputFull() throws Exception { 229 testSwitchToPreviousInput(false); 230 } 231 232 @AppModeInstant 233 @Test 234 public void testSwitchToPreviousInputInstant() throws Exception { 235 testSwitchToPreviousInput(true); 236 } 237 238 private void testInputUnbindsOnImeStopped(boolean instant) throws Exception { 239 final TestInfo testUnbind = new TestInfo( 240 DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS, 241 DeviceTestConstants.TEST_INPUT_UNBINDS_ON_IME_STOPPED); 242 sendTestStartEvent(testUnbind); 243 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 244 installPackage(Ime1Constants.APK, "-r"); 245 installPackage(Ime2Constants.APK, "-r"); 246 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 247 shell(ShellCommandUtils.enableIme(Ime2Constants.IME_ID)); 248 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 249 250 assertTrue(runDeviceTestMethod(testUnbind)); 251 } 252 253 @AppModeFull 254 @Test 255 public void testInputUnbindsOnImeStoppedFull() throws Exception { 256 testInputUnbindsOnImeStopped(false); 257 } 258 259 @AppModeInstant 260 @Test 261 public void testInputUnbindsOnImeStoppedInstant() throws Exception { 262 testInputUnbindsOnImeStopped(true); 263 } 264 265 private void testInputUnbindsOnAppStop(boolean instant) throws Exception { 266 final TestInfo testUnbind = new TestInfo( 267 DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_CLASS, 268 DeviceTestConstants.TEST_INPUT_UNBINDS_ON_APP_STOPPED); 269 sendTestStartEvent(testUnbind); 270 installPossibleInstantPackage(EditTextAppConstants.APK, instant); 271 installPackage(Ime1Constants.APK, "-r"); 272 shell(ShellCommandUtils.enableIme(Ime1Constants.IME_ID)); 273 shell(ShellCommandUtils.setCurrentIme(Ime1Constants.IME_ID)); 274 275 assertTrue(runDeviceTestMethod(testUnbind)); 276 } 277 278 @AppModeFull 279 @Test 280 public void testInputUnbindsOnAppStopFull() throws Exception { 281 testInputUnbindsOnAppStop(false); 282 } 283 284 @AppModeInstant 285 @Test 286 public void testInputUnbindsOnAppStopInstant() throws Exception { 287 testInputUnbindsOnAppStop(true); 288 } 289 290 private void sendTestStartEvent(final TestInfo deviceTest) throws Exception { 291 final String sender = deviceTest.getTestName(); 292 // {@link EventType#EXTRA_EVENT_TIME} will be recorded at device side. 293 shell(ShellCommandUtils.broadcastIntent( 294 ACTION_DEVICE_EVENT, RECEIVER_COMPONENT, 295 "--es", EXTRA_EVENT_SENDER, sender, 296 "--es", EXTRA_EVENT_TYPE, TEST_START.name())); 297 } 298 299 private boolean runDeviceTestMethod(final TestInfo deviceTest) throws Exception { 300 return runDeviceTests(deviceTest.testPackage, deviceTest.testClass, deviceTest.testMethod); 301 } 302 303 private String shell(final String command) throws Exception { 304 return getDevice().executeShellCommand(command).trim(); 305 } 306 307 private void cleanUpTestImes() throws Exception { 308 uninstallPackageIfExists(Ime1Constants.PACKAGE); 309 uninstallPackageIfExists(Ime2Constants.PACKAGE); 310 } 311 312 private void uninstallPackageIfExists(final String packageName) throws Exception { 313 if (isPackageInstalled(getDevice(), packageName)) { 314 uninstallPackage(getDevice(), packageName); 315 } 316 } 317 318 /** 319 * Makes sure that the given IME is not in the stored in the secure settings as the current IME. 320 * 321 * @param imeId IME ID to be monitored 322 * @param timeout timeout in millisecond 323 */ 324 private void assertImeNotSelectedInSecureSettings(String imeId, long timeout) throws Exception { 325 while (true) { 326 if (timeout < 0) { 327 throw new TimeoutException(imeId + " is still the current IME even after " 328 + timeout + " msec."); 329 } 330 if (!imeId.equals(shell(ShellCommandUtils.getCurrentIme()))) { 331 break; 332 } 333 Thread.sleep(POLLING_INTERVAL); 334 timeout -= POLLING_INTERVAL; 335 } 336 } 337 } 338