Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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.webkit.cts;
     18 
     19 import android.graphics.Bitmap;
     20 import android.os.Message;
     21 import android.os.SystemClock;
     22 import android.test.ActivityInstrumentationTestCase2;
     23 import android.view.MotionEvent;
     24 import android.view.ViewGroup;
     25 import android.webkit.JsPromptResult;
     26 import android.webkit.JsResult;
     27 import android.webkit.WebIconDatabase;
     28 import android.webkit.WebSettings;
     29 import android.webkit.WebView;
     30 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
     31 
     32 import com.android.compatibility.common.util.NullWebViewUtils;
     33 import com.android.compatibility.common.util.PollingCheck;
     34 
     35 public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     36     private static final long TEST_TIMEOUT = 5000L;
     37 
     38     private CtsTestServer mWebServer;
     39     private WebIconDatabase mIconDb;
     40     private WebViewOnUiThread mOnUiThread;
     41     private boolean mBlockWindowCreationSync;
     42     private boolean mBlockWindowCreationAsync;
     43 
     44     public WebChromeClientTest() {
     45         super(WebViewCtsActivity.class);
     46     }
     47 
     48     @Override
     49     protected void setUp() throws Exception {
     50         super.setUp();
     51         WebView webview = getActivity().getWebView();
     52         if (webview != null) {
     53             mOnUiThread = new WebViewOnUiThread(this, webview);
     54         }
     55         mWebServer = new CtsTestServer(getActivity());
     56     }
     57 
     58     @Override
     59     protected void tearDown() throws Exception {
     60         if (mOnUiThread != null) {
     61             mOnUiThread.cleanUp();
     62         }
     63         if (mWebServer != null) {
     64             mWebServer.shutdown();
     65         }
     66         if (mIconDb != null) {
     67             mIconDb.removeAllIcons();
     68             mIconDb.close();
     69         }
     70         super.tearDown();
     71     }
     72 
     73     public void testOnProgressChanged() {
     74         if (!NullWebViewUtils.isWebViewAvailable()) {
     75             return;
     76         }
     77         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
     78         mOnUiThread.setWebChromeClient(webChromeClient);
     79 
     80         assertFalse(webChromeClient.hadOnProgressChanged());
     81         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
     82         mOnUiThread.loadUrlAndWaitForCompletion(url);
     83 
     84         new PollingCheck(TEST_TIMEOUT) {
     85             @Override
     86             protected boolean check() {
     87                 return webChromeClient.hadOnProgressChanged();
     88             }
     89         }.run();
     90     }
     91 
     92     public void testOnReceivedTitle() throws Exception {
     93         if (!NullWebViewUtils.isWebViewAvailable()) {
     94             return;
     95         }
     96         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
     97         mOnUiThread.setWebChromeClient(webChromeClient);
     98 
     99         assertFalse(webChromeClient.hadOnReceivedTitle());
    100         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
    101         mOnUiThread.loadUrlAndWaitForCompletion(url);
    102 
    103         new PollingCheck(TEST_TIMEOUT) {
    104             @Override
    105             protected boolean check() {
    106                 return webChromeClient.hadOnReceivedTitle();
    107             }
    108         }.run();
    109         assertTrue(webChromeClient.hadOnReceivedTitle());
    110         assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, webChromeClient.getPageTitle());
    111     }
    112 
    113     public void testOnReceivedIcon() throws Throwable {
    114         if (!NullWebViewUtils.isWebViewAvailable()) {
    115             return;
    116         }
    117         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    118         mOnUiThread.setWebChromeClient(webChromeClient);
    119 
    120         runTestOnUiThread(new Runnable() {
    121             @Override
    122             public void run() {
    123                 // getInstance must run on the UI thread
    124                 mIconDb = WebIconDatabase.getInstance();
    125                 String dbPath = getActivity().getFilesDir().toString() + "/icons";
    126                 mIconDb.open(dbPath);
    127             }
    128         });
    129         getInstrumentation().waitForIdleSync();
    130         Thread.sleep(100); // Wait for open to be received on the icon db thread.
    131 
    132         assertFalse(webChromeClient.hadOnReceivedIcon());
    133         assertNull(mOnUiThread.getFavicon());
    134 
    135         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
    136         mOnUiThread.loadUrlAndWaitForCompletion(url);
    137 
    138         new PollingCheck(TEST_TIMEOUT) {
    139             @Override
    140             protected boolean check() {
    141                 return webChromeClient.hadOnReceivedIcon();
    142             }
    143         }.run();
    144         assertNotNull(mOnUiThread.getFavicon());
    145     }
    146 
    147     public void runWindowTest(boolean expectWindowClose) throws Exception {
    148         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    149         mOnUiThread.setWebChromeClient(webChromeClient);
    150 
    151         final WebSettings settings = mOnUiThread.getSettings();
    152         settings.setJavaScriptEnabled(true);
    153         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    154         settings.setSupportMultipleWindows(true);
    155 
    156         assertFalse(webChromeClient.hadOnCreateWindow());
    157 
    158         // Load a page that opens a child window and sets a timeout after which the child
    159         // will be closed.
    160         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.
    161                 getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
    162 
    163         new PollingCheck(TEST_TIMEOUT) {
    164             @Override
    165             protected boolean check() {
    166                 return webChromeClient.hadOnCreateWindow();
    167             }
    168         }.run();
    169 
    170         if (expectWindowClose) {
    171             new PollingCheck(TEST_TIMEOUT) {
    172                 @Override
    173                 protected boolean check() {
    174                     return webChromeClient.hadOnCloseWindow();
    175                 }
    176             }.run();
    177         } else {
    178             assertFalse(webChromeClient.hadOnCloseWindow());
    179         }
    180     }
    181     public void testWindows() throws Exception {
    182         if (!NullWebViewUtils.isWebViewAvailable()) {
    183             return;
    184         }
    185         runWindowTest(true);
    186     }
    187 
    188     public void testBlockWindowsSync() throws Exception {
    189         if (!NullWebViewUtils.isWebViewAvailable()) {
    190             return;
    191         }
    192         mBlockWindowCreationSync = true;
    193         runWindowTest(false);
    194     }
    195 
    196     public void testBlockWindowsAsync() throws Exception {
    197         if (!NullWebViewUtils.isWebViewAvailable()) {
    198             return;
    199         }
    200         mBlockWindowCreationAsync = true;
    201         runWindowTest(false);
    202     }
    203 
    204     public void testOnJsBeforeUnloadIsCalled() throws Exception {
    205         if (!NullWebViewUtils.isWebViewAvailable()) {
    206             return;
    207         }
    208 
    209         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    210         mOnUiThread.setWebChromeClient(webChromeClient);
    211 
    212         final WebSettings settings = mOnUiThread.getSettings();
    213         settings.setJavaScriptEnabled(true);
    214         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    215 
    216         assertFalse(webChromeClient.hadOnJsBeforeUnload());
    217 
    218         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.getAssetUrl(TestHtmlConstants.JS_UNLOAD_URL));
    219 
    220         // Send a user gesture, required for unload to execute since WebView version 60.
    221         tapWebView();
    222 
    223         // unload should trigger when we try to navigate away
    224         mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
    225 
    226         new PollingCheck(TEST_TIMEOUT) {
    227             @Override
    228             protected boolean check() {
    229                 return webChromeClient.hadOnJsBeforeUnload();
    230             }
    231         }.run();
    232     }
    233 
    234     public void testOnJsAlert() throws Exception {
    235         if (!NullWebViewUtils.isWebViewAvailable()) {
    236             return;
    237         }
    238         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    239         mOnUiThread.setWebChromeClient(webChromeClient);
    240 
    241         final WebSettings settings = mOnUiThread.getSettings();
    242         settings.setJavaScriptEnabled(true);
    243         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    244 
    245         assertFalse(webChromeClient.hadOnJsAlert());
    246 
    247         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_ALERT_URL);
    248         mOnUiThread.loadUrlAndWaitForCompletion(url);
    249 
    250         new PollingCheck(TEST_TIMEOUT) {
    251             @Override
    252             protected boolean check() {
    253                 return webChromeClient.hadOnJsAlert();
    254             }
    255         }.run();
    256         assertEquals(webChromeClient.getMessage(), "testOnJsAlert");
    257     }
    258 
    259     public void testOnJsConfirm() throws Exception {
    260         if (!NullWebViewUtils.isWebViewAvailable()) {
    261             return;
    262         }
    263         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    264         mOnUiThread.setWebChromeClient(webChromeClient);
    265 
    266         final WebSettings settings = mOnUiThread.getSettings();
    267         settings.setJavaScriptEnabled(true);
    268         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    269 
    270         assertFalse(webChromeClient.hadOnJsConfirm());
    271 
    272         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_CONFIRM_URL);
    273         mOnUiThread.loadUrlAndWaitForCompletion(url);
    274 
    275         new PollingCheck(TEST_TIMEOUT) {
    276             @Override
    277             protected boolean check() {
    278                 return webChromeClient.hadOnJsConfirm();
    279             }
    280         }.run();
    281         assertEquals(webChromeClient.getMessage(), "testOnJsConfirm");
    282     }
    283 
    284     public void testOnJsPrompt() throws Exception {
    285         if (!NullWebViewUtils.isWebViewAvailable()) {
    286             return;
    287         }
    288         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
    289         mOnUiThread.setWebChromeClient(webChromeClient);
    290 
    291         final WebSettings settings = mOnUiThread.getSettings();
    292         settings.setJavaScriptEnabled(true);
    293         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    294 
    295         assertFalse(webChromeClient.hadOnJsPrompt());
    296 
    297         final String promptResult = "CTS";
    298         webChromeClient.setPromptResult(promptResult);
    299         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_PROMPT_URL);
    300         mOnUiThread.loadUrlAndWaitForCompletion(url);
    301 
    302         new PollingCheck(TEST_TIMEOUT) {
    303             @Override
    304             protected boolean check() {
    305                 return webChromeClient.hadOnJsPrompt();
    306             }
    307         }.run();
    308         // the result returned by the client gets set as the page title
    309         new PollingCheck(TEST_TIMEOUT) {
    310             @Override
    311             protected boolean check() {
    312                 return mOnUiThread.getTitle().equals(promptResult);
    313             }
    314         }.run();
    315         assertEquals(webChromeClient.getMessage(), "testOnJsPrompt");
    316     }
    317 
    318     /**
    319      * Taps in the the center of a webview.
    320      */
    321     private void tapWebView() {
    322         int[] location = mOnUiThread.getLocationOnScreen();
    323         int middleX = location[0] + mOnUiThread.getWebView().getWidth() / 2;
    324         int middleY = location[1] + mOnUiThread.getWebView().getHeight() / 2;
    325 
    326         long timeDown = SystemClock.uptimeMillis();
    327         getInstrumentation().sendPointerSync(
    328                 MotionEvent.obtain(timeDown, timeDown, MotionEvent.ACTION_DOWN,
    329                         middleX, middleY, 0));
    330 
    331         long timeUp = SystemClock.uptimeMillis();
    332         getInstrumentation().sendPointerSync(
    333                 MotionEvent.obtain(timeUp, timeUp, MotionEvent.ACTION_UP,
    334                         middleX, middleY, 0));
    335 
    336         // Wait for the system to process all events in the queue
    337         getInstrumentation().waitForIdleSync();
    338     }
    339 
    340     private class MockWebChromeClient extends WaitForProgressClient {
    341         private boolean mHadOnProgressChanged;
    342         private boolean mHadOnReceivedTitle;
    343         private String mPageTitle;
    344         private boolean mHadOnJsAlert;
    345         private boolean mHadOnJsConfirm;
    346         private boolean mHadOnJsPrompt;
    347         private boolean mHadOnJsBeforeUnload;
    348         private String mMessage;
    349         private String mPromptResult;
    350         private boolean mHadOnCloseWindow;
    351         private boolean mHadOnCreateWindow;
    352         private boolean mHadOnRequestFocus;
    353         private boolean mHadOnReceivedIcon;
    354 
    355         public MockWebChromeClient() {
    356             super(mOnUiThread);
    357         }
    358 
    359         public void setPromptResult(String promptResult) {
    360             mPromptResult = promptResult;
    361         }
    362 
    363         public boolean hadOnProgressChanged() {
    364             return mHadOnProgressChanged;
    365         }
    366 
    367         public boolean hadOnReceivedTitle() {
    368             return mHadOnReceivedTitle;
    369         }
    370 
    371         public String getPageTitle() {
    372             return mPageTitle;
    373         }
    374 
    375         public boolean hadOnJsAlert() {
    376             return mHadOnJsAlert;
    377         }
    378 
    379         public boolean hadOnJsConfirm() {
    380             return mHadOnJsConfirm;
    381         }
    382 
    383         public boolean hadOnJsPrompt() {
    384             return mHadOnJsPrompt;
    385         }
    386 
    387         public boolean hadOnJsBeforeUnload() {
    388             return mHadOnJsBeforeUnload;
    389         }
    390 
    391         public boolean hadOnCreateWindow() {
    392             return mHadOnCreateWindow;
    393         }
    394 
    395         public boolean hadOnCloseWindow() {
    396             return mHadOnCloseWindow;
    397         }
    398 
    399         public boolean hadOnRequestFocus() {
    400             return mHadOnRequestFocus;
    401         }
    402 
    403         public boolean hadOnReceivedIcon() {
    404             return mHadOnReceivedIcon;
    405         }
    406 
    407         public String getMessage() {
    408             return mMessage;
    409         }
    410 
    411         @Override
    412         public void onProgressChanged(WebView view, int newProgress) {
    413             super.onProgressChanged(view, newProgress);
    414             mHadOnProgressChanged = true;
    415         }
    416 
    417         @Override
    418         public void onReceivedTitle(WebView view, String title) {
    419             super.onReceivedTitle(view, title);
    420             mPageTitle = title;
    421             mHadOnReceivedTitle = true;
    422         }
    423 
    424         @Override
    425         public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    426             super.onJsAlert(view, url, message, result);
    427             mHadOnJsAlert = true;
    428             mMessage = message;
    429             result.confirm();
    430             return true;
    431         }
    432 
    433         @Override
    434         public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    435             super.onJsConfirm(view, url, message, result);
    436             mHadOnJsConfirm = true;
    437             mMessage = message;
    438             result.confirm();
    439             return true;
    440         }
    441 
    442         @Override
    443         public boolean onJsPrompt(WebView view, String url, String message,
    444                 String defaultValue, JsPromptResult result) {
    445             super.onJsPrompt(view, url, message, defaultValue, result);
    446             mHadOnJsPrompt = true;
    447             mMessage = message;
    448             result.confirm(mPromptResult);
    449             return true;
    450         }
    451 
    452         @Override
    453         public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
    454             super.onJsBeforeUnload(view, url, message, result);
    455             mHadOnJsBeforeUnload = true;
    456             mMessage = message;
    457             result.confirm();
    458             return true;
    459         }
    460 
    461         @Override
    462         public void onCloseWindow(WebView window) {
    463             super.onCloseWindow(window);
    464             mHadOnCloseWindow = true;
    465         }
    466 
    467         @Override
    468         public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
    469                 Message resultMsg) {
    470             mHadOnCreateWindow = true;
    471             if (mBlockWindowCreationSync) {
    472                 return false;
    473             }
    474             WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
    475             if (mBlockWindowCreationAsync) {
    476                 transport.setWebView(null);
    477             } else {
    478                 WebView childView = new WebView(getActivity());
    479                 final WebSettings settings = childView.getSettings();
    480                 settings.setJavaScriptEnabled(true);
    481                 childView.setWebChromeClient(this);
    482                 transport.setWebView(childView);
    483                 getActivity().addContentView(childView, new ViewGroup.LayoutParams(
    484                         ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    485             }
    486             resultMsg.sendToTarget();
    487             return true;
    488         }
    489 
    490         @Override
    491         public void onRequestFocus(WebView view) {
    492             mHadOnRequestFocus = true;
    493         }
    494 
    495         @Override
    496         public void onReceivedIcon(WebView view, Bitmap icon) {
    497             mHadOnReceivedIcon = true;
    498         }
    499     }
    500 }
    501