| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package com.android.webview.chromium; | 5 package com.android.webview.chromium; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.content.res.Configuration; | 8 import android.content.res.Configuration; |
| 9 import android.graphics.Bitmap; | 9 import android.graphics.Bitmap; |
| 10 import android.graphics.Canvas; | 10 import android.graphics.Canvas; |
| 11 import android.graphics.Paint; | 11 import android.graphics.Paint; |
| 12 import android.graphics.Picture; | 12 import android.graphics.Picture; |
| 13 import android.graphics.Rect; | 13 import android.graphics.Rect; |
| 14 import android.graphics.drawable.Drawable; | 14 import android.graphics.drawable.Drawable; |
| 15 import android.net.http.SslCertificate; | 15 import android.net.http.SslCertificate; |
| 16 import android.os.Build; | 16 import android.os.Build; |
| 17 import android.os.Bundle; | 17 import android.os.Bundle; |
| 18 import android.os.Handler; | 18 import android.os.Handler; |
| 19 import android.os.Looper; | 19 import android.os.Looper; |
| 20 import android.os.Message; | 20 import android.os.Message; |
| 21 import android.print.PrintDocumentAdapter; | 21 import android.print.PrintDocumentAdapter; |
| 22 import android.text.TextUtils; | |
| 23 import android.util.Base64; | |
| 24 import android.util.Log; | 22 import android.util.Log; |
| 25 import android.view.KeyEvent; | 23 import android.view.KeyEvent; |
| 26 import android.view.MotionEvent; | 24 import android.view.MotionEvent; |
| 27 import android.view.View; | 25 import android.view.View; |
| 28 import android.view.ViewGroup; | 26 import android.view.ViewGroup; |
| 29 import android.view.accessibility.AccessibilityEvent; | 27 import android.view.accessibility.AccessibilityEvent; |
| 30 import android.view.accessibility.AccessibilityNodeInfo; | 28 import android.view.accessibility.AccessibilityNodeInfo; |
| 31 import android.view.accessibility.AccessibilityNodeProvider; | 29 import android.view.accessibility.AccessibilityNodeProvider; |
| 32 import android.view.inputmethod.EditorInfo; | 30 import android.view.inputmethod.EditorInfo; |
| 33 import android.view.inputmethod.InputConnection; | 31 import android.view.inputmethod.InputConnection; |
| 34 import android.webkit.DownloadListener; | 32 import android.webkit.DownloadListener; |
| 35 import android.webkit.FindActionModeCallback; | 33 import android.webkit.FindActionModeCallback; |
| 36 import android.webkit.JavascriptInterface; | 34 import android.webkit.JavascriptInterface; |
| 37 import android.webkit.ValueCallback; | 35 import android.webkit.ValueCallback; |
| 38 import android.webkit.WebBackForwardList; | 36 import android.webkit.WebBackForwardList; |
| 39 import android.webkit.WebChromeClient; | 37 import android.webkit.WebChromeClient; |
| 40 import android.webkit.WebChromeClient.CustomViewCallback; | 38 import android.webkit.WebChromeClient.CustomViewCallback; |
| 41 import android.webkit.WebSettings; | 39 import android.webkit.WebSettings; |
| 42 import android.webkit.WebView; | 40 import android.webkit.WebView; |
| 43 import android.webkit.WebViewClient; | 41 import android.webkit.WebViewClient; |
| 44 import android.webkit.WebViewProvider; | 42 import android.webkit.WebViewProvider; |
| 45 import android.widget.TextView; | 43 import android.widget.TextView; |
| 46 | 44 |
| 47 import org.chromium.android_webview.AwContents; | 45 import org.chromium.android_webview.AwContents; |
| 48 import org.chromium.android_webview.AwContentsStatics; | 46 import org.chromium.android_webview.AwContentsStatics; |
| 49 import org.chromium.android_webview.AwPrintDocumentAdapter; | 47 import org.chromium.android_webview.AwPrintDocumentAdapter; |
| 50 import org.chromium.android_webview.AwSettings; | 48 import org.chromium.android_webview.AwSettings; |
| 51 import org.chromium.base.ThreadUtils; | 49 import org.chromium.base.ThreadUtils; |
| 52 import org.chromium.content.browser.SmartClipProvider; | 50 import org.chromium.content.browser.SmartClipProvider; |
| 53 import org.chromium.content_public.browser.LoadUrlParams; | |
| 54 | 51 |
| 55 import java.io.BufferedWriter; | 52 import java.io.BufferedWriter; |
| 56 import java.io.File; | 53 import java.io.File; |
| 57 import java.lang.annotation.Annotation; | 54 import java.lang.annotation.Annotation; |
| 58 import java.util.HashMap; | |
| 59 import java.util.Map; | 55 import java.util.Map; |
| 60 import java.util.Queue; | 56 import java.util.Queue; |
| 61 import java.util.concurrent.Callable; | 57 import java.util.concurrent.Callable; |
| 62 import java.util.concurrent.ConcurrentLinkedQueue; | 58 import java.util.concurrent.ConcurrentLinkedQueue; |
| 63 import java.util.concurrent.FutureTask; | 59 import java.util.concurrent.FutureTask; |
| 64 import java.util.concurrent.TimeUnit; | 60 import java.util.concurrent.TimeUnit; |
| 65 | 61 |
| 66 /** | 62 /** |
| 67 * This class is the delegate to which WebViewProxy forwards all API calls. | 63 * This class is the delegate to which WebViewProxy forwards all API calls. |
| 68 * | 64 * |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 } | 495 } |
| 500 }); | 496 }); |
| 501 return ret; | 497 return ret; |
| 502 } | 498 } |
| 503 if (inState == null) return null; | 499 if (inState == null) return null; |
| 504 if (!mAwContents.restoreState(inState)) return null; | 500 if (!mAwContents.restoreState(inState)) return null; |
| 505 return copyBackForwardList(); | 501 return copyBackForwardList(); |
| 506 } | 502 } |
| 507 | 503 |
| 508 @Override | 504 @Override |
| 509 public void loadUrl(final String url, Map<String, String> additionalHttpHead
ers) { | 505 public void loadUrl(final String url, final Map<String, String> additionalHt
tpHeaders) { |
| 510 // TODO: We may actually want to do some sanity checks here (like filter
about://chrome). | 506 mFactory.startYourEngines(true); |
| 511 | 507 if (checkNeedsPost()) { |
| 512 // For backwards compatibility, apps targeting less than K will have JS
URLs evaluated | 508 // Disallowed in WebView API for apps targetting a new SDK |
| 513 // directly and any result of the evaluation will not replace the curren
t page content. | 509 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; |
| 514 // Matching Chrome behavior more closely; apps targetting >= K that load
a JS URL will | 510 mRunQueue.addTask(new Runnable() { |
| 515 // have the result of that URL replace the content of the current page. | 511 @Override |
| 516 final String javaScriptScheme = "javascript:"; | 512 public void run() { |
| 517 if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT && url != null | 513 mAwContents.loadUrl(url, additionalHttpHeaders); |
| 518 && url.startsWith(javaScriptScheme)) { | 514 } |
| 519 mFactory.startYourEngines(true); | 515 }); |
| 520 if (checkNeedsPost()) { | |
| 521 mRunQueue.addTask(new Runnable() { | |
| 522 @Override | |
| 523 public void run() { | |
| 524 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( | |
| 525 url.substring(javaScriptScheme.length())); | |
| 526 } | |
| 527 }); | |
| 528 } else { | |
| 529 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( | |
| 530 url.substring(javaScriptScheme.length())); | |
| 531 } | |
| 532 return; | 516 return; |
| 533 } | 517 } |
| 534 | 518 mAwContents.loadUrl(url, additionalHttpHeaders); |
| 535 LoadUrlParams params = new LoadUrlParams(url); | |
| 536 if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttp
Headers); | |
| 537 loadUrlOnUiThread(params); | |
| 538 } | 519 } |
| 539 | 520 |
| 540 @Override | 521 @Override |
| 541 public void loadUrl(String url) { | 522 public void loadUrl(final String url) { |
| 542 // Early out to match old WebView implementation | 523 mFactory.startYourEngines(true); |
| 543 if (url == null) { | 524 if (checkNeedsPost()) { |
| 525 // Disallowed in WebView API for apps targetting a new SDK |
| 526 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; |
| 527 mRunQueue.addTask(new Runnable() { |
| 528 @Override |
| 529 public void run() { |
| 530 mAwContents.loadUrl(url); |
| 531 } |
| 532 }); |
| 544 return; | 533 return; |
| 545 } | 534 } |
| 546 loadUrl(url, null); | 535 mAwContents.loadUrl(url); |
| 547 } | 536 } |
| 548 | 537 |
| 549 @Override | 538 @Override |
| 550 public void postUrl(String url, byte[] postData) { | 539 public void postUrl(final String url, final byte[] postData) { |
| 551 LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postD
ata); | 540 mFactory.startYourEngines(true); |
| 552 Map<String, String> headers = new HashMap<String, String>(); | 541 if (checkNeedsPost()) { |
| 553 headers.put("Content-Type", "application/x-www-form-urlencoded"); | 542 // Disallowed in WebView API for apps targetting a new SDK |
| 554 params.setExtraHeaders(headers); | 543 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; |
| 555 loadUrlOnUiThread(params); | 544 mRunQueue.addTask(new Runnable() { |
| 556 } | 545 @Override |
| 557 | 546 public void run() { |
| 558 private static String fixupMimeType(String mimeType) { | 547 mAwContents.postUrl(url, postData); |
| 559 return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType; | 548 } |
| 560 } | 549 }); |
| 561 | 550 return; |
| 562 private static String fixupData(String data) { | 551 } |
| 563 return TextUtils.isEmpty(data) ? "" : data; | 552 mAwContents.postUrl(url, postData); |
| 564 } | |
| 565 | |
| 566 private static String fixupBase(String url) { | |
| 567 return TextUtils.isEmpty(url) ? "about:blank" : url; | |
| 568 } | |
| 569 | |
| 570 private static String fixupHistory(String url) { | |
| 571 return TextUtils.isEmpty(url) ? "about:blank" : url; | |
| 572 } | |
| 573 | |
| 574 private static boolean isBase64Encoded(String encoding) { | |
| 575 return "base64".equals(encoding); | |
| 576 } | 553 } |
| 577 | 554 |
| 578 @Override | 555 @Override |
| 579 public void loadData(String data, String mimeType, String encoding) { | 556 public void loadData(final String data, final String mimeType, final String
encoding) { |
| 580 loadUrlOnUiThread(LoadUrlParams.createLoadDataParams( | 557 mFactory.startYourEngines(true); |
| 581 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encodi
ng))); | 558 if (checkNeedsPost()) { |
| 559 // Disallowed in WebView API for apps targetting a new SDK |
| 560 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; |
| 561 mRunQueue.addTask(new Runnable() { |
| 562 @Override |
| 563 public void run() { |
| 564 mAwContents.loadData(data, mimeType, encoding); |
| 565 } |
| 566 }); |
| 567 return; |
| 568 } |
| 569 mAwContents.loadData(data, mimeType, encoding); |
| 582 } | 570 } |
| 583 | 571 |
| 584 @Override | 572 @Override |
| 585 public void loadDataWithBaseURL(String baseUrl, String data, String mimeType
, String encoding, | 573 public void loadDataWithBaseURL(final String baseUrl, final String data, fin
al String mimeType, |
| 586 String historyUrl) { | 574 final String encoding, final String historyUrl) { |
| 587 data = fixupData(data); | |
| 588 mimeType = fixupMimeType(mimeType); | |
| 589 LoadUrlParams loadUrlParams; | |
| 590 baseUrl = fixupBase(baseUrl); | |
| 591 historyUrl = fixupHistory(historyUrl); | |
| 592 | |
| 593 if (baseUrl.startsWith("data:")) { | |
| 594 // For backwards compatibility with WebViewClassic, we use the value
of |encoding| | |
| 595 // as the charset, as long as it's not "base64". | |
| 596 boolean isBase64 = isBase64Encoded(encoding); | |
| 597 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( | |
| 598 data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? nu
ll : encoding); | |
| 599 } else { | |
| 600 // When loading data with a non-data: base URL, the classic WebView
would effectively | |
| 601 // "dump" that string of data into the WebView without going through
regular URL | |
| 602 // loading steps such as decoding URL-encoded entities. We achieve t
his same behavior by | |
| 603 // base64 encoding the data that is passed here and then loading tha
t as a data: URL. | |
| 604 try { | |
| 605 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( | |
| 606 Base64.encodeToString(data.getBytes("utf-8"), Base64.DEF
AULT), mimeType, | |
| 607 true, baseUrl, historyUrl, "utf-8"); | |
| 608 } catch (java.io.UnsupportedEncodingException e) { | |
| 609 Log.wtf(TAG, "Unable to load data string " + data, e); | |
| 610 return; | |
| 611 } | |
| 612 } | |
| 613 loadUrlOnUiThread(loadUrlParams); | |
| 614 } | |
| 615 | |
| 616 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { | |
| 617 // This is the last point that we can delay starting the Chromium backen
d up | |
| 618 // and if the app has not caused us to bind the Chromium UI thread to a
background thread | |
| 619 // we now bind Chromium's notion of the UI thread to the app main thread
. | |
| 620 mFactory.startYourEngines(true); | 575 mFactory.startYourEngines(true); |
| 621 if (checkNeedsPost()) { | 576 if (checkNeedsPost()) { |
| 622 // Disallowed in WebView API for apps targetting a new SDK | 577 // Disallowed in WebView API for apps targetting a new SDK |
| 623 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; | 578 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; |
| 624 mRunQueue.addTask(new Runnable() { | 579 mRunQueue.addTask(new Runnable() { |
| 625 @Override | 580 @Override |
| 626 public void run() { | 581 public void run() { |
| 627 mAwContents.loadUrl(loadUrlParams); | 582 mAwContents.loadDataWithBaseURL(baseUrl, data, mimeType, enc
oding, historyUrl); |
| 628 } | 583 } |
| 629 }); | 584 }); |
| 630 return; | 585 return; |
| 631 } | 586 } |
| 632 mAwContents.loadUrl(loadUrlParams); | 587 mAwContents.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, histo
ryUrl); |
| 633 } | 588 } |
| 634 | 589 |
| 635 public void evaluateJavaScript(String script, ValueCallback<String> resultCa
llback) { | 590 public void evaluateJavaScript(String script, ValueCallback<String> resultCa
llback) { |
| 636 checkThread(); | 591 checkThread(); |
| 637 mAwContents.evaluateJavaScript(script, resultCallback); | 592 mAwContents.evaluateJavaScript(script, resultCallback); |
| 638 } | 593 } |
| 639 | 594 |
| 640 @Override | 595 @Override |
| 641 public void saveWebArchive(String filename) { | 596 public void saveWebArchive(String filename) { |
| 642 saveWebArchive(filename, false, null); | 597 saveWebArchive(filename, false, null); |
| (...skipping 1563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2206 mAwContents.extractSmartClipData(x, y, width, height); | 2161 mAwContents.extractSmartClipData(x, y, width, height); |
| 2207 } | 2162 } |
| 2208 | 2163 |
| 2209 // Implements SmartClipProvider | 2164 // Implements SmartClipProvider |
| 2210 @Override | 2165 @Override |
| 2211 public void setSmartClipResultHandler(final Handler resultHandler) { | 2166 public void setSmartClipResultHandler(final Handler resultHandler) { |
| 2212 checkThread(); | 2167 checkThread(); |
| 2213 mAwContents.setSmartClipResultHandler(resultHandler); | 2168 mAwContents.setSmartClipResultHandler(resultHandler); |
| 2214 } | 2169 } |
| 2215 } | 2170 } |
| OLD | NEW |