1 // Copyright 2018 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 
5 package com.android.webview.chromium;
6 
7 import android.webkit.WebChromeClient;
8 import android.webkit.WebViewClient;
9 
10 import org.chromium.android_webview.AwContents;
11 import org.chromium.android_webview.AwRenderProcess;
12 import org.chromium.android_webview.ScriptReference;
13 import org.chromium.android_webview.WebMessageListener;
14 import org.chromium.android_webview.WebViewChromiumRunQueue;
15 import org.chromium.base.ThreadUtils;
16 import org.chromium.content_public.browser.MessagePort;
17 
18 import java.util.concurrent.Callable;
19 
20 /**
21  * This class contains the parts of WebViewChromium that should be shared between the webkit-glue
22  * layer and the support library glue layer.
23  */
24 public class SharedWebViewChromium {
25     private final WebViewChromiumRunQueue mRunQueue;
26     private final WebViewChromiumAwInit mAwInit;
27     // The WebView wrapper for WebContents and required browser components.
28     private AwContents mAwContents;
29 
30     private SharedWebViewContentsClientAdapter mContentsClientAdapter;
31 
32     // Default WebViewClient used to avoid null checks.
33     static final WebViewClient sNullWebViewClient = new WebViewClient();
34     // The WebViewClient instance that was passed to WebView.setWebViewClient().
35     private WebViewClient mWebViewClient = sNullWebViewClient;
36     private WebChromeClient mWebChromeClient;
37 
SharedWebViewChromium(WebViewChromiumRunQueue runQueue, WebViewChromiumAwInit awInit)38     public SharedWebViewChromium(WebViewChromiumRunQueue runQueue, WebViewChromiumAwInit awInit) {
39         mRunQueue = runQueue;
40         mAwInit = awInit;
41     }
42 
setWebViewClient(WebViewClient client)43     void setWebViewClient(WebViewClient client) {
44         mWebViewClient = client != null ? client : sNullWebViewClient;
45     }
46 
getWebViewClient()47     public WebViewClient getWebViewClient() {
48         return mWebViewClient;
49     }
50 
setWebChromeClient(WebChromeClient client)51     void setWebChromeClient(WebChromeClient client) {
52         mWebChromeClient = client;
53     }
54 
getWebChromeClient()55     public WebChromeClient getWebChromeClient() {
56         return mWebChromeClient;
57     }
58 
getRenderProcess()59     public AwRenderProcess getRenderProcess() {
60         mAwInit.startYourEngines(true);
61         if (checkNeedsPost()) {
62             return mRunQueue.runOnUiThreadBlocking(() -> getRenderProcess());
63         }
64         return mAwContents.getRenderProcess();
65     }
66 
init(SharedWebViewContentsClientAdapter contentsClientAdapter)67     public void init(SharedWebViewContentsClientAdapter contentsClientAdapter) {
68         mContentsClientAdapter = contentsClientAdapter;
69     }
70 
initForReal(AwContents awContents)71     public void initForReal(AwContents awContents) {
72         assert ThreadUtils.runningOnUiThread();
73 
74         if (mAwContents != null) {
75             throw new RuntimeException(
76                     "Cannot create multiple AwContents for the same SharedWebViewChromium");
77         }
78         mAwContents = awContents;
79     }
80 
insertVisualStateCallback(long requestId, AwContents.VisualStateCallback callback)81     public void insertVisualStateCallback(long requestId, AwContents.VisualStateCallback callback) {
82         if (checkNeedsPost()) {
83             mRunQueue.addTask(new Runnable() {
84                 @Override
85                 public void run() {
86                     insertVisualStateCallback(requestId, callback);
87                 }
88             });
89             return;
90         }
91         mAwContents.insertVisualStateCallback(requestId, callback);
92     }
93 
createWebMessageChannel()94     public MessagePort[] createWebMessageChannel() {
95         mAwInit.startYourEngines(true);
96         if (checkNeedsPost()) {
97             MessagePort[] ret = mRunQueue.runOnUiThreadBlocking(new Callable<MessagePort[]>() {
98                 @Override
99                 public MessagePort[] call() {
100                     return createWebMessageChannel();
101                 }
102             });
103             return ret;
104         }
105         return mAwContents.createMessageChannel();
106     }
107 
postMessageToMainFrame( final String message, final String targetOrigin, final MessagePort[] sentPorts)108     public void postMessageToMainFrame(
109             final String message, final String targetOrigin, final MessagePort[] sentPorts) {
110         if (checkNeedsPost()) {
111             mRunQueue.addTask(new Runnable() {
112                 @Override
113                 public void run() {
114                     postMessageToMainFrame(message, targetOrigin, sentPorts);
115                 }
116             });
117             return;
118         }
119         mAwContents.postMessageToMainFrame(message, targetOrigin, sentPorts);
120     }
121 
addWebMessageListener(final String jsObjectName, final String[] allowedOriginRules, final WebMessageListener listener)122     public void addWebMessageListener(final String jsObjectName, final String[] allowedOriginRules,
123             final WebMessageListener listener) {
124         if (checkNeedsPost()) {
125             mRunQueue.addTask(
126                     () -> addWebMessageListener(jsObjectName, allowedOriginRules, listener));
127             return;
128         }
129         mAwContents.addWebMessageListener(jsObjectName, allowedOriginRules, listener);
130     }
131 
removeWebMessageListener(final String jsObjectName)132     public void removeWebMessageListener(final String jsObjectName) {
133         if (checkNeedsPost()) {
134             mRunQueue.addTask(() -> removeWebMessageListener(jsObjectName));
135             return;
136         }
137         mAwContents.removeWebMessageListener(jsObjectName);
138     }
139 
addDocumentStartJavaScript( final String script, final String[] allowedOriginRules)140     public ScriptReference addDocumentStartJavaScript(
141             final String script, final String[] allowedOriginRules) {
142         if (checkNeedsPost()) {
143             return mRunQueue.runOnUiThreadBlocking(
144                     () -> addDocumentStartJavaScript(script, allowedOriginRules));
145         }
146         return mAwContents.addDocumentStartJavaScript(script, allowedOriginRules);
147     }
148 
setWebViewRendererClientAdapter( SharedWebViewRendererClientAdapter webViewRendererClientAdapter)149     public void setWebViewRendererClientAdapter(
150             SharedWebViewRendererClientAdapter webViewRendererClientAdapter) {
151         if (checkNeedsPost()) {
152             mRunQueue.addTask(new Runnable() {
153                 @Override
154                 public void run() {
155                     setWebViewRendererClientAdapter(webViewRendererClientAdapter);
156                 }
157             });
158             return;
159         }
160         mContentsClientAdapter.setWebViewRendererClientAdapter(webViewRendererClientAdapter);
161     }
162 
getWebViewRendererClientAdapter()163     public SharedWebViewRendererClientAdapter getWebViewRendererClientAdapter() {
164         mAwInit.startYourEngines(true);
165         if (checkNeedsPost()) {
166             return mRunQueue.runOnUiThreadBlocking(
167                     new Callable<SharedWebViewRendererClientAdapter>() {
168                         @Override
169                         public SharedWebViewRendererClientAdapter call() {
170                             return getWebViewRendererClientAdapter();
171                         }
172                     });
173         }
174         return mContentsClientAdapter.getWebViewRendererClientAdapter();
175     }
176 
177     protected boolean checkNeedsPost() {
178         boolean needsPost = !mRunQueue.chromiumHasStarted() || !ThreadUtils.runningOnUiThread();
179         if (!needsPost && mAwContents == null) {
180             throw new IllegalStateException("AwContents must be created if we are not posting!");
181         }
182         return needsPost;
183     }
184 
185     public AwContents getAwContents() {
186         return mAwContents;
187     }
188 }
189