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