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 package android.autofillservice.cts;
17 
18 import static android.autofillservice.cts.Timeouts.FILL_TIMEOUT;
19 
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.content.Context;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 import android.view.autofill.AutofillManager;
26 import android.webkit.JavascriptInterface;
27 import android.webkit.WebView;
28 
29 import com.android.compatibility.common.util.RetryableException;
30 
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 
34 /**
35  * Custom {@link WebView} used to assert contents were autofilled.
36  */
37 public class MyWebView extends WebView {
38 
39     private static final String TAG = "MyWebView";
40 
41     private FillExpectation mExpectation;
42 
MyWebView(Context context)43     public MyWebView(Context context) {
44         super(context);
45         setJsHandler();
46         Log.d(TAG, "isAutofillEnabled() on constructor? " + isAutofillEnabled());
47     }
48 
MyWebView(Context context, AttributeSet attrs)49     public MyWebView(Context context, AttributeSet attrs) {
50         super(context, attrs);
51         setJsHandler();
52         Log.d(TAG, "isAutofillEnabled() on constructor? " + isAutofillEnabled());
53     }
54 
expectAutofill(String username, String password)55     public void expectAutofill(String username, String password) {
56         mExpectation = new FillExpectation(username, password);
57     }
58 
assertAutofilled()59     public void assertAutofilled() throws Exception {
60         assertWithMessage("expectAutofill() not called").that(mExpectation).isNotNull();
61         mExpectation.assertUsernameCalled();
62         mExpectation.assertPasswordCalled();
63     }
64 
setJsHandler()65     private void setJsHandler() {
66         getSettings().setJavaScriptEnabled(true);
67         addJavascriptInterface(new JavascriptHandler(), "JsHandler");
68     }
69 
isAutofillEnabled()70     boolean isAutofillEnabled() {
71         return getContext().getSystemService(AutofillManager.class).isEnabled();
72     }
73 
74     private class FillExpectation {
75         private final CountDownLatch mUsernameLatch = new CountDownLatch(1);
76         private final CountDownLatch mPasswordLatch = new CountDownLatch(1);
77         private final String mExpectedUsername;
78         private final String mExpectedPassword;
79         private String mActualUsername;
80         private String mActualPassword;
81 
FillExpectation(String username, String password)82         FillExpectation(String username, String password) {
83             this.mExpectedUsername = username;
84             this.mExpectedPassword = password;
85         }
86 
setUsername(String username)87         void setUsername(String username) {
88             mActualUsername = username;
89             mUsernameLatch.countDown();
90         }
91 
setPassword(String password)92         void setPassword(String password) {
93             mActualPassword = password;
94             mPasswordLatch.countDown();
95         }
96 
assertUsernameCalled()97         void assertUsernameCalled() throws Exception {
98             assertCalled(mUsernameLatch, "username");
99             assertWithMessage("Wrong value for username").that(mExpectation.mActualUsername)
100                 .isEqualTo(mExpectation.mExpectedUsername);
101         }
102 
assertPasswordCalled()103         void assertPasswordCalled() throws Exception {
104             assertCalled(mPasswordLatch, "password");
105             assertWithMessage("Wrong value for password").that(mExpectation.mActualPassword)
106                     .isEqualTo(mExpectation.mExpectedPassword);
107         }
108 
assertCalled(CountDownLatch latch, String field)109         private void assertCalled(CountDownLatch latch, String field) throws Exception {
110             if (!latch.await(FILL_TIMEOUT.ms(), TimeUnit.MILLISECONDS)) {
111                 throw new RetryableException(FILL_TIMEOUT, "%s not called", field);
112             }
113         }
114     }
115 
116     private class JavascriptHandler {
117 
118         @JavascriptInterface
onUsernameChanged(String username)119         public void onUsernameChanged(String username) {
120             Log.d(TAG, "onUsernameChanged():" + username);
121             if (mExpectation != null) {
122                 mExpectation.setUsername(username);
123             }
124         }
125 
126         @JavascriptInterface
onPasswordChanged(String password)127         public void onPasswordChanged(String password) {
128             Log.d(TAG, "onPasswordChanged():" + password);
129             if (mExpectation != null) {
130                 mExpectation.setPassword(password);
131             }
132         }
133     }
134 }
135