diff --git a/src/android/InAppBrowser.java b/src/android/InAppBrowser.java index b3e0e6126..588959c8f 100644 --- a/src/android/InAppBrowser.java +++ b/src/android/InAppBrowser.java @@ -18,14 +18,13 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.cordova.inappbrowser; +import android.Manifest; import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.ComponentName; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Parcelable; +import android.os.Environment; import android.provider.Browser; import android.content.res.Resources; import android.graphics.Bitmap; @@ -33,11 +32,12 @@ Licensed to the Apache Software Foundation (ASF) under one import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Color; -import android.net.http.SslError; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.provider.MediaStore; import android.text.InputType; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; @@ -50,12 +50,8 @@ Licensed to the Apache Software Foundation (ASF) under one import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.HttpAuthHandler; -import android.webkit.JavascriptInterface; -import android.webkit.SslErrorHandler; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -65,6 +61,7 @@ Licensed to the Apache Software Foundation (ASF) under one import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; +import android.content.ContentValues; import org.apache.cordova.CallbackContext; import org.apache.cordova.Config; @@ -78,14 +75,18 @@ Licensed to the Apache Software Foundation (ASF) under one import org.json.JSONException; import org.json.JSONObject; +import java.io.File; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.ArrayList; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.HashMap; import java.util.StringTokenizer; +import java.util.Locale;; @SuppressLint("SetJavaScriptEnabled") public class InAppBrowser extends CordovaPlugin { @@ -101,7 +102,6 @@ public class InAppBrowser extends CordovaPlugin { 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 MESSAGE_EVENT = "message"; private static final String CLEAR_ALL_CACHE = "clearcache"; private static final String CLEAR_SESSION_CACHE = "clearsessioncache"; private static final String HARDWARE_BACK_BUTTON = "hardwareback"; @@ -112,14 +112,11 @@ public class InAppBrowser extends CordovaPlugin { private static final String TOOLBAR_COLOR = "toolbarcolor"; private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption"; private static final String CLOSE_BUTTON_COLOR = "closebuttoncolor"; - private static final String LEFT_TO_RIGHT = "lefttoright"; private static final String HIDE_NAVIGATION = "hidenavigationbuttons"; private static final String NAVIGATION_COLOR = "navigationbuttoncolor"; private static final String HIDE_URL = "hideurlbar"; private static final String FOOTER = "footer"; private static final String FOOTER_COLOR = "footercolor"; - private static final String BEFORELOAD = "beforeload"; - private static final String FULLSCREEN = "fullscreen"; private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR); @@ -142,17 +139,17 @@ public class InAppBrowser extends CordovaPlugin { private final static int FILECHOOSER_REQUESTCODE_LOLLIPOP = 2; private String closeButtonCaption = ""; private String closeButtonColor = ""; - private boolean leftToRight = false; private int toolbarColor = android.graphics.Color.LTGRAY; private boolean hideNavigationButtons = false; private String navigationButtonColor = ""; private boolean hideUrlBar = false; private boolean showFooter = false; private String footerColor = ""; - private String beforeload = ""; - private boolean fullscreen = true; private String[] allowedSchemes; - private InAppBrowserClient currentClient; + + private String mCM; + private boolean isAndroidQ = Build.VERSION.SDK_INT >= 29; + private Uri mCameraUri; /** * Executes the request and returns PluginResult. @@ -260,25 +257,6 @@ else if (SYSTEM.equals(target)) { else if (action.equals("close")) { closeDialog(); } - else if (action.equals("loadAfterBeforeload")) { - if (beforeload == null) { - LOG.e(LOG_TAG, "unexpected loadAfterBeforeload called without feature beforeload=yes"); - } - final String url = args.getString(0); - this.cordova.getActivity().runOnUiThread(new Runnable() { - @SuppressLint("NewApi") - @Override - public void run() { - if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) { - currentClient.waitForBeforeload = false; - inAppWebView.setWebViewClient(currentClient); - } else { - ((InAppBrowserClient)inAppWebView.getWebViewClient()).waitForBeforeload = false; - } - inAppWebView.loadUrl(url); - } - }); - } else if (action.equals("injectScriptCode")) { String jsWrapper = null; if (args.getBoolean(1)) { @@ -317,9 +295,7 @@ else if (action.equals("show")) { this.cordova.getActivity().runOnUiThread(new Runnable() { @Override public void run() { - if (dialog != null && !cordova.getActivity().isFinishing()) { - dialog.show(); - } + dialog.show(); } }); PluginResult pluginResult = new PluginResult(PluginResult.Status.OK); @@ -330,9 +306,7 @@ else if (action.equals("hide")) { this.cordova.getActivity().runOnUiThread(new Runnable() { @Override public void run() { - if (dialog != null && !cordova.getActivity().isFinishing()) { - dialog.hide(); - } + dialog.hide(); } }); PluginResult pluginResult = new PluginResult(PluginResult.Status.OK); @@ -445,7 +419,7 @@ private HashMap parseFeature(String optString) { if (option.hasMoreElements()) { String key = option.nextToken(); String value = option.nextToken(); - if (!customizableOptions.contains(key)) { + if (!customizableOptions.contains(key)){ value = value.equals("yes") || value.equals("no") ? value : "yes"; } map.put(key, value); @@ -474,8 +448,7 @@ public String openExternal(String url) { intent.setData(uri); } intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName()); - // CB-10795: Avoid circular loops by preventing it from opening in the current app - this.openExternalExcludeCurrentApp(intent); + this.cordova.getActivity().startActivity(intent); return ""; // not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it } catch (java.lang.RuntimeException e) { @@ -484,46 +457,6 @@ public String openExternal(String url) { } } - /** - * Opens the intent, providing a chooser that excludes the current app to avoid - * circular loops. - */ - private void openExternalExcludeCurrentApp(Intent intent) { - String currentPackage = cordova.getActivity().getPackageName(); - boolean hasCurrentPackage = false; - - PackageManager pm = cordova.getActivity().getPackageManager(); - List activities = pm.queryIntentActivities(intent, 0); - ArrayList targetIntents = new ArrayList(); - - for (ResolveInfo ri : activities) { - if (!currentPackage.equals(ri.activityInfo.packageName)) { - Intent targetIntent = (Intent)intent.clone(); - targetIntent.setPackage(ri.activityInfo.packageName); - targetIntents.add(targetIntent); - } - else { - hasCurrentPackage = true; - } - } - - // If the current app package isn't a target for this URL, then use - // the normal launch behavior - if (hasCurrentPackage == false || targetIntents.size() == 0) { - this.cordova.getActivity().startActivity(intent); - } - // If there's only one possible intent, launch it directly - else if (targetIntents.size() == 1) { - this.cordova.getActivity().startActivity(targetIntents.get(0)); - } - // Otherwise, show a custom chooser without the current app listed - else if (targetIntents.size() > 0) { - Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size()-1), null); - chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {})); - this.cordova.getActivity().startActivity(chooser); - } - } - /** * Closes the dialog */ @@ -541,7 +474,7 @@ public void run() { childView.setWebViewClient(new WebViewClient() { // NB: wait for about:blank before dismissing public void onPageFinished(WebView view, String url) { - if (dialog != null && !cordova.getActivity().isFinishing()) { + if (dialog != null) { dialog.dismiss(); dialog = null; } @@ -624,7 +557,7 @@ private boolean getShowLocationBar() { return this.showLocationBar; } - private InAppBrowser getInAppBrowser() { + private InAppBrowser getInAppBrowser(){ return this; } @@ -695,9 +628,6 @@ public String showWebPage(final String url, HashMap features) { if (closeButtonColorSet != null) { closeButtonColor = closeButtonColorSet; } - String leftToRightSet = features.get(LEFT_TO_RIGHT); - leftToRight = leftToRightSet != null && leftToRightSet.equals("yes"); - String toolbarColorSet = features.get(TOOLBAR_COLOR); if (toolbarColorSet != null) { toolbarColor = android.graphics.Color.parseColor(toolbarColorSet); @@ -714,13 +644,6 @@ public String showWebPage(final String url, HashMap features) { if (footerColorSet != null) { footerColor = footerColorSet; } - if (features.get(BEFORELOAD) != null) { - beforeload = features.get(BEFORELOAD); - } - String fullscreenSet = features.get(FULLSCREEN); - if (fullscreenSet != null) { - fullscreen = fullscreenSet.equals("yes") ? true : false; - } } final CordovaWebView thatWebView = this.webView; @@ -741,7 +664,7 @@ private int dpToPixels(int dipValue) { return value; } - private View createCloseButton(int id) { + private View createCloseButton(int id){ View _close; Resources activityRes = cordova.getActivity().getResources(); @@ -769,8 +692,7 @@ private View createCloseButton(int id) { } RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - if (leftToRight) closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - else closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); _close.setLayoutParams(closeLayoutParams); if (Build.VERSION.SDK_INT >= 16) @@ -801,9 +723,6 @@ public void run() { dialog = new InAppBrowserDialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar); dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog; dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - if (fullscreen) { - dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } dialog.setCancelable(true); dialog.setInAppBroswer(getInAppBrowser()); @@ -817,22 +736,15 @@ public void run() { toolbar.setBackgroundColor(toolbarColor); 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)); - if (leftToRight) { - toolbar.setHorizontalGravity(Gravity.LEFT); - } else { - toolbar.setHorizontalGravity(Gravity.RIGHT); - } + toolbar.setHorizontalGravity(Gravity.LEFT); toolbar.setVerticalGravity(Gravity.TOP); // Action Button Container layout RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity()); - RelativeLayout.LayoutParams actionButtonLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - if (leftToRight) actionButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - else actionButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - actionButtonContainer.setLayoutParams(actionButtonLayoutParams); + actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); actionButtonContainer.setHorizontalGravity(Gravity.LEFT); actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL); - actionButtonContainer.setId(leftToRight ? Integer.valueOf(5) : Integer.valueOf(1)); + actionButtonContainer.setId(Integer.valueOf(1)); // Back button ImageButton back = new ImageButton(cordova.getActivity()); @@ -912,16 +824,15 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { // Header Close/Done button - int closeButtonId = leftToRight ? 1 : 5; - View close = createCloseButton(closeButtonId); + View close = createCloseButton(5); toolbar.addView(close); // Footer RelativeLayout footer = new RelativeLayout(cordova.getActivity()); int _footerColor; - if(footerColor != "") { + if(footerColor != ""){ _footerColor = Color.parseColor(footerColor); - } else { + }else{ _footerColor = android.graphics.Color.LTGRAY; } footer.setBackgroundColor(_footerColor); @@ -935,7 +846,6 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { View footerClose = createCloseButton(7); footer.addView(footerClose); - // WebView inAppWebView = new WebView(cordova.getActivity()); inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); @@ -945,23 +855,96 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { // For Android 5.0+ public boolean onShowFileChooser (WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { + if(Build.VERSION.SDK_INT >=23 && (cordova.getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || cordova.getActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) { + cordova.getActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1); + } + LOG.d(LOG_TAG, "File Chooser 5.0+"); + // If callback exists, finish it. if(mUploadCallbackLollipop != null) { mUploadCallbackLollipop.onReceiveValue(null); } mUploadCallbackLollipop = filePathCallback; + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + + if(takePictureIntent.resolveActivity(cordova.getActivity().getPackageManager()) != null) { + + File photoFile = null; + Uri photoUri = null; + + if (isAndroidQ) { + // Android Q compatibility + photoUri = createImageUri(); + mCameraUri = photoUri; + if (photoUri != null) { + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); + } + } else { + try { + photoFile = createImageFile(); + takePictureIntent.putExtra("PhotoPath", mCM); + } catch (IOException ex) { + Log.e(LOG_TAG, "Image file creation failed", ex); + } + if (photoFile != null) { + mCM = "file:" + photoFile.getAbsolutePath(); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); + } else { + takePictureIntent = null; + } + } + } // Create File Chooser Intent - Intent content = new Intent(Intent.ACTION_GET_CONTENT); - content.addCategory(Intent.CATEGORY_OPENABLE); - content.setType("*/*"); + Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); + contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); + contentSelectionIntent.setType("*/*"); + Intent[] intentArray; + if(takePictureIntent != null){ + intentArray = new Intent[]{takePictureIntent}; + }else{ + intentArray = new Intent[0]; + } + + Locale localeInfo = cordova.getActivity().getApplicationContext().getResources() + .getConfiguration().getLocales().get(0); + + String lang = localeInfo.toLanguageTag(); + + String title; + + if (lang.startsWith("en")) + { + title = "Choose the source"; + } else if (lang.startsWith("es")) + { + title = "Seleccione el origen"; + } else + { + title = "Escolha a origem"; + } + + Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); + chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); + chooserIntent.putExtra(Intent.EXTRA_TITLE, title); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); // Run cordova startActivityForResult - cordova.startActivityForResult(InAppBrowser.this, Intent.createChooser(content, "Select File"), FILECHOOSER_REQUESTCODE_LOLLIPOP); + cordova.startActivityForResult(InAppBrowser.this, chooserIntent, 120); + return true; } + private Uri createImageUri() { + String status = Environment.getExternalStorageState(); + if (status.equals(Environment.MEDIA_MOUNTED)) { + return cordova.getActivity().getApplicationContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues()); + } else { + return cordova.getActivity().getApplicationContext().getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues()); + } + } + // For Android 4.1+ public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) { @@ -983,32 +966,16 @@ public void openFileChooser(ValueCallback uploadMsg, String acceptType) } }); - currentClient = new InAppBrowserClient(thatWebView, edittext, beforeload); - inAppWebView.setWebViewClient(currentClient); + WebViewClient client = new InAppBrowserClient(thatWebView, edittext); + inAppWebView.setWebViewClient(client); WebSettings settings = inAppWebView.getSettings(); settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setBuiltInZoomControls(showZoomControls); settings.setPluginState(android.webkit.WebSettings.PluginState.ON); - // Add postMessage interface - class JsObject { - @JavascriptInterface - public void postMessage(String data) { - try { - JSONObject obj = new JSONObject(); - obj.put("type", MESSAGE_EVENT); - obj.put("data", new JSONObject(data)); - sendUpdate(obj, true); - } catch (JSONException ex) { - LOG.e(LOG_TAG, "data object passed to postMessage has caused a JSON error."); - } - } - } - if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture); - inAppWebView.addJavascriptInterface(new JsObject(), "cordova_iab"); } String overrideUserAgent = preferences.getString("OverrideUserAgent", null); @@ -1078,14 +1045,12 @@ public void postMessage(String data) { lp.width = WindowManager.LayoutParams.MATCH_PARENT; lp.height = WindowManager.LayoutParams.MATCH_PARENT; - if (dialog != null) { - dialog.setContentView(main); - dialog.show(); - dialog.getWindow().setAttributes(lp); - } + dialog.setContentView(main); + dialog.show(); + dialog.getWindow().setAttributes(lp); // the goal of openhidden is to load the url and not display it // Show() needs to be called to cause the URL to be loaded - if (openWindowHidden && dialog != null) { + if(openWindowHidden) { dialog.hide(); } } @@ -1094,6 +1059,12 @@ public void postMessage(String data) { return ""; } + private File createImageFile() throws IOException{ + @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + String imageFileName = "img_"+timeStamp+"_"; + File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + return File.createTempFile(imageFileName,".jpg",storageDir); + } /** * Create a new plugin success result and send it back to JavaScript * @@ -1130,13 +1101,30 @@ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Statu public void onActivityResult(int requestCode, int resultCode, Intent intent) { // For Android >= 5.0 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + LOG.d(LOG_TAG, "onActivityResult (For Android >= 5.0)"); - // If RequestCode or Callback is Invalid - if(requestCode != FILECHOOSER_REQUESTCODE_LOLLIPOP || mUploadCallbackLollipop == null) { - super.onActivityResult(requestCode, resultCode, intent); - return; + + Uri[] results = null; + //Check if response is positive + if(resultCode== Activity.RESULT_OK){ + if(requestCode == FILECHOOSER_REQUESTCODE){ + if(null == mUploadCallbackLollipop){ + return; + } + if(intent == null || intent.getData() == null){ + //Capture Photo if no image available + if(mCM != null){ + results = new Uri[]{Uri.parse(mCM)}; + } + }else{ + String dataString = intent.getDataString(); + if(dataString != null){ + results = new Uri[]{Uri.parse(dataString)}; + } + } + } } - mUploadCallbackLollipop.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent)); + mUploadCallbackLollipop .onReceiveValue(results); mUploadCallbackLollipop = null; } // For Android < 5.0 @@ -1162,8 +1150,6 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) { public class InAppBrowserClient extends WebViewClient { EditText edittext; CordovaWebView webView; - String beforeload; - boolean waitForBeforeload; /** * Constructor. @@ -1171,97 +1157,27 @@ public class InAppBrowserClient extends WebViewClient { * @param webView * @param mEditText */ - public InAppBrowserClient(CordovaWebView webView, EditText mEditText, String beforeload) { + public InAppBrowserClient(CordovaWebView webView, EditText mEditText) { this.webView = webView; this.edittext = mEditText; - this.beforeload = beforeload; - this.waitForBeforeload = beforeload != null; } /** * Override the URL that should be loaded * - * Legacy (deprecated in API 24) - * For Android 6 and below. + * This handles a small subset of all the URIs that would be encountered. * * @param webView * @param url */ - @SuppressWarnings("deprecation") @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { - return shouldOverrideUrlLoading(url, null); - } - - /** - * Override the URL that should be loaded - * - * New (added in API 24) - * For Android 7 and above. - * - * @param webView - * @param request - */ - @TargetApi(Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request) { - return shouldOverrideUrlLoading(request.getUrl().toString(), request.getMethod()); - } - - /** - * Override the URL that should be loaded - * - * This handles a small subset of all the URIs that would be encountered. - * - * @param url - * @param method - */ - public boolean shouldOverrideUrlLoading(String url, String method) { - boolean override = false; - boolean useBeforeload = false; - String errorMessage = null; - - if (beforeload.equals("yes") && method == null) { - useBeforeload = true; - } else if(beforeload.equals("yes") - //TODO handle POST requests then this condition can be removed: - && !method.equals("POST")) - { - useBeforeload = true; - } else if(beforeload.equals("get") && (method == null || method.equals("GET"))) { - useBeforeload = true; - } else if(beforeload.equals("post") && (method == null || method.equals("POST"))) { - //TODO handle POST requests - errorMessage = "beforeload doesn't yet support POST requests"; - } - - // On first URL change, initiate JS callback. Only after the beforeload event, continue. - if (useBeforeload && this.waitForBeforeload) { - if(sendBeforeLoad(url, method)) { - return true; - } - } - - if(errorMessage != null) { - try { - LOG.e(LOG_TAG, errorMessage); - JSONObject obj = new JSONObject(); - obj.put("type", LOAD_ERROR_EVENT); - obj.put("url", url); - obj.put("code", -1); - obj.put("message", errorMessage); - sendUpdate(obj, true, PluginResult.Status.ERROR); - } catch(Exception e) { - LOG.e(LOG_TAG, "Error sending loaderror for " + url + ": " + e.toString()); - } - } - if (url.startsWith(WebView.SCHEME_TEL)) { try { Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse(url)); cordova.getActivity().startActivity(intent); - override = true; + return true; } catch (android.content.ActivityNotFoundException e) { LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString()); } @@ -1270,7 +1186,7 @@ public boolean shouldOverrideUrlLoading(String url, String method) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); cordova.getActivity().startActivity(intent); - override = true; + return true; } catch (android.content.ActivityNotFoundException e) { LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString()); } @@ -1301,18 +1217,16 @@ else if (url.startsWith("sms:")) { intent.putExtra("address", address); intent.setType("vnd.android-dir/mms-sms"); cordova.getActivity().startActivity(intent); - override = true; + return true; } catch (android.content.ActivityNotFoundException e) { LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString()); } } // Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response) - else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[A-Za-z0-9+.-]*://.*?$")) { + else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[a-z]*://.*?$")) { if (allowedSchemes == null) { - String allowed = preferences.getString("AllowedSchemes", null); - if(allowed != null) { - allowedSchemes = allowed.split(","); - } + String allowed = preferences.getString("AllowedSchemes", ""); + allowedSchemes = allowed.split(","); } if (allowedSchemes != null) { for (String scheme : allowedSchemes) { @@ -1322,7 +1236,7 @@ else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^ obj.put("type", "customscheme"); obj.put("url", url); sendUpdate(obj, true); - override = true; + return true; } catch (JSONException ex) { LOG.e(LOG_TAG, "Custom Scheme URI passed in has caused a JSON error."); } @@ -1331,59 +1245,10 @@ else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^ } } - if (useBeforeload) { - this.waitForBeforeload = true; - } - return override; - } - - private boolean sendBeforeLoad(String url, String method) { - try { - JSONObject obj = new JSONObject(); - obj.put("type", BEFORELOAD); - obj.put("url", url); - if(method != null) { - obj.put("method", method); - } - sendUpdate(obj, true); - return true; - } catch (JSONException ex) { - LOG.e(LOG_TAG, "URI passed in has caused a JSON error."); - } return false; } - /** - * Legacy (deprecated in API 21) - * For Android 4.4 and below. - * @param view - * @param url - * @return - */ - @SuppressWarnings("deprecation") - @Override - public WebResourceResponse shouldInterceptRequest (final WebView view, String url) { - return shouldInterceptRequest(url, super.shouldInterceptRequest(view, url), null); - } - - /** - * New (added in API 21) - * For Android 5.0 and above. - * - * @param webView - * @param request - */ - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - return shouldInterceptRequest(request.getUrl().toString(), super.shouldInterceptRequest(view, request), request.getMethod()); - } - - public WebResourceResponse shouldInterceptRequest(String url, WebResourceResponse response, String method) { - return response; - } - /* * onPageStarted fires the LOAD_START_EVENT * @@ -1421,14 +1286,11 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) { } } + + public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - // Set the namespace for postMessage() - if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { - injectDeferredObject("window.webkit={messageHandlers:{cordova_iab:cordova_iab}}", null); - } - // CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().flush(); @@ -1467,46 +1329,6 @@ public void onReceivedError(WebView view, int errorCode, String description, Str } } - @Override - public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - super.onReceivedSslError(view, handler, error); - try { - JSONObject obj = new JSONObject(); - obj.put("type", LOAD_ERROR_EVENT); - obj.put("url", error.getUrl()); - obj.put("code", 0); - obj.put("sslerror", error.getPrimaryError()); - String message; - switch (error.getPrimaryError()) { - case SslError.SSL_DATE_INVALID: - message = "The date of the certificate is invalid"; - break; - case SslError.SSL_EXPIRED: - message = "The certificate has expired"; - break; - case SslError.SSL_IDMISMATCH: - message = "Hostname mismatch"; - break; - default: - case SslError.SSL_INVALID: - message = "A generic error occurred"; - break; - case SslError.SSL_NOTYETVALID: - message = "The certificate is not yet valid"; - break; - case SslError.SSL_UNTRUSTED: - message = "The certificate authority is not trusted"; - break; - } - obj.put("message", message); - - sendUpdate(obj, true, PluginResult.Status.ERROR); - } catch (JSONException ex) { - LOG.d(LOG_TAG, "Should never happen"); - } - handler.cancel(); - } - /** * On received http auth request. */