1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.android_webview.test; 6 7import android.graphics.Bitmap; 8import android.graphics.BitmapFactory; 9import android.test.suitebuilder.annotation.SmallTest; 10 11import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; 12 13import org.chromium.android_webview.AwContents; 14import org.chromium.android_webview.test.util.CommonResources; 15import org.chromium.content.browser.test.util.CallbackHelper; 16import org.chromium.net.test.util.TestWebServer; 17 18import java.io.InputStream; 19import java.net.URL; 20import java.util.HashMap; 21import java.util.concurrent.Callable; 22 23/** 24 * Tests for the Favicon and TouchIcon related APIs. 25 */ 26public class AwContentsClientFaviconTest extends AwTestBase { 27 28 private static final String FAVICON1_URL = "/favicon1.png"; 29 private static final String FAVICON1_PAGE_URL = "/favicon1.html"; 30 private static final String FAVICON1_PAGE_HTML = 31 CommonResources.makeHtmlPageFrom( 32 "<link rel=\"icon\" href=\"" + FAVICON1_URL + "\" />", 33 "Body"); 34 35 private static final String TOUCHICON_REL_LINK = "touch.png"; 36 private static final String TOUCHICON_REL_LINK_72 = "touch_72.png"; 37 private static final String TOUCHICON_REL_URL = "/" + TOUCHICON_REL_LINK; 38 private static final String TOUCHICON_REL_URL_72 = "/" + TOUCHICON_REL_LINK_72; 39 private static final String TOUCHICON_REL_PAGE_HTML = 40 CommonResources.makeHtmlPageFrom( 41 "<link rel=\"apple-touch-icon\" href=\"" + TOUCHICON_REL_URL + "\" />" + 42 "<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"" + TOUCHICON_REL_URL_72 43 + "\" />", 44 "Body"); 45 46 // Maximum number of milliseconds within which a request to web server is made. 47 private static final long MAX_REQUEST_WAITING_LIMIT_MS = scaleTimeout(500); 48 49 private static class FaviconHelper extends CallbackHelper { 50 private Bitmap mIcon; 51 private HashMap<String, Boolean> mTouchIcons = new HashMap<String, Boolean>(); 52 53 public void notifyFavicon(Bitmap icon) { 54 mIcon = icon; 55 super.notifyCalled(); 56 } 57 58 public void notifyTouchIcon(String url, boolean precomposed) { 59 mTouchIcons.put(url, precomposed); 60 super.notifyCalled(); 61 } 62 } 63 64 private static class TestAwContentsClientBase 65 extends org.chromium.android_webview.test.TestAwContentsClient { 66 FaviconHelper mFaviconHelper = new FaviconHelper(); 67 } 68 69 private static class TestAwContentsClientFavicon extends TestAwContentsClientBase { 70 @Override 71 public void onReceivedIcon(Bitmap bitmap) { 72 // We don't inform the API client about the URL of the icon. 73 mFaviconHelper.notifyFavicon(bitmap); 74 } 75 } 76 77 private static class TestAwContentsClientTouchIcon extends TestAwContentsClientBase { 78 @Override 79 public void onReceivedTouchIconUrl(String url, boolean precomposed) { 80 mFaviconHelper.notifyTouchIcon(url, precomposed); 81 } 82 } 83 84 private TestAwContentsClientBase mContentsClient; 85 private AwContents mAwContents; 86 private TestWebServer mWebServer; 87 88 @Override 89 protected void setUp() throws Exception { 90 super.setUp(); 91 AwContents.setShouldDownloadFavicons(); 92 mWebServer = new TestWebServer(false); 93 } 94 95 private void init(TestAwContentsClientBase contentsClient) throws Exception { 96 mContentsClient = contentsClient; 97 AwTestContainerView testContainerView = 98 createAwTestContainerViewOnMainSync(mContentsClient); 99 mAwContents = testContainerView.getAwContents(); 100 } 101 102 @Override 103 protected void tearDown() throws Exception { 104 if (mWebServer != null) mWebServer.shutdown(); 105 super.tearDown(); 106 } 107 108 @SmallTest 109 public void testReceiveBasicFavicon() throws Throwable { 110 init(new TestAwContentsClientFavicon()); 111 int callCount = mContentsClient.mFaviconHelper.getCallCount(); 112 113 final String faviconUrl = mWebServer.setResponseBase64(FAVICON1_URL, 114 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true)); 115 final String pageUrl = mWebServer.setResponse(FAVICON1_PAGE_URL, FAVICON1_PAGE_HTML, 116 CommonResources.getTextHtmlHeaders(true)); 117 118 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl); 119 120 mContentsClient.mFaviconHelper.waitForCallback(callCount); 121 assertEquals(1, mWebServer.getRequestCount(FAVICON1_URL)); 122 Object originalFaviconSource = (new URL(faviconUrl)).getContent(); 123 Bitmap originalFavicon = BitmapFactory.decodeStream((InputStream) originalFaviconSource); 124 assertNotNull(originalFavicon); 125 assertNotNull(mContentsClient.mFaviconHelper.mIcon); 126 assertTrue(mContentsClient.mFaviconHelper.mIcon.sameAs(originalFavicon)); 127 128 // Make sure the request counter for favicon is incremented when the page is loaded again 129 // successfully. 130 loadUrlAsync(mAwContents, pageUrl); 131 mContentsClient.mFaviconHelper.waitForCallback(callCount); 132 assertEquals(2, mWebServer.getRequestCount(FAVICON1_URL)); 133 } 134 135 @SmallTest 136 public void testDoNotMakeRequestForFaviconAfter404() throws Throwable { 137 init(new TestAwContentsClientFavicon()); 138 139 mWebServer.setResponseWithNotFoundStatus(FAVICON1_URL); 140 final String pageUrl = mWebServer.setResponse(FAVICON1_PAGE_URL, FAVICON1_PAGE_HTML, 141 CommonResources.getTextHtmlHeaders(true)); 142 143 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl); 144 poll(new Callable<Boolean>() { 145 @Override 146 public Boolean call() throws Exception { 147 return mWebServer.getRequestCount(FAVICON1_URL) == 1; 148 } 149 }); 150 151 // Make sure the request counter for favicon is not incremented, since we already got 404. 152 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl); 153 // If a request hasn't been done within this time period, we assume it won't be done. 154 Thread.sleep(MAX_REQUEST_WAITING_LIMIT_MS); 155 assertEquals(1, mWebServer.getRequestCount(FAVICON1_URL)); 156 } 157 158 @SmallTest 159 public void testReceiveBasicTouchIconLinkRel() throws Throwable { 160 init(new TestAwContentsClientTouchIcon()); 161 int callCount = mContentsClient.mFaviconHelper.getCallCount(); 162 163 final String pageUrl = mWebServer.setResponse(TOUCHICON_REL_URL, TOUCHICON_REL_PAGE_HTML, 164 CommonResources.getTextHtmlHeaders(true)); 165 166 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageUrl); 167 168 mContentsClient.mFaviconHelper.waitForCallback(callCount, 2); 169 HashMap<String, Boolean> touchIcons = mContentsClient.mFaviconHelper.mTouchIcons; 170 assertEquals(2, touchIcons.size()); 171 assertFalse(touchIcons.get(mWebServer.getBaseUrl() + TOUCHICON_REL_LINK)); 172 assertFalse(touchIcons.get(mWebServer.getBaseUrl() + TOUCHICON_REL_LINK_72)); 173 } 174} 175