summaryrefslogtreecommitdiff
path: root/www/external/SystemWebViewClient.java
diff options
context:
space:
mode:
authorPliable Pixels <pliablepixels@gmail.com>2017-09-21 12:49:18 -0400
committerPliable Pixels <pliablepixels@gmail.com>2017-09-21 12:49:18 -0400
commitb28028ac4082842143b0f528d6bc539da6ccb419 (patch)
tree1e26ea969a781ed8e323fca4e3c76345113fc694 /www/external/SystemWebViewClient.java
parent676270d21beed31d767a06c89522198c77d5d865 (diff)
mega changes, including updates and X
Diffstat (limited to 'www/external/SystemWebViewClient.java')
-rwxr-xr-xwww/external/SystemWebViewClient.java378
1 files changed, 378 insertions, 0 deletions
diff --git a/www/external/SystemWebViewClient.java b/www/external/SystemWebViewClient.java
new file mode 100755
index 00000000..86b3f0ce
--- /dev/null
+++ b/www/external/SystemWebViewClient.java
@@ -0,0 +1,378 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+package org.apache.cordova.engine;
+
+import android.annotation.TargetApi;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.webkit.ClientCertRequest;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import org.apache.cordova.AuthenticationToken;
+import org.apache.cordova.CordovaClientCertRequest;
+import org.apache.cordova.CordovaHttpAuthHandler;
+import org.apache.cordova.CordovaResourceApi;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginManager;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Hashtable;
+
+
+/**
+ * This class is the WebViewClient that implements callbacks for our web view.
+ * The kind of callbacks that happen here are regarding the rendering of the
+ * document instead of the chrome surrounding it, such as onPageStarted(),
+ * shouldOverrideUrlLoading(), etc. Related to but different than
+ * CordovaChromeClient.
+ */
+public class SystemWebViewClient extends WebViewClient {
+
+ private static final String TAG = "SystemWebViewClient";
+ protected final SystemWebViewEngine parentEngine;
+ private boolean doClearHistory = false;
+ boolean isCurrentlyLoading;
+
+ /** The authorization tokens. */
+ private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
+
+ public SystemWebViewClient(SystemWebViewEngine parentEngine) {
+ this.parentEngine = parentEngine;
+ }
+
+ /**
+ * Give the host application a chance to take over the control when a new url
+ * is about to be loaded in the current WebView.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param url The url to be loaded.
+ * @return true to override, false for default behavior
+ */
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ return parentEngine.client.onNavigationAttempt(url);
+ }
+
+ /**
+ * On received http auth request.
+ * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
+ */
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
+
+ // Get the authentication token (if specified)
+ AuthenticationToken token = this.getAuthenticationToken(host, realm);
+ if (token != null) {
+ handler.proceed(token.getUserName(), token.getPassword());
+ return;
+ }
+
+ // Check if there is some plugin which can resolve this auth challenge
+ PluginManager pluginManager = this.parentEngine.pluginManager;
+ if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(null, new CordovaHttpAuthHandler(handler), host, realm)) {
+ parentEngine.client.clearLoadTimeoutTimer();
+ return;
+ }
+
+ // By default handle 401 like we'd normally do!
+ super.onReceivedHttpAuthRequest(view, handler, host, realm);
+ }
+
+ /**
+ * On received client cert request.
+ * The method forwards the request to any running plugins before using the default implementation.
+ *
+ * @param view
+ * @param request
+ */
+ @Override
+ @TargetApi(21)
+ public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
+ {
+
+ // Check if there is some plugin which can resolve this certificate request
+ PluginManager pluginManager = this.parentEngine.pluginManager;
+ if (pluginManager != null && pluginManager.onReceivedClientCertRequest(null, new CordovaClientCertRequest(request))) {
+ parentEngine.client.clearLoadTimeoutTimer();
+ return;
+ }
+
+ // By default pass to WebViewClient
+ super.onReceivedClientCertRequest(view, request);
+ }
+
+ /**
+ * Notify the host application that a page has started loading.
+ * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
+ * one time for the main frame. This also means that onPageStarted will not be called when the contents of an
+ * embedded frame changes, i.e. clicking a link whose target is an iframe.
+ *
+ * @param view The webview initiating the callback.
+ * @param url The url of the page.
+ */
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ isCurrentlyLoading = true;
+ // Flush stale messages & reset plugins.
+ parentEngine.bridge.reset();
+ parentEngine.client.onPageStarted(url);
+ }
+
+ /**
+ * Notify the host application that a page has finished loading.
+ * This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
+ *
+ *
+ * @param view The webview initiating the callback.
+ * @param url The url of the page.
+ */
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ // Ignore excessive calls, if url is not about:blank (CB-8317).
+ if (!isCurrentlyLoading && !url.startsWith("about:")) {
+ return;
+ }
+ isCurrentlyLoading = false;
+
+ /**
+ * Because of a timing issue we need to clear this history in onPageFinished as well as
+ * onPageStarted. However we only want to do this if the doClearHistory boolean is set to
+ * true. You see when you load a url with a # in it which is common in jQuery applications
+ * onPageStared is not called. Clearing the history at that point would break jQuery apps.
+ */
+ if (this.doClearHistory) {
+ view.clearHistory();
+ this.doClearHistory = false;
+ }
+ parentEngine.client.onPageFinishedLoading(url);
+
+ }
+
+ /**
+ * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
+ * The errorCode parameter corresponds to one of the ERROR_* constants.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param errorCode The error code corresponding to an ERROR_* value.
+ * @param description A String describing the error.
+ * @param failingUrl The url that failed to load.
+ */
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ // Ignore error due to stopLoading().
+ if (!isCurrentlyLoading) {
+ return;
+ }
+ LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
+
+ // If this is a "Protocol Not Supported" error, then revert to the previous
+ // page. If there was no previous page, then punt. The application's config
+ // is likely incorrect (start page set to sms: or something like that)
+ if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {
+ parentEngine.client.clearLoadTimeoutTimer();
+
+ if (view.canGoBack()) {
+ view.goBack();
+ return;
+ } else {
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+ }
+ parentEngine.client.onReceivedError(errorCode, description, failingUrl);
+ }
+
+ /**
+ * Notify the host application that an SSL error occurred while loading a resource.
+ * The host application must call either handler.cancel() or handler.proceed().
+ * Note that the decision may be retained for use in response to future SSL errors.
+ * The default behavior is to cancel the load.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param handler An SslErrorHandler object that will handle the user's response.
+ * @param error The SSL error object.
+ */
+ @TargetApi(8)
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+
+ final String packageName = parentEngine.cordova.getActivity().getPackageName();
+ final PackageManager pm = parentEngine.cordova.getActivity().getPackageManager();
+
+ ApplicationInfo appInfo;
+ try {
+ appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
+ if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ // debug = true
+ handler.proceed();
+ return;
+ } else {
+ // debug = false
+ // credit http://ivancevich.me/articles/ignoring-invalid-ssl-certificates-on-cordova-android-ios/
+
+ // super.onReceivedSslError(view, handler, error);
+ handler.proceed();
+ return;
+ }
+ } catch (NameNotFoundException e) {
+ // When it doubt, lock it out!
+ super.onReceivedSslError(view, handler, error);
+ }
+ }
+
+
+ /**
+ * Sets the authentication token.
+ *
+ * @param authenticationToken
+ * @param host
+ * @param realm
+ */
+ public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
+ if (host == null) {
+ host = "";
+ }
+ if (realm == null) {
+ realm = "";
+ }
+ this.authenticationTokens.put(host.concat(realm), authenticationToken);
+ }
+
+ /**
+ * Removes the authentication token.
+ *
+ * @param host
+ * @param realm
+ *
+ * @return the authentication token or null if did not exist
+ */
+ public AuthenticationToken removeAuthenticationToken(String host, String realm) {
+ return this.authenticationTokens.remove(host.concat(realm));
+ }
+
+ /**
+ * Gets the authentication token.
+ *
+ * In order it tries:
+ * 1- host + realm
+ * 2- host
+ * 3- realm
+ * 4- no host, no realm
+ *
+ * @param host
+ * @param realm
+ *
+ * @return the authentication token
+ */
+ public AuthenticationToken getAuthenticationToken(String host, String realm) {
+ AuthenticationToken token = null;
+ token = this.authenticationTokens.get(host.concat(realm));
+
+ if (token == null) {
+ // try with just the host
+ token = this.authenticationTokens.get(host);
+
+ // Try the realm
+ if (token == null) {
+ token = this.authenticationTokens.get(realm);
+ }
+
+ // if no host found, just query for default
+ if (token == null) {
+ token = this.authenticationTokens.get("");
+ }
+ }
+
+ return token;
+ }
+
+ /**
+ * Clear all authentication tokens.
+ */
+ public void clearAuthenticationTokens() {
+ this.authenticationTokens.clear();
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+ try {
+ // Check the against the whitelist and lock out access to the WebView directory
+ // Changing this will cause problems for your application
+ if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
+ LOG.w(TAG, "URL blocked by whitelist: " + url);
+ // Results in a 404.
+ return new WebResourceResponse("text/plain", "UTF-8", null);
+ }
+
+ CordovaResourceApi resourceApi = parentEngine.resourceApi;
+ Uri origUri = Uri.parse(url);
+ // Allow plugins to intercept WebView requests.
+ Uri remappedUri = resourceApi.remapUri(origUri);
+
+ if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {
+ CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
+ return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
+ }
+ // If we don't need to special-case the request, let the browser load it.
+ return null;
+ } catch (IOException e) {
+ if (!(e instanceof FileNotFoundException)) {
+ LOG.e(TAG, "Error occurred while loading a file (returning a 404).", e);
+ }
+ // Results in a 404.
+ return new WebResourceResponse("text/plain", "UTF-8", null);
+ }
+ }
+
+ private static boolean needsKitKatContentUrlFix(Uri uri) {
+ return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && "content".equals(uri.getScheme());
+ }
+
+ private static boolean needsSpecialsInAssetUrlFix(Uri uri) {
+ if (CordovaResourceApi.getUriType(uri) != CordovaResourceApi.URI_TYPE_ASSET) {
+ return false;
+ }
+ if (uri.getQuery() != null || uri.getFragment() != null) {
+ return true;
+ }
+
+ if (!uri.toString().contains("%")) {
+ return false;
+ }
+
+ switch(android.os.Build.VERSION.SDK_INT){
+ case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH:
+ case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1:
+ return true;
+ }
+ return false;
+ }
+}