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.view.inputmethod.cts.util; 18 19 import static org.junit.Assert.fail; 20 import static org.junit.Assume.assumeFalse; 21 import static org.junit.Assume.assumeTrue; 22 23 import android.Manifest; 24 import android.app.ActivityTaskManager; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.content.res.Resources; 29 import android.platform.test.annotations.AppModeFull; 30 import android.platform.test.annotations.AppModeInstant; 31 32 import androidx.test.platform.app.InstrumentationRegistry; 33 34 import com.android.compatibility.common.util.SystemUtil; 35 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Rule; 39 import org.junit.rules.TestName; 40 41 import java.lang.reflect.Method; 42 import java.util.List; 43 44 public class EndToEndImeTestBase { 45 @Rule 46 public TestName mTestName = new TestName(); 47 48 /** 49 * Enters touch mode when instrumenting. 50 * 51 * Making the view focus state in instrumentation process more reliable in case when 52 * {@link android.view.View#clearFocus()} invoked but system may reFocus again when the view 53 * was not in touch mode. (i.e {@link android.view.View#isInTouchMode()} is {@code false}). 54 */ 55 @Before enterTouchMode()56 public final void enterTouchMode() { 57 InstrumentationRegistry.getInstrumentation().setInTouchMode(true); 58 } 59 60 /** 61 * Restore to the default touch mode state after the test. 62 */ 63 @After restoreTouchMode()64 public final void restoreTouchMode() { 65 InstrumentationRegistry.getInstrumentation().resetInTouchMode(); 66 } 67 68 /** 69 * Our own safeguard in case "atest" command is regressed and start running tests with 70 * {@link AppModeInstant} even when {@code --instant} option is not specified. 71 * 72 * <p>Unfortunately this scenario had regressed at least 3 times. That's why we also check 73 * this in our side. See Bug 158617529, Bug 187211725 and Bug 187222205 for examples.</p> 74 */ 75 @Before verifyAppModeConsistency()76 public void verifyAppModeConsistency() { 77 final Class<?> thisClass = this.getClass(); 78 final String testMethodName = mTestName.getMethodName(); 79 final String fullTestMethodName = thisClass.getSimpleName() + "#" + testMethodName; 80 81 final Method testMethod; 82 try { 83 testMethod = thisClass.getMethod(testMethodName); 84 } catch (NoSuchMethodException e) { 85 throw new IllegalStateException("Failed to find " + fullTestMethodName, e); 86 } 87 88 final boolean hasAppModeFull = testMethod.getAnnotation(AppModeFull.class) != null; 89 final boolean hasAppModeInstant = testMethod.getAnnotation(AppModeInstant.class) != null; 90 91 if (hasAppModeFull && hasAppModeInstant) { 92 fail("Both @AppModeFull and @AppModeInstant are found in " + fullTestMethodName 93 + ", which does not make sense. " 94 + "Remove both to make it clear that this test is app-mode agnostic, " 95 + "or specify one of them otherwise."); 96 } 97 98 // We want to explicitly check this condition in case tests are executed with atest 99 // command. See Bug 158617529 for details. 100 if (hasAppModeFull) { 101 assumeFalse("This test should run under and only under the full app mode.", 102 InstrumentationRegistry.getInstrumentation().getTargetContext() 103 .getPackageManager().isInstantApp()); 104 } 105 if (hasAppModeInstant) { 106 assumeTrue("This test should run under and only under the instant app mode.", 107 InstrumentationRegistry.getInstrumentation().getTargetContext() 108 .getPackageManager().isInstantApp()); 109 } 110 } 111 112 @Before showStateInitializeActivity()113 public void showStateInitializeActivity() { 114 // TODO(b/37502066): Move this back to @BeforeClass once b/37502066 is fixed. 115 assumeTrue("MockIme cannot be used for devices that do not support installable IMEs", 116 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager() 117 .hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)); 118 119 final Intent intent = new Intent() 120 .setAction(Intent.ACTION_MAIN) 121 .setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(), 122 StateInitializeActivity.class) 123 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 124 .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) 125 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 126 InstrumentationRegistry.getInstrumentation().startActivitySync(intent); 127 } 128 129 @Before clearLaunchParams()130 public void clearLaunchParams() { 131 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 132 final ActivityTaskManager atm = context.getSystemService(ActivityTaskManager.class); 133 SystemUtil.runWithShellPermissionIdentity(() -> { 134 // Clear launch params for all test packages to make sure each test is run in a clean 135 // state. 136 atm.clearLaunchParamsForPackages(List.of(context.getPackageName())); 137 }, Manifest.permission.MANAGE_ACTIVITY_TASKS); 138 } 139 isPreventImeStartup()140 protected static boolean isPreventImeStartup() { 141 final Context context = InstrumentationRegistry.getInstrumentation().getContext(); 142 try { 143 return context.getResources().getBoolean( 144 android.R.bool.config_preventImeStartupUnlessTextEditor); 145 } catch (Resources.NotFoundException e) { 146 // Assume this is not enabled. 147 return false; 148 } 149 } 150 } 151