diff options
| author | ARC <arjunrc@gmail.com> | 2015-05-13 14:58:25 -0400 |
|---|---|---|
| committer | ARC <arjunrc@gmail.com> | 2015-05-13 14:58:25 -0400 |
| commit | 73968ba1b3c3b5efeb92f70969e40d143eebf3d8 (patch) | |
| tree | 25f9d358356645c89c212f014f622d5c831e81d0 /plugins/cordova-plugin-crosswalk-webview/src/android | |
| parent | 1bef6ad92cafa215e3927d0a4d0a29147d52fe56 (diff) | |
Added plugin directory as well to make sure you have all you need to compile (hopefully)
Diffstat (limited to 'plugins/cordova-plugin-crosswalk-webview/src/android')
6 files changed, 822 insertions, 0 deletions
diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaCookieManager.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaCookieManager.java new file mode 100644 index 00000000..43f170d2 --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaCookieManager.java @@ -0,0 +1,53 @@ +/* + 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.crosswalk.engine; + +import org.apache.cordova.ICordovaCookieManager; +import org.xwalk.core.internal.XWalkCookieManager; + +class XWalkCordovaCookieManager implements ICordovaCookieManager { + + protected XWalkCookieManager cookieManager = null; + + public XWalkCordovaCookieManager() { + cookieManager = new XWalkCookieManager(); + } + + public void setCookiesEnabled(boolean accept) { + cookieManager.setAcceptCookie(accept); + } + + public void setCookie(final String url, final String value) { + cookieManager.setCookie(url, value); + } + + public String getCookie(final String url) { + return cookieManager.getCookie(url); + } + + public void clearCookies() { + cookieManager.removeAllCookie(); + } + + public void flush() { + cookieManager.flushCookieStore(); + } +}; + + diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaResourceClient.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaResourceClient.java new file mode 100644 index 00000000..57d0b0f9 --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaResourceClient.java @@ -0,0 +1,231 @@ +/* + 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.crosswalk.engine; + +import android.net.Uri; +import android.webkit.WebResourceResponse; + +import org.apache.cordova.CordovaResourceApi; +import org.apache.cordova.CordovaResourceApi.OpenForReadResult; +import org.apache.cordova.LOG; +import org.chromium.net.NetError; +import org.xwalk.core.XWalkResourceClient; +import org.xwalk.core.XWalkView; + +import java.io.FileNotFoundException; +import java.io.IOException; + +public class XWalkCordovaResourceClient extends XWalkResourceClient { + + private static final String TAG = "XWalkCordovaResourceClient"; + protected XWalkWebViewEngine parentEngine; + + // Success + public static final int ERROR_OK = 0; + // Generic error + public static final int ERROR_UNKNOWN = -1; + // Server or proxy hostname lookup failed + public static final int ERROR_HOST_LOOKUP = -2; + // Unsupported authentication scheme (not basic or digest) + public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3; + // User authentication failed on server + public static final int ERROR_AUTHENTICATION = -4; + // User authentication failed on proxy + public static final int ERROR_PROXY_AUTHENTICATION = -5; + // Failed to connect to the server + public static final int ERROR_CONNECT = -6; + // Failed to read or write to the server + public static final int ERROR_IO = -7; + // Connection timed out + public static final int ERROR_TIMEOUT = -8; + // Too many redirects + public static final int ERROR_REDIRECT_LOOP = -9; + // Unsupported URI scheme + public static final int ERROR_UNSUPPORTED_SCHEME = -10; + // Failed to perform SSL handshake + public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; + // Malformed URL + public static final int ERROR_BAD_URL = -12; + // Generic file error + public static final int ERROR_FILE = -13; + // File not found + public static final int ERROR_FILE_NOT_FOUND = -14; + // Too many requests during this load + public static final int ERROR_TOO_MANY_REQUESTS = -15; + + public XWalkCordovaResourceClient(XWalkWebViewEngine parentEngine) { + super(parentEngine.webView); + this.parentEngine = parentEngine; + } + + // Map XWalk error code about loading a page to Android specific ones. + // XWalk shares the error code with chromium currently. + static int convertErrorCode(int netError) { + // Note: many NetError.Error constants don't have an obvious mapping. + // These will be handled by the default case, ERROR_UNKNOWN. + switch (netError) { + case NetError.ERR_UNSUPPORTED_AUTH_SCHEME: + return ERROR_UNSUPPORTED_AUTH_SCHEME; + + case NetError.ERR_INVALID_AUTH_CREDENTIALS: + case NetError.ERR_MISSING_AUTH_CREDENTIALS: + case NetError.ERR_MISCONFIGURED_AUTH_ENVIRONMENT: + return ERROR_AUTHENTICATION; + + case NetError.ERR_TOO_MANY_REDIRECTS: + return ERROR_REDIRECT_LOOP; + + case NetError.ERR_UPLOAD_FILE_CHANGED: + return ERROR_FILE_NOT_FOUND; + + case NetError.ERR_INVALID_URL: + return ERROR_BAD_URL; + + case NetError.ERR_DISALLOWED_URL_SCHEME: + case NetError.ERR_UNKNOWN_URL_SCHEME: + return ERROR_UNSUPPORTED_SCHEME; + + case NetError.ERR_IO_PENDING: + case NetError.ERR_NETWORK_IO_SUSPENDED: + return ERROR_IO; + + case NetError.ERR_CONNECTION_TIMED_OUT: + case NetError.ERR_TIMED_OUT: + return ERROR_TIMEOUT; + + case NetError.ERR_FILE_TOO_BIG: + return ERROR_FILE; + + case NetError.ERR_HOST_RESOLVER_QUEUE_TOO_LARGE: + case NetError.ERR_INSUFFICIENT_RESOURCES: + case NetError.ERR_OUT_OF_MEMORY: + return ERROR_TOO_MANY_REQUESTS; + + case NetError.ERR_CONNECTION_CLOSED: + case NetError.ERR_CONNECTION_RESET: + case NetError.ERR_CONNECTION_REFUSED: + case NetError.ERR_CONNECTION_ABORTED: + case NetError.ERR_CONNECTION_FAILED: + case NetError.ERR_SOCKET_NOT_CONNECTED: + return ERROR_CONNECT; + + case NetError.ERR_INTERNET_DISCONNECTED: + case NetError.ERR_ADDRESS_INVALID: + case NetError.ERR_ADDRESS_UNREACHABLE: + case NetError.ERR_NAME_NOT_RESOLVED: + case NetError.ERR_NAME_RESOLUTION_FAILED: + return ERROR_HOST_LOOKUP; + + case NetError.ERR_SSL_PROTOCOL_ERROR: + case NetError.ERR_SSL_CLIENT_AUTH_CERT_NEEDED: + case NetError.ERR_TUNNEL_CONNECTION_FAILED: + case NetError.ERR_NO_SSL_VERSIONS_ENABLED: + case NetError.ERR_SSL_VERSION_OR_CIPHER_MISMATCH: + case NetError.ERR_SSL_RENEGOTIATION_REQUESTED: + case NetError.ERR_CERT_ERROR_IN_SSL_RENEGOTIATION: + case NetError.ERR_BAD_SSL_CLIENT_AUTH_CERT: + case NetError.ERR_SSL_NO_RENEGOTIATION: + case NetError.ERR_SSL_DECOMPRESSION_FAILURE_ALERT: + case NetError.ERR_SSL_BAD_RECORD_MAC_ALERT: + case NetError.ERR_SSL_UNSAFE_NEGOTIATION: + case NetError.ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: + case NetError.ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED: + case NetError.ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY: + return ERROR_FAILED_SSL_HANDSHAKE; + + case NetError.ERR_PROXY_AUTH_UNSUPPORTED: + case NetError.ERR_PROXY_AUTH_REQUESTED: + case NetError.ERR_PROXY_CONNECTION_FAILED: + case NetError.ERR_UNEXPECTED_PROXY_AUTH: + return ERROR_PROXY_AUTHENTICATION; + + // The certificate errors are handled by onReceivedSslError + // and don't need to be reported here. + case NetError.ERR_CERT_COMMON_NAME_INVALID: + case NetError.ERR_CERT_DATE_INVALID: + case NetError.ERR_CERT_AUTHORITY_INVALID: + case NetError.ERR_CERT_CONTAINS_ERRORS: + case NetError.ERR_CERT_NO_REVOCATION_MECHANISM: + case NetError.ERR_CERT_UNABLE_TO_CHECK_REVOCATION: + case NetError.ERR_CERT_REVOKED: + case NetError.ERR_CERT_INVALID: + case NetError.ERR_CERT_WEAK_SIGNATURE_ALGORITHM: + case NetError.ERR_CERT_NON_UNIQUE_NAME: + return ERROR_OK; + + default: + return ERROR_UNKNOWN; + } + } + + /** + * 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 onReceivedLoadError(XWalkView view, int errorCode, String description, + String failingUrl) { + LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl); + + // Convert the XWalk error code to Cordova error code, which follows the Android spec, + // http://developer.android.com/reference/android/webkit/WebViewClient.html. + errorCode = XWalkCordovaResourceClient.convertErrorCode(errorCode); + parentEngine.client.onReceivedError(errorCode, description, failingUrl); + } + + @Override + public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) { + try { + // Check the against the white-list. + 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)) { + 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); + } + } + + @Override + public boolean shouldOverrideUrlLoading(XWalkView view, String url) { + return parentEngine.client.onNavigationAttempt(url); + } +} diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaUiClient.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaUiClient.java new file mode 100644 index 00000000..a5a20b70 --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaUiClient.java @@ -0,0 +1,193 @@ +/* + 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.crosswalk.engine; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.net.Uri; +import android.util.Log; +import android.webkit.ValueCallback; + +import org.apache.cordova.CordovaDialogsHelper; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.LOG; +import org.xwalk.core.XWalkJavascriptResult; +import org.xwalk.core.XWalkUIClient; +import org.xwalk.core.XWalkView; + +public class XWalkCordovaUiClient extends XWalkUIClient { + private static final String TAG = "XWalkCordovaUiClient"; + protected final CordovaDialogsHelper dialogsHelper; + protected final XWalkWebViewEngine parentEngine; + + private static final int FILECHOOSER_RESULTCODE = 5173; + + public XWalkCordovaUiClient(XWalkWebViewEngine parentEngine) { + super(parentEngine.webView); + this.parentEngine = parentEngine; + dialogsHelper = new CordovaDialogsHelper(parentEngine.webView.getContext()); + } + + @Override + public boolean onJavascriptModalDialog(XWalkView view, JavascriptMessageType type, String url, + String message, String defaultValue, XWalkJavascriptResult result) { + switch (type) { + case JAVASCRIPT_ALERT: + return onJsAlert(view, url, message, result); + case JAVASCRIPT_CONFIRM: + return onJsConfirm(view, url, message, result); + case JAVASCRIPT_PROMPT: + return onJsPrompt(view, url, message, defaultValue, result); + case JAVASCRIPT_BEFOREUNLOAD: + // Reuse onJsConfirm to show the dialog. + return onJsConfirm(view, url, message, result); + default: + break; + } + assert (false); + return false; + } + + /** + * Tell the client to display a javascript alert dialog. + */ + private boolean onJsAlert(XWalkView view, String url, String message, + final XWalkJavascriptResult result) { + dialogsHelper.showAlert(message, new CordovaDialogsHelper.Result() { + @Override + public void gotResult(boolean success, String value) { + if (success) { + result.confirm(); + } else { + result.cancel(); + } + } + }); + return true; + } + + /** + * Tell the client to display a confirm dialog to the user. + */ + private boolean onJsConfirm(XWalkView view, String url, String message, + final XWalkJavascriptResult result) { + dialogsHelper.showConfirm(message, new CordovaDialogsHelper.Result() { + @Override + public void gotResult(boolean success, String value) { + if (success) { + result.confirm(); + } else { + result.cancel(); + } + } + }); + return true; + } + + /** + * Tell the client to display a prompt dialog to the user. + * If the client returns true, WebView will assume that the client will + * handle the prompt dialog and call the appropriate JsPromptResult method. + * <p/> + * Since we are hacking prompts for our own purposes, we should not be using them for + * this purpose, perhaps we should hack console.log to do this instead! + */ + private boolean onJsPrompt(XWalkView view, String origin, String message, String defaultValue, + final XWalkJavascriptResult result) { + // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread. + String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue); + if (handledRet != null) { + result.confirmWithResult(handledRet); + } else { + dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() { + @Override + public void gotResult(boolean success, String value) { + if (success) { + result.confirmWithResult(value); + } else { + result.cancel(); + } + } + }); + + } + return true; + } + + /** + * 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 onPageLoadStarted(XWalkView view, String url) { + + // Only proceed if this is a top-level navigation + if (view.getUrl() != null && view.getUrl().equals(url)) { + // Flush stale messages. + parentEngine.client.onPageStarted(url); + parentEngine.bridge.reset(); + } + } + + /** + * Notify the host application that a page has stopped loading. + * This method is called only for main frame. When onPageLoadStopped() is called, the rendering picture may not be updated yet. + * + * @param view The webView initiating the callback. + * @param url The url of the page. + * @param status The load status of the webView, can be FINISHED, CANCELLED or FAILED. + */ + @Override + public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) { + LOG.d(TAG, "onPageFinished(" + url + ")"); + if (status == LoadStatus.FINISHED) { + parentEngine.client.onPageFinishedLoading(url); + } else if (status == LoadStatus.FAILED) { + // TODO: Should this call parentEngine.client.onReceivedError()? + // Right now we call this from ResourceClient, but maybe that is just for sub-resources? + } + } + + // File Chooser + @Override + public void openFileChooser(XWalkView view, final ValueCallback<Uri> uploadFile, String acceptType, String capture) { + Intent i = new Intent(Intent.ACTION_GET_CONTENT); + i.addCategory(Intent.CATEGORY_OPENABLE); + i.setType("*/*"); // TODO: wire this to acceptType. + Intent intent = Intent.createChooser(i, "File Browser"); + try { + parentEngine.cordova.startActivityForResult(new CordovaPlugin() { + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); + uploadFile.onReceiveValue(result); + } + }, intent, FILECHOOSER_RESULTCODE); + } catch (ActivityNotFoundException e) { + Log.w("No activity found to handle file chooser intent.", e); + uploadFile.onReceiveValue(null); + } + } +} diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaView.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaView.java new file mode 100644 index 00000000..0be2e998 --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkCordovaView.java @@ -0,0 +1,108 @@ +package org.crosswalk.engine; + +import org.apache.cordova.CordovaPreferences; +import org.xwalk.core.XWalkPreferences; +import org.xwalk.core.XWalkResourceClient; +import org.xwalk.core.XWalkUIClient; +import org.xwalk.core.XWalkView; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.util.AttributeSet; +import android.view.KeyEvent; + +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.CordovaWebViewEngine; + +public class XWalkCordovaView extends XWalkView implements CordovaWebViewEngine.EngineView { + protected XWalkCordovaResourceClient resourceClient; + protected XWalkCordovaUiClient uiClient; + protected XWalkWebViewEngine parentEngine; + + private static boolean hasSetStaticPref; + // This needs to run before the super's constructor. + private static Context setGlobalPrefs(Context context, CordovaPreferences preferences) { + if (!hasSetStaticPref) { + hasSetStaticPref = true; + ApplicationInfo ai = null; + try { + ai = context.getPackageManager().getApplicationInfo(context.getApplicationContext().getPackageName(), PackageManager.GET_META_DATA); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException(e); + } + boolean prefAnimatable = preferences == null ? false : preferences.getBoolean("CrosswalkAnimatable", false); + boolean manifestAnimatable = ai.metaData == null ? false : ai.metaData.getBoolean("CrosswalkAnimatable"); + if (prefAnimatable || manifestAnimatable) { + // Slows it down a bit, but allows for it to be animated by Android View properties. + XWalkPreferences.setValue(XWalkPreferences.ANIMATABLE_XWALK_VIEW, true); + } + if ((ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true); + } + XWalkPreferences.setValue(XWalkPreferences.JAVASCRIPT_CAN_OPEN_WINDOW, true); + XWalkPreferences.setValue(XWalkPreferences.ALLOW_UNIVERSAL_ACCESS_FROM_FILE, true); + } + return context; + } + + public XWalkCordovaView(Context context, CordovaPreferences preferences) { + super(setGlobalPrefs(context, preferences), (AttributeSet)null); + } + + public XWalkCordovaView(Context context, AttributeSet attrs) { + super(setGlobalPrefs(context, null), attrs); + } + + void init(XWalkWebViewEngine parentEngine) { + this.parentEngine = parentEngine; + if (resourceClient == null) { + setResourceClient(new XWalkCordovaResourceClient(parentEngine)); + } + if (uiClient == null) { + setUIClient(new XWalkCordovaUiClient(parentEngine)); + } + } + + @Override + public void setResourceClient(XWalkResourceClient client) { + // XWalk calls this method from its constructor. + if (client instanceof XWalkCordovaResourceClient) { + this.resourceClient = (XWalkCordovaResourceClient)client; + } + super.setResourceClient(client); + } + + @Override + public void setUIClient(XWalkUIClient client) { + // XWalk calls this method from its constructor. + if (client instanceof XWalkCordovaUiClient) { + this.uiClient = (XWalkCordovaUiClient)client; + } + super.setUIClient(client); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + Boolean ret = parentEngine.client.onDispatchKeyEvent(event); + if (ret != null) { + return ret.booleanValue(); + } + return super.dispatchKeyEvent(event); + } + + @Override + public void pauseTimers() { + // This is called by XWalkViewInternal.onActivityStateChange(). + // We don't want them paused by default though. + } + + public void pauseTimersForReal() { + super.pauseTimers(); + } + + @Override + public CordovaWebView getCordovaWebView() { + return parentEngine == null ? null : parentEngine.getCordovaWebView(); + } +} diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkExposedJsApi.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkExposedJsApi.java new file mode 100644 index 00000000..25715216 --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkExposedJsApi.java @@ -0,0 +1,52 @@ +/* + 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.crosswalk.engine; + +import android.os.Looper; + +import org.apache.cordova.CordovaBridge; +import org.apache.cordova.ExposedJsApi; +import org.json.JSONException; +import org.xwalk.core.JavascriptInterface; + +class XWalkExposedJsApi implements ExposedJsApi { + private final CordovaBridge bridge; + + XWalkExposedJsApi(CordovaBridge bridge) { + this.bridge = bridge; + } + + @JavascriptInterface + public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments); + } + + @JavascriptInterface + public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException { + bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value); + } + + @JavascriptInterface + public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException { + return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent); + } +} diff --git a/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkWebViewEngine.java b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkWebViewEngine.java new file mode 100644 index 00000000..7e5a4f1c --- /dev/null +++ b/plugins/cordova-plugin-crosswalk-webview/src/android/XWalkWebViewEngine.java @@ -0,0 +1,185 @@ +/* + 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.crosswalk.engine; + +import android.content.Context; +import android.view.View; + +import org.apache.cordova.CordovaBridge; +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPreferences; +import org.apache.cordova.CordovaResourceApi; +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.CordovaWebViewEngine; +import org.apache.cordova.ICordovaCookieManager; +import org.apache.cordova.NativeToJsMessageQueue; +import org.apache.cordova.PluginManager; +import org.xwalk.core.XWalkNavigationHistory; +import org.xwalk.core.XWalkView; + +/** + * Glue class between CordovaWebView (main Cordova logic) and XWalkCordovaView (the actual View). + */ +public class XWalkWebViewEngine implements CordovaWebViewEngine { + + public static final String TAG = "XWalkWebViewEngine"; + + protected final XWalkCordovaView webView; + protected XWalkCordovaCookieManager cookieManager; + protected CordovaBridge bridge; + protected CordovaWebViewEngine.Client client; + protected CordovaWebView parentWebView; + protected CordovaInterface cordova; + protected PluginManager pluginManager; + protected CordovaResourceApi resourceApi; + protected NativeToJsMessageQueue nativeToJsMessageQueue; + + /** Used when created via reflection. */ + public XWalkWebViewEngine(Context context, CordovaPreferences preferences) { + this(new XWalkCordovaView(context, preferences)); + } + + public XWalkWebViewEngine(XWalkCordovaView webView) { + this.webView = webView; + cookieManager = new XWalkCordovaCookieManager(); + } + + // Use two-phase init so that the control will work with XML layouts. + + @Override + public void init(CordovaWebView parentWebView, CordovaInterface cordova, CordovaWebViewEngine.Client client, + CordovaResourceApi resourceApi, PluginManager pluginManager, + NativeToJsMessageQueue nativeToJsMessageQueue) { + if (this.cordova != null) { + throw new IllegalStateException(); + } + this.parentWebView = parentWebView; + this.cordova = cordova; + this.client = client; + this.resourceApi = resourceApi; + this.pluginManager = pluginManager; + this.nativeToJsMessageQueue = nativeToJsMessageQueue; + + webView.init(this); + initWebViewSettings(); + + nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() { + @Override + public void setNetworkAvailable(boolean value) { + webView.setNetworkAvailable(value); + } + @Override + public void runOnUiThread(Runnable r) { + XWalkWebViewEngine.this.cordova.getActivity().runOnUiThread(r); + } + })); + bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue); + exposeJsInterface(webView, bridge); + } + + @Override + public CordovaWebView getCordovaWebView() { + return parentWebView; + } + + @Override + public View getView() { + return webView; + } + + private void initWebViewSettings() { + webView.setVerticalScrollBarEnabled(false); + } + + private static void exposeJsInterface(XWalkView webView, CordovaBridge bridge) { + XWalkExposedJsApi exposedJsApi = new XWalkExposedJsApi(bridge); + webView.addJavascriptInterface(exposedJsApi, "_cordovaNative"); + } + + // TODO(ningxin): XWalkViewUIClient should provide onScrollChanged callback + /* + public void onScrollChanged(int l, int t, int oldl, int oldt) + { + super.onScrollChanged(l, t, oldl, oldt); + //We should post a message that the scroll changed + ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this); + this.postMessage("onScrollChanged", myEvent); + } + */ + + @Override + public boolean canGoBack() { + return this.webView.getNavigationHistory().canGoBack(); + } + + @Override + public boolean goBack() { + if (this.webView.getNavigationHistory().canGoBack()) { + this.webView.getNavigationHistory().navigate(XWalkNavigationHistory.Direction.BACKWARD, 1); + return true; + } + return false; + } + + @Override + public void setPaused(boolean value) { + if (value) { + // TODO: I think this has been fixed upstream and we don't need to override pauseTimers() anymore. + webView.pauseTimersForReal(); + } else { + webView.resumeTimers(); + } + } + + @Override + public void destroy() { + webView.onDestroy(); + } + + @Override + public void clearHistory() { + this.webView.getNavigationHistory().clear(); + } + + @Override + public void stopLoading() { + this.webView.stopLoading(); + } + + @Override + public void clearCache() { + webView.clearCache(true); + } + + @Override + public String getUrl() { + return this.webView.getUrl(); + } + + @Override + public ICordovaCookieManager getCookieManager() { + return cookieManager; + } + + @Override + public void loadUrl(String url, boolean clearNavigationStack) { + webView.load(url, null); + } +} |
