| /* |
| 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; |
| |
| import java.util.HashMap; |
| import java.util.StringTokenizer; |
| |
| import org.apache.cordova.api.CallbackContext; |
| import org.apache.cordova.api.CordovaPlugin; |
| import org.apache.cordova.api.LOG; |
| import org.apache.cordova.api.PluginResult; |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import android.annotation.SuppressLint; |
| import android.app.Dialog; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.graphics.Bitmap; |
| import android.graphics.Color; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.text.InputType; |
| import android.util.Log; |
| import android.util.TypedValue; |
| import android.view.Gravity; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.view.Window; |
| import android.view.WindowManager; |
| import android.view.WindowManager.LayoutParams; |
| import android.view.inputmethod.EditorInfo; |
| import android.view.inputmethod.InputMethodManager; |
| import android.webkit.WebChromeClient; |
| import android.webkit.GeolocationPermissions.Callback; |
| import android.webkit.WebSettings; |
| import android.webkit.WebStorage; |
| import android.webkit.WebView; |
| import android.webkit.WebViewClient; |
| import android.widget.Button; |
| import android.widget.EditText; |
| import android.widget.LinearLayout; |
| import android.widget.RelativeLayout; |
| |
| @SuppressLint("SetJavaScriptEnabled") |
| public class InAppBrowser extends CordovaPlugin { |
| |
| private static final String NULL = "null"; |
| protected static final String LOG_TAG = "InAppBrowser"; |
| private static final String SELF = "_self"; |
| private static final String SYSTEM = "_system"; |
| // private static final String BLANK = "_blank"; |
| private static final String LOCATION = "location"; |
| private static final String EXIT_EVENT = "exit"; |
| private static final String LOAD_START_EVENT = "loadstart"; |
| private static final String LOAD_STOP_EVENT = "loadstop"; |
| private static final String LOAD_ERROR_EVENT = "loaderror"; |
| private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption"; |
| private long MAX_QUOTA = 100 * 1024 * 1024; |
| |
| private Dialog dialog; |
| private WebView inAppWebView; |
| private EditText edittext; |
| private boolean showLocationBar = true; |
| private CallbackContext callbackContext; |
| private String buttonLabel = "Done"; |
| |
| /** |
| * Executes the request and returns PluginResult. |
| * |
| * @param action The action to execute. |
| * @param args JSONArry of arguments for the plugin. |
| * @param callbackId The callback id used when calling back into JavaScript. |
| * @return A PluginResult object with a status and message. |
| */ |
| public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { |
| PluginResult.Status status = PluginResult.Status.OK; |
| String result = ""; |
| this.callbackContext = callbackContext; |
| |
| try { |
| if (action.equals("open")) { |
| String url = args.getString(0); |
| String target = args.optString(1); |
| if (target == null || target.equals("") || target.equals(NULL)) { |
| target = SELF; |
| } |
| HashMap<String, Boolean> features = parseFeature(args.optString(2)); |
| |
| Log.d(LOG_TAG, "target = " + target); |
| |
| url = updateUrl(url); |
| |
| // SELF |
| if (SELF.equals(target)) { |
| Log.d(LOG_TAG, "in self"); |
| // load in webview |
| if (url.startsWith("file://") || url.startsWith("javascript:") |
| || Config.isUrlWhiteListed(url)) { |
| this.webView.loadUrl(url); |
| } |
| //Load the dialer |
| else if (url.startsWith(WebView.SCHEME_TEL)) |
| { |
| try { |
| Intent intent = new Intent(Intent.ACTION_DIAL); |
| intent.setData(Uri.parse(url)); |
| this.cordova.getActivity().startActivity(intent); |
| } catch (android.content.ActivityNotFoundException e) { |
| LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); |
| } |
| } |
| // load in InAppBrowser |
| else { |
| result = this.showWebPage(url, features); |
| } |
| } |
| // SYSTEM |
| else if (SYSTEM.equals(target)) { |
| Log.d(LOG_TAG, "in system"); |
| result = this.openExternal(url); |
| } |
| // BLANK - or anything else |
| else { |
| Log.d(LOG_TAG, "in blank"); |
| result = this.showWebPage(url, features); |
| } |
| } |
| else if (action.equals("close")) { |
| closeDialog(); |
| |
| PluginResult pluginResult = new PluginResult(PluginResult.Status.OK); |
| pluginResult.setKeepCallback(false); |
| this.callbackContext.sendPluginResult(pluginResult); |
| } |
| else { |
| status = PluginResult.Status.INVALID_ACTION; |
| } |
| PluginResult pluginResult = new PluginResult(status, result); |
| pluginResult.setKeepCallback(true); |
| this.callbackContext.sendPluginResult(pluginResult); |
| } catch (JSONException e) { |
| this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); |
| } |
| return true; |
| } |
| |
| /** |
| * Put the list of features into a hash map |
| * |
| * @param optString |
| * @return |
| */ |
| private HashMap<String, Boolean> parseFeature(String optString) { |
| if (optString.equals(NULL)) { |
| return null; |
| } else { |
| HashMap<String, Boolean> map = new HashMap<String, Boolean>(); |
| StringTokenizer features = new StringTokenizer(optString, ","); |
| StringTokenizer option; |
| while(features.hasMoreElements()) { |
| option = new StringTokenizer(features.nextToken(), "="); |
| if (option.hasMoreElements()) { |
| String key = option.nextToken(); |
| if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) { |
| this.buttonLabel = option.nextToken(); |
| } else { |
| Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE; |
| map.put(key, value); |
| } |
| } |
| } |
| return map; |
| } |
| } |
| |
| /** |
| * Convert relative URL to full path |
| * |
| * @param url |
| * @return |
| */ |
| private String updateUrl(String url) { |
| Uri newUrl = Uri.parse(url); |
| if (newUrl.isRelative()) { |
| url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url; |
| } |
| return url; |
| } |
| |
| /** |
| * Display a new browser with the specified URL. |
| * |
| * @param url The url to load. |
| * @param usePhoneGap Load url in PhoneGap webview |
| * @return "" if ok, or error message. |
| */ |
| public String openExternal(String url) { |
| try { |
| Intent intent = null; |
| intent = new Intent(Intent.ACTION_VIEW); |
| intent.setData(Uri.parse(url)); |
| this.cordova.getActivity().startActivity(intent); |
| return ""; |
| } catch (android.content.ActivityNotFoundException e) { |
| Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString()); |
| return e.toString(); |
| } |
| } |
| |
| /** |
| * Closes the dialog |
| */ |
| private void closeDialog() { |
| try { |
| this.inAppWebView.loadUrl("about:blank"); |
| JSONObject obj = new JSONObject(); |
| obj.put("type", EXIT_EVENT); |
| |
| sendUpdate(obj, false); |
| } catch (JSONException ex) { |
| Log.d(LOG_TAG, "Should never happen"); |
| } |
| |
| if (dialog != null) { |
| dialog.dismiss(); |
| } |
| } |
| |
| /** |
| * Checks to see if it is possible to go back one page in history, then does so. |
| */ |
| private void goBack() { |
| if (this.inAppWebView.canGoBack()) { |
| this.inAppWebView.goBack(); |
| } |
| } |
| |
| /** |
| * Checks to see if it is possible to go forward one page in history, then does so. |
| */ |
| private void goForward() { |
| if (this.inAppWebView.canGoForward()) { |
| this.inAppWebView.goForward(); |
| } |
| } |
| |
| /** |
| * Navigate to the new page |
| * |
| * @param url to load |
| */ |
| private void navigate(String url) { |
| InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); |
| imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); |
| |
| if (!url.startsWith("http") && !url.startsWith("file:")) { |
| this.inAppWebView.loadUrl("http://" + url); |
| } else { |
| this.inAppWebView.loadUrl(url); |
| } |
| this.inAppWebView.requestFocus(); |
| } |
| |
| |
| /** |
| * Should we show the location bar? |
| * |
| * @return boolean |
| */ |
| private boolean getShowLocationBar() { |
| return this.showLocationBar; |
| } |
| |
| /** |
| * Display a new browser with the specified URL. |
| * |
| * @param url The url to load. |
| * @param jsonObject |
| */ |
| public String showWebPage(final String url, HashMap<String, Boolean> features) { |
| // Determine if we should hide the location bar. |
| showLocationBar = true; |
| if (features != null) { |
| Boolean show = features.get(LOCATION); |
| if (show != null) { |
| showLocationBar = show.booleanValue(); |
| } |
| } |
| |
| final CordovaWebView thatWebView = this.webView; |
| |
| // Create dialog in new thread |
| Runnable runnable = new Runnable() { |
| /** |
| * Convert our DIP units to Pixels |
| * |
| * @return int |
| */ |
| private int dpToPixels(int dipValue) { |
| int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, |
| (float) dipValue, |
| cordova.getActivity().getResources().getDisplayMetrics() |
| ); |
| |
| return value; |
| } |
| |
| public void run() { |
| // Let's create the main dialog |
| dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar); |
| dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog; |
| dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); |
| dialog.setCancelable(true); |
| dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
| public void onDismiss(DialogInterface dialog) { |
| try { |
| JSONObject obj = new JSONObject(); |
| obj.put("type", EXIT_EVENT); |
| |
| sendUpdate(obj, false); |
| } catch (JSONException e) { |
| Log.d(LOG_TAG, "Should never happen"); |
| } |
| } |
| }); |
| |
| // Main container layout |
| LinearLayout main = new LinearLayout(cordova.getActivity()); |
| main.setOrientation(LinearLayout.VERTICAL); |
| |
| // Toolbar layout |
| RelativeLayout toolbar = new RelativeLayout(cordova.getActivity()); |
| toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44))); |
| toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2)); |
| toolbar.setHorizontalGravity(Gravity.LEFT); |
| toolbar.setVerticalGravity(Gravity.TOP); |
| |
| // Action Button Container layout |
| RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity()); |
| actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); |
| actionButtonContainer.setHorizontalGravity(Gravity.LEFT); |
| actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL); |
| actionButtonContainer.setId(1); |
| |
| // Back button |
| Button back = new Button(cordova.getActivity()); |
| RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); |
| backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT); |
| back.setLayoutParams(backLayoutParams); |
| back.setContentDescription("Back Button"); |
| back.setId(2); |
| back.setText("<"); |
| back.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View v) { |
| goBack(); |
| } |
| }); |
| |
| // Forward button |
| Button forward = new Button(cordova.getActivity()); |
| RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); |
| forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2); |
| forward.setLayoutParams(forwardLayoutParams); |
| forward.setContentDescription("Forward Button"); |
| forward.setId(3); |
| forward.setText(">"); |
| forward.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View v) { |
| goForward(); |
| } |
| }); |
| |
| // Edit Text Box |
| edittext = new EditText(cordova.getActivity()); |
| RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); |
| textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1); |
| textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5); |
| edittext.setLayoutParams(textLayoutParams); |
| edittext.setId(4); |
| edittext.setSingleLine(true); |
| edittext.setText(url); |
| edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI); |
| edittext.setImeOptions(EditorInfo.IME_ACTION_GO); |
| edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE |
| edittext.setOnKeyListener(new View.OnKeyListener() { |
| public boolean onKey(View v, int keyCode, KeyEvent event) { |
| // If the event is a key-down event on the "enter" button |
| if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { |
| navigate(edittext.getText().toString()); |
| return true; |
| } |
| return false; |
| } |
| }); |
| |
| // Close button |
| Button close = new Button(cordova.getActivity()); |
| RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); |
| closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); |
| close.setLayoutParams(closeLayoutParams); |
| forward.setContentDescription("Close Button"); |
| close.setId(5); |
| close.setText(buttonLabel); |
| close.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View v) { |
| closeDialog(); |
| } |
| }); |
| |
| // WebView |
| inAppWebView = new WebView(cordova.getActivity()); |
| inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); |
| inAppWebView.setWebChromeClient(new InAppChromeClient()); |
| WebViewClient client = new InAppBrowserClient(thatWebView, edittext); |
| inAppWebView.setWebViewClient(client); |
| WebSettings settings = inAppWebView.getSettings(); |
| settings.setJavaScriptEnabled(true); |
| settings.setJavaScriptCanOpenWindowsAutomatically(true); |
| settings.setBuiltInZoomControls(true); |
| /** |
| * We need to be careful of this line as a future Android release may deprecate it out of existence. |
| * Can't replace it with the API 8 level call right now as our minimum SDK is 7 until May 2013 |
| */ |
| // @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON) |
| settings.setPluginsEnabled(true); |
| |
| //Toggle whether this is enabled or not! |
| Bundle appSettings = cordova.getActivity().getIntent().getExtras(); |
| boolean enableDatabase = appSettings.getBoolean("InAppBrowserStorageEnabled", true); |
| if(enableDatabase) |
| { |
| String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath(); |
| settings.setDatabasePath(databasePath); |
| settings.setDatabaseEnabled(true); |
| } |
| settings.setDomStorageEnabled(true); |
| |
| inAppWebView.loadUrl(url); |
| inAppWebView.setId(6); |
| inAppWebView.getSettings().setLoadWithOverviewMode(true); |
| inAppWebView.getSettings().setUseWideViewPort(true); |
| inAppWebView.requestFocus(); |
| inAppWebView.requestFocusFromTouch(); |
| |
| // Add the back and forward buttons to our action button container layout |
| actionButtonContainer.addView(back); |
| actionButtonContainer.addView(forward); |
| |
| // Add the views to our toolbar |
| toolbar.addView(actionButtonContainer); |
| toolbar.addView(edittext); |
| toolbar.addView(close); |
| |
| // Don't add the toolbar if its been disabled |
| if (getShowLocationBar()) { |
| // Add our toolbar to our main view/layout |
| main.addView(toolbar); |
| } |
| |
| // Add our webview to our main view/layout |
| main.addView(inAppWebView); |
| |
| WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); |
| lp.copyFrom(dialog.getWindow().getAttributes()); |
| lp.width = WindowManager.LayoutParams.MATCH_PARENT; |
| lp.height = WindowManager.LayoutParams.MATCH_PARENT; |
| |
| dialog.setContentView(main); |
| dialog.show(); |
| dialog.getWindow().setAttributes(lp); |
| } |
| }; |
| this.cordova.getActivity().runOnUiThread(runnable); |
| return ""; |
| } |
| |
| /** |
| * Create a new plugin success result and send it back to JavaScript |
| * |
| * @param obj a JSONObject contain event payload information |
| */ |
| private void sendUpdate(JSONObject obj, boolean keepCallback) { |
| sendUpdate(obj, keepCallback, PluginResult.Status.OK); |
| } |
| |
| /** |
| * Create a new plugin result and send it back to JavaScript |
| * |
| * @param obj a JSONObject contain event payload information |
| * @param status the status code to return to the JavaScript environment |
| */ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) { |
| PluginResult result = new PluginResult(status, obj); |
| result.setKeepCallback(keepCallback); |
| this.callbackContext.sendPluginResult(result); |
| } |
| public class InAppChromeClient extends WebChromeClient { |
| |
| /** |
| * Handle database quota exceeded notification. |
| * |
| * @param url |
| * @param databaseIdentifier |
| * @param currentQuota |
| * @param estimatedSize |
| * @param totalUsedQuota |
| * @param quotaUpdater |
| */ |
| @Override |
| public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, |
| long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) |
| { |
| LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); |
| |
| if (estimatedSize < MAX_QUOTA) |
| { |
| //increase for 1Mb |
| long newQuota = estimatedSize; |
| LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota); |
| quotaUpdater.updateQuota(newQuota); |
| } |
| else |
| { |
| // Set the quota to whatever it is and force an error |
| // TODO: get docs on how to handle this properly |
| quotaUpdater.updateQuota(currentQuota); |
| } |
| } |
| |
| /** |
| * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. |
| * |
| * @param origin |
| * @param callback |
| */ |
| @Override |
| public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { |
| super.onGeolocationPermissionsShowPrompt(origin, callback); |
| callback.invoke(origin, true, false); |
| } |
| } |
| |
| /** |
| * The webview client receives notifications about appView |
| */ |
| public class InAppBrowserClient extends WebViewClient { |
| EditText edittext; |
| CordovaWebView webView; |
| |
| /** |
| * Constructor. |
| * |
| * @param mContext |
| * @param edittext |
| */ |
| public InAppBrowserClient(CordovaWebView webView, EditText mEditText) { |
| this.webView = webView; |
| this.edittext = mEditText; |
| } |
| |
| /** |
| * Notify the host application that a page has started loading. |
| * |
| * @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); |
| String newloc = ""; |
| if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) { |
| newloc = url; |
| } |
| // If dialing phone (tel:5551212) |
| else if (url.startsWith(WebView.SCHEME_TEL)) { |
| try { |
| Intent intent = new Intent(Intent.ACTION_DIAL); |
| intent.setData(Uri.parse(url)); |
| cordova.getActivity().startActivity(intent); |
| } catch (android.content.ActivityNotFoundException e) { |
| LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); |
| } |
| } |
| |
| else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) { |
| try { |
| Intent intent = new Intent(Intent.ACTION_VIEW); |
| intent.setData(Uri.parse(url)); |
| cordova.getActivity().startActivity(intent); |
| } catch (android.content.ActivityNotFoundException e) { |
| LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString()); |
| } |
| } |
| // If sms:5551212?body=This is the message |
| else if (url.startsWith("sms:")) { |
| try { |
| Intent intent = new Intent(Intent.ACTION_VIEW); |
| |
| // Get address |
| String address = null; |
| int parmIndex = url.indexOf('?'); |
| if (parmIndex == -1) { |
| address = url.substring(4); |
| } |
| else { |
| address = url.substring(4, parmIndex); |
| |
| // If body, then set sms body |
| Uri uri = Uri.parse(url); |
| String query = uri.getQuery(); |
| if (query != null) { |
| if (query.startsWith("body=")) { |
| intent.putExtra("sms_body", query.substring(5)); |
| } |
| } |
| } |
| intent.setData(Uri.parse("sms:" + address)); |
| intent.putExtra("address", address); |
| intent.setType("vnd.android-dir/mms-sms"); |
| cordova.getActivity().startActivity(intent); |
| } catch (android.content.ActivityNotFoundException e) { |
| LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString()); |
| } |
| } |
| else { |
| newloc = "http://" + url; |
| } |
| |
| if (!newloc.equals(edittext.getText().toString())) { |
| edittext.setText(newloc); |
| } |
| |
| try { |
| JSONObject obj = new JSONObject(); |
| obj.put("type", LOAD_START_EVENT); |
| obj.put("url", newloc); |
| |
| sendUpdate(obj, true); |
| } catch (JSONException ex) { |
| Log.d(LOG_TAG, "Should never happen"); |
| } |
| } |
| |
| public void onPageFinished(WebView view, String url) { |
| super.onPageFinished(view, url); |
| |
| try { |
| JSONObject obj = new JSONObject(); |
| obj.put("type", LOAD_STOP_EVENT); |
| obj.put("url", url); |
| |
| sendUpdate(obj, true); |
| } catch (JSONException ex) { |
| Log.d(LOG_TAG, "Should never happen"); |
| } |
| } |
| |
| public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { |
| super.onReceivedError(view, errorCode, description, failingUrl); |
| |
| try { |
| JSONObject obj = new JSONObject(); |
| obj.put("type", LOAD_ERROR_EVENT); |
| obj.put("url", failingUrl); |
| obj.put("code", errorCode); |
| obj.put("message", description); |
| |
| sendUpdate(obj, true, PluginResult.Status.ERROR); |
| } catch (JSONException ex) { |
| Log.d(LOG_TAG, "Should never happen"); |
| } |
| |
| } |
| } |
| } |