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