1 | /*
|
2 | Licensed to the Apache Software Foundation (ASF) under one
|
3 | or more contributor license agreements. See the NOTICE file
|
4 | distributed with this work for additional information
|
5 | regarding copyright ownership. The ASF licenses this file
|
6 | to you under the Apache License, Version 2.0 (the
|
7 | "License"); you may not use this file except in compliance
|
8 | with the License. You may obtain a copy of the License at
|
9 |
|
10 | http://www.apache.org/licenses/LICENSE-2.0
|
11 |
|
12 | Unless required by applicable law or agreed to in writing,
|
13 | software distributed under the License is distributed on an
|
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15 | KIND, either express or implied. See the License for the
|
16 | specific language governing permissions and limitations
|
17 | under the License.
|
18 | */
|
19 | package org.apache.cordova.inappbrowser;
|
20 |
|
21 | import org.apache.cordova.CordovaWebView;
|
22 | import org.apache.cordova.LOG;
|
23 | import org.apache.cordova.PluginResult;
|
24 | import org.json.JSONArray;
|
25 | import org.json.JSONException;
|
26 |
|
27 | import android.annotation.TargetApi;
|
28 | import android.os.Build;
|
29 | import android.os.Message;
|
30 | import android.webkit.JsPromptResult;
|
31 | import android.webkit.WebChromeClient;
|
32 | import android.webkit.WebResourceRequest;
|
33 | import android.webkit.WebStorage;
|
34 | import android.webkit.WebView;
|
35 | import android.webkit.WebViewClient;
|
36 | import android.webkit.GeolocationPermissions.Callback;
|
37 |
|
38 | public class InAppChromeClient extends WebChromeClient {
|
39 |
|
40 | private CordovaWebView webView;
|
41 | private String LOG_TAG = "InAppChromeClient";
|
42 | private long MAX_QUOTA = 100 * 1024 * 1024;
|
43 |
|
44 | public InAppChromeClient(CordovaWebView webView) {
|
45 | super();
|
46 | this.webView = webView;
|
47 | }
|
48 | /**
|
49 | * Handle database quota exceeded notification.
|
50 | *
|
51 | * @param url
|
52 | * @param databaseIdentifier
|
53 | * @param currentQuota
|
54 | * @param estimatedSize
|
55 | * @param totalUsedQuota
|
56 | * @param quotaUpdater
|
57 | */
|
58 |
|
59 | public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
|
60 | long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
|
61 | {
|
62 | LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
63 | quotaUpdater.updateQuota(MAX_QUOTA);
|
64 | }
|
65 |
|
66 | /**
|
67 | * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
|
68 | *
|
69 | * @param origin
|
70 | * @param callback
|
71 | */
|
72 |
|
73 | public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
|
74 | super.onGeolocationPermissionsShowPrompt(origin, callback);
|
75 | callback.invoke(origin, true, false);
|
76 | }
|
77 |
|
78 | /**
|
79 | * Tell the client to display a prompt dialog to the user.
|
80 | * If the client returns true, WebView will assume that the client will
|
81 | * handle the prompt dialog and call the appropriate JsPromptResult method.
|
82 | *
|
83 | * The prompt bridge provided for the InAppBrowser is capable of executing any
|
84 | * oustanding callback belonging to the InAppBrowser plugin. Care has been
|
85 | * taken that other callbacks cannot be triggered, and that no other code
|
86 | * execution is possible.
|
87 | *
|
88 | * To trigger the bridge, the prompt default value should be of the form:
|
89 | *
|
90 | * gap-iab://<callbackId>
|
91 | *
|
92 | * where <callbackId> is the string id of the callback to trigger (something
|
93 | * like "InAppBrowser0123456789")
|
94 | *
|
95 | * If present, the prompt message is expected to be a JSON-encoded value to
|
96 | * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
|
97 | *
|
98 | * @param view
|
99 | * @param url
|
100 | * @param message
|
101 | * @param defaultValue
|
102 | * @param result
|
103 | */
|
104 |
|
105 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
106 | // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
|
107 | if (defaultValue != null && defaultValue.startsWith("gap")) {
|
108 | if(defaultValue.startsWith("gap-iab://")) {
|
109 | PluginResult scriptResult;
|
110 | String scriptCallbackId = defaultValue.substring(10);
|
111 | if (scriptCallbackId.matches("^InAppBrowser[0-9]{1,10}$")) {
|
112 | if(message == null || message.length() == 0) {
|
113 | scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
|
114 | } else {
|
115 | try {
|
116 | scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
|
117 | } catch(JSONException e) {
|
118 | scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
|
119 | }
|
120 | }
|
121 | this.webView.sendPluginResult(scriptResult, scriptCallbackId);
|
122 | result.confirm("");
|
123 | return true;
|
124 | }
|
125 | else {
|
126 | // Anything else that doesn't look like InAppBrowser0123456789 should end up here
|
127 | LOG.w(LOG_TAG, "InAppBrowser callback called with invalid callbackId : "+ scriptCallbackId);
|
128 | result.cancel();
|
129 | return true;
|
130 | }
|
131 | }
|
132 | else {
|
133 | // Anything else with a gap: prefix should get this message
|
134 | LOG.w(LOG_TAG, "InAppBrowser does not support Cordova API calls: " + url + " " + defaultValue);
|
135 | result.cancel();
|
136 | return true;
|
137 | }
|
138 | }
|
139 | return false;
|
140 | }
|
141 |
|
142 | /**
|
143 | * The InAppWebBrowser WebView is configured to MultipleWindow mode to mitigate a security
|
144 | * bug found in Chromium prior to version 83.0.4103.106.
|
145 | * See https://bugs.chromium.org/p/chromium/issues/detail?id=1083819
|
146 | *
|
147 | * Valid Urls set to open in new window will be routed back to load in the original WebView.
|
148 | *
|
149 | * @param view
|
150 | * @param isDialog
|
151 | * @param isUserGesture
|
152 | * @param resultMsg
|
153 | * @return
|
154 | */
|
155 |
|
156 | public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
|
157 | WebView inAppWebView = view;
|
158 | final WebViewClient webViewClient =
|
159 | new WebViewClient() {
|
160 | (Build.VERSION_CODES.LOLLIPOP)
|
161 |
|
162 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
163 | inAppWebView.loadUrl(request.getUrl().toString());
|
164 | return true;
|
165 | }
|
166 |
|
167 |
|
168 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
169 | inAppWebView.loadUrl(url);
|
170 | return true;
|
171 | }
|
172 | };
|
173 |
|
174 | final WebView newWebView = new WebView(view.getContext());
|
175 | newWebView.setWebViewClient(webViewClient);
|
176 |
|
177 | final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
|
178 | transport.setWebView(newWebView);
|
179 | resultMsg.sendToTarget();
|
180 |
|
181 | return true;
|
182 | }
|
183 | }
|