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.autofillservice.cts; 18 19 import static android.autofillservice.cts.Helper.getLoggingLevel; 20 import static android.autofillservice.cts.Helper.hasAutofillFeature; 21 import static android.autofillservice.cts.Helper.runShellCommand; 22 import static android.autofillservice.cts.Helper.setLoggingLevel; 23 import static android.provider.Settings.Secure.AUTOFILL_SERVICE; 24 25 import static com.google.common.truth.Truth.assertWithMessage; 26 27 import android.autofillservice.cts.InstrumentedAutoFillService.Replier; 28 import android.content.Context; 29 import android.content.pm.PackageManager; 30 import android.support.test.InstrumentationRegistry; 31 import android.support.test.runner.AndroidJUnit4; 32 import android.util.Log; 33 import android.widget.RemoteViews; 34 35 import org.junit.After; 36 import org.junit.AfterClass; 37 import org.junit.Before; 38 import org.junit.BeforeClass; 39 import org.junit.Rule; 40 import org.junit.runner.RunWith; 41 42 /** 43 * Base class for all other tests. 44 */ 45 @RunWith(AndroidJUnit4.class) 46 abstract class AutoFillServiceTestCase { 47 private static final String TAG = "AutoFillServiceTestCase"; 48 49 private static final String SERVICE_NAME = 50 InstrumentedAutoFillService.class.getPackage().getName() 51 + "/." + InstrumentedAutoFillService.class.getSimpleName(); 52 53 protected static UiBot sUiBot; 54 55 protected static final Replier sReplier = InstrumentedAutoFillService.getReplier(); 56 57 @Rule 58 public final RetryRule mRetryRule = new RetryRule(2); 59 60 @Rule 61 public final RequiredFeatureRule mRequiredFeatureRule = 62 new RequiredFeatureRule(PackageManager.FEATURE_AUTOFILL); 63 64 /** 65 * Stores the previous logging level so it's restored after the test. 66 */ 67 private String mLoggingLevel; 68 69 @BeforeClass removeLockScreen()70 public static void removeLockScreen() { 71 if (!hasAutofillFeature()) return; 72 73 runShellCommand("input keyevent KEYCODE_WAKEUP"); 74 } 75 76 @BeforeClass setUiBot()77 public static void setUiBot() throws Exception { 78 if (!hasAutofillFeature()) return; 79 80 sUiBot = new UiBot(InstrumentationRegistry.getInstrumentation()); 81 } 82 83 @AfterClass resetSettings()84 public static void resetSettings() { 85 runShellCommand("settings delete secure %s", AUTOFILL_SERVICE); 86 } 87 88 @Before disableService()89 public void disableService() { 90 if (!hasAutofillFeature()) return; 91 92 if (!isServiceEnabled()) return; 93 94 final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(), 95 AUTOFILL_SERVICE); 96 runShellCommand("settings delete secure %s", AUTOFILL_SERVICE); 97 observer.assertCalled(); 98 assertServiceDisabled(); 99 100 InstrumentedAutoFillService.setIgnoreUnexpectedRequests(false); 101 } 102 103 @Before reset()104 public void reset() { 105 destroyAllSessions(); 106 sReplier.reset(); 107 InstrumentedAutoFillService.resetStaticState(); 108 AuthenticationActivity.resetStaticState(); 109 } 110 111 @Before setVerboseLogging()112 public void setVerboseLogging() { 113 try { 114 mLoggingLevel = getLoggingLevel(); 115 } catch (Exception e) { 116 Log.w(TAG, "Could not get previous logging level: " + e); 117 mLoggingLevel = "debug"; 118 } 119 try { 120 setLoggingLevel("verbose"); 121 } catch (Exception e) { 122 Log.w(TAG, "Could not change logging level to verbose: " + e); 123 } 124 } 125 126 @After resetVerboseLogging()127 public void resetVerboseLogging() { 128 try { 129 setLoggingLevel(mLoggingLevel); 130 } catch (Exception e) { 131 Log.w(TAG, "Could not restore logging level to " + mLoggingLevel + ": " + e); 132 } 133 } 134 135 // TODO: we shouldn't throw exceptions on @After / @AfterClass because if the test failed, these 136 // exceptions would mask the real cause. A better approach might be using a @Rule or some other 137 // visitor pattern. 138 @After assertNoPendingRequests()139 public void assertNoPendingRequests() { 140 sReplier.assertNumberUnhandledFillRequests(0); 141 sReplier.assertNumberUnhandledSaveRequests(0); 142 } 143 144 @After ignoreFurtherRequests()145 public void ignoreFurtherRequests() { 146 InstrumentedAutoFillService.setIgnoreUnexpectedRequests(true); 147 } 148 149 /** 150 * Enables the {@link InstrumentedAutoFillService} for autofill for the current user. 151 */ enableService()152 protected void enableService() { 153 if (isServiceEnabled()) return; 154 155 final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(), 156 AUTOFILL_SERVICE); 157 runShellCommand("settings put secure %s %s default", AUTOFILL_SERVICE, SERVICE_NAME); 158 observer.assertCalled(); 159 assertServiceEnabled(); 160 } 161 162 /** 163 * Asserts that the {@link InstrumentedAutoFillService} is enabled for the default user. 164 */ assertServiceEnabled()165 protected static void assertServiceEnabled() { 166 assertServiceStatus(true); 167 } 168 169 /** 170 * Asserts that the {@link InstrumentedAutoFillService} is disabled for the default user. 171 */ assertServiceDisabled()172 protected static void assertServiceDisabled() { 173 assertServiceStatus(false); 174 } 175 176 /** 177 * Asserts that there is no session left in the service. 178 */ assertNoDanglingSessions()179 protected void assertNoDanglingSessions() { 180 final String command = "cmd autofill list sessions"; 181 final String result = runShellCommand(command); 182 assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty(); 183 } 184 185 /** 186 * Destroys all sessions. 187 */ destroyAllSessions()188 protected void destroyAllSessions() { 189 runShellCommand("cmd autofill destroy sessions"); 190 assertNoDanglingSessions(); 191 } 192 getContext()193 protected static Context getContext() { 194 return InstrumentationRegistry.getInstrumentation().getContext(); 195 } 196 createPresentation(String message)197 protected static RemoteViews createPresentation(String message) { 198 final RemoteViews presentation = new RemoteViews(getContext() 199 .getPackageName(), R.layout.list_item); 200 presentation.setTextViewText(R.id.text1, message); 201 return presentation; 202 } 203 isServiceEnabled()204 private static boolean isServiceEnabled() { 205 final String service = runShellCommand("settings get secure %s", AUTOFILL_SERVICE); 206 return SERVICE_NAME.equals(service); 207 } 208 assertServiceStatus(boolean enabled)209 private static void assertServiceStatus(boolean enabled) { 210 final String actual = runShellCommand("settings get secure %s", AUTOFILL_SERVICE); 211 final String expected = enabled ? SERVICE_NAME : "null"; 212 assertWithMessage("Invalid value for secure setting %s", AUTOFILL_SERVICE) 213 .that(actual).isEqualTo(expected); 214 } 215 } 216