diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java index 134cf098..f434661a 100755 --- a/framework/src/org/apache/cordova/CameraLauncher.java +++ b/framework/src/org/apache/cordova/CameraLauncher.java @@ -342,7 +342,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Add compressed version of captured image to returned media store Uri DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent"); - OutputStream os = dataResource.getOutputStream(); + OutputStream os = dataResource.getOs(); bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); os.close(); @@ -540,9 +540,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect private void writeUncompressedImage(Uri uri) throws FileNotFoundException, IOException { DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage"); - InputStream fis = inputDataResource.getInputStream(); + InputStream fis = inputDataResource.getIs(); DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage"); - OutputStream os = outDataResource.getOutputStream(); + OutputStream os = outDataResource.getOs(); if(fis == null) { throw new FileNotFoundException("Could not get the input file"); } else if(os == null) { @@ -592,13 +592,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // If no new width or height were specified return the original bitmap DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap"); if (this.targetWidth <= 0 && this.targetHeight <= 0) { - return BitmapFactory.decodeStream(dataResource.getInputStream()); + return BitmapFactory.decodeStream(dataResource.getIs()); } // figure out the original width and height of the image BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(dataResource.getInputStream(), null, options); + BitmapFactory.decodeStream(dataResource.getIs(), null, options); //CB-2292: WTF? Why is the width null? if(options.outWidth == 0 || options.outHeight == 0) @@ -612,7 +612,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Load in the smallest bitmap possible that is closest to the size we want options.inJustDecodeBounds = false; options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight); - Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getInputStream(), null, options); + Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getIs(), null, options); if (unscaledBitmap == null) { return null; } diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java index 69c7f489..e7bf98a8 100644 --- a/framework/src/org/apache/cordova/FileHelper.java +++ b/framework/src/org/apache/cordova/FileHelper.java @@ -130,27 +130,33 @@ public class FileHelper { */ public static boolean isUriWritable(String uriString) { String scheme = uriString.split(":")[0]; + String writableSchemes[] = new String[]{ "content" }; if(scheme.equals("file")){ // special case file - return !uriString.startsWith("file:///android_asset/"); + if(uriString.startsWith("file:///android_asset/")){ + return false; + } else { + return true; + } } - return "content".equals(scheme); + for(int i = writableSchemes.length - 1; i >= 0 ; i--){ + if(writableSchemes[i].equals(scheme)){ + return true; + } + } + return false; } /** * Ensures the "file://" prefix exists for the given string - * If the given URI string already has a scheme, it is returned unchanged + * If the given URI string has a "file://" prefix, it is returned unchanged * * @param path - the path string to operate on * @return a String with the "file://" scheme set */ public static String insertFileProtocol(String path) { if(!path.matches("^[a-z0-9+.-]+:.*")){ - //Ensure it is not a relative path - if(!path.startsWith("/")){ - throw new IllegalArgumentException("Relative paths" + path + "are not allowed."); - } path = "file://" + path; } return path; diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java index 4b136ed2..fe5a4ab1 100755 --- a/framework/src/org/apache/cordova/FileUtils.java +++ b/framework/src/org/apache/cordova/FileUtils.java @@ -897,7 +897,7 @@ public class FileUtils extends CordovaPlugin { public void run() { try { DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs"); - byte[] bytes = readAsBinaryHelper(dataResource.getInputStream(), start, end); + byte[] bytes = readAsBinaryHelper(dataResource.getIs(), start, end); PluginResult result; switch (resultType) { diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java index 4b3408c9..2a686d8a 100644 --- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java @@ -46,13 +46,16 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient { public WebResourceResponse shouldInterceptRequest(WebView view, String url) { // We need to support the new DataResource intercepts without breaking the shouldInterceptRequest mechanism. DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.appView.pluginManager, cordova, - "WebViewClient.shouldInterceptRequest"); + new DataResourceContext("WebViewClient.shouldInterceptRequest", true /* this is from a browser request*/)); url = dataResource.getUri().toString(); // This mechanism is no longer needed due to the dataResource mechanism. It would be awesome to just get rid of it. //Check if plugins intercept the request WebResourceResponse ret = super.shouldInterceptRequest(view, url); - +// The below bugfix is taken care of by the dataResource mechanism +// if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){ +// ret = generateWebResourceResponse(url); +// } if(ret == null) { try { ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getInputStream()); diff --git a/framework/src/org/apache/cordova/api/CordovaPlugin.java b/framework/src/org/apache/cordova/api/CordovaPlugin.java index 866677c3..69f8fdeb 100644 --- a/framework/src/org/apache/cordova/api/CordovaPlugin.java +++ b/framework/src/org/apache/cordova/api/CordovaPlugin.java @@ -182,10 +182,10 @@ public class CordovaPlugin { * * @param dataResource The resource to be loaded. * @param dataResourceContext Context associated with the resource load - * @return Return a new DataResource if the plugin wants to assist in loading the request or null if it doesn't. + * @return Return a new DataResource if the plugin wants o assist in loading the request or null if it doesn't. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public DataResource handleDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) { + public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) { return null; } diff --git a/framework/src/org/apache/cordova/api/DataResource.java b/framework/src/org/apache/cordova/api/DataResource.java index 5c1bb18e..38bf31bf 100644 --- a/framework/src/org/apache/cordova/api/DataResource.java +++ b/framework/src/org/apache/cordova/api/DataResource.java @@ -42,13 +42,10 @@ public class DataResource { private String mimeType; private Boolean writable; private File realFile; - private boolean retryIsLoad = true; - private boolean retryOsLoad = true; - private boolean retryMimeTypeLoad = true; - private boolean retryWritableLoad = true; - private boolean retryRealFileLoad = true; + private boolean retryLoad = true; public DataResource(CordovaInterface cordova, Uri uri) { + super(); this.cordova = cordova; this.uri = uri; } @@ -64,61 +61,61 @@ public class DataResource { // Uri is always provided return uri; } - public InputStream getInputStream() throws IOException { - if(is == null && retryIsLoad) { + public InputStream getIs() throws IOException { + if(is == null && retryLoad) { try { is = FileHelper.getInputStreamFromUriString(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(is == null) { - retryIsLoad = false; + retryLoad = false; } } } return is; } - public OutputStream getOutputStream() throws FileNotFoundException { - if(os == null && retryOsLoad) { + public OutputStream getOs() throws FileNotFoundException { + if(os == null && retryLoad) { try { os = FileHelper.getOutputStreamFromUriString(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(os == null) { - retryOsLoad = false; + retryLoad = false; } } } return os; } public String getMimeType() { - if(mimeType == null && retryMimeTypeLoad) { + if(mimeType == null && retryLoad) { try { mimeType = FileHelper.getMimeType(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(mimeType == null) { - retryMimeTypeLoad = false; + retryLoad = false; } } } return mimeType; } public boolean isWritable() { - if(writable == null && retryWritableLoad) { + if(writable == null && retryLoad) { try { writable = FileHelper.isUriWritable(uri.toString()); } finally { // We failed loading once, don't try loading anymore if(writable == null) { - retryWritableLoad = false; + retryLoad = false; } } } // default to false - return writable != null && writable.booleanValue(); + return writable != null? writable.booleanValue() : false; } public File getRealFile() { - if(realFile == null && retryRealFileLoad) { + if(realFile == null && retryLoad) { try { String realPath = FileHelper.getRealPath(uri, cordova); if(realPath != null) { @@ -127,7 +124,7 @@ public class DataResource { } finally { // We failed loading once, don't try loading anymore if(realFile == null) { - retryRealFileLoad = false; + retryLoad = false; } } } @@ -141,7 +138,7 @@ public class DataResource { return initiateNewDataRequestForUri(Uri.parse(uriString), pluginManager, cordova, requestSourceTag); } public static DataResource initiateNewDataRequestForUri(Uri uri, PluginManager pluginManager, CordovaInterface cordova, String requestSourceTag){ - return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag)); + return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag, false /* Assume, not a browser request by default */ )); } public static DataResource initiateNewDataRequestForUri(String uriString, PluginManager pluginManager, CordovaInterface cordova, DataResourceContext dataResourceContext){ // if no protocol is specified, assume its file: @@ -152,7 +149,7 @@ public class DataResource { DataResource dataResource = new DataResource(cordova, uri); if (pluginManager != null) { // get the resource as returned by plugins - dataResource = pluginManager.handleDataResourceRequestWithPlugins(dataResource, dataResourceContext); + dataResource = pluginManager.shouldInterceptDataResourceRequest(dataResource, dataResourceContext); } return dataResource; } diff --git a/framework/src/org/apache/cordova/api/DataResourceContext.java b/framework/src/org/apache/cordova/api/DataResourceContext.java index 9cfe7bcc..55bbc1d0 100644 --- a/framework/src/org/apache/cordova/api/DataResourceContext.java +++ b/framework/src/org/apache/cordova/api/DataResourceContext.java @@ -30,11 +30,15 @@ public class DataResourceContext { // A tag associated with the source of this dataResourceContext private String source; // If needed, any data associated with core plugins can be a part of the context object + // This field indicates whether the request came from a browser network request + private boolean isFromBrowser; // If needed, any data associated with non core plugins should store data in a Map so as to not clutter the context object private Map dataMap; - public DataResourceContext(String source) { + public DataResourceContext(String source, boolean isFromBrowser) { + super(); this.requestId = new Random().nextInt(); this.source = source; + this.isFromBrowser = isFromBrowser; this.dataMap = new HashMap(); } public int getRequestId() { @@ -43,6 +47,9 @@ public class DataResourceContext { public String getSource() { return source; } + public boolean isFromBrowser() { + return isFromBrowser; + } public Map getDataMap() { return dataMap; } diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java index e0ceabfb..36ac357e 100755 --- a/framework/src/org/apache/cordova/api/PluginManager.java +++ b/framework/src/org/apache/cordova/api/PluginManager.java @@ -54,7 +54,6 @@ public class PluginManager { // Map URL schemes like foo: to plugins that want to handle those schemes // This would allow how all URLs are handled to be offloaded to a plugin protected HashMap urlMap = new HashMap(); - private int MAX_REPITIONS = 1000; /** * Constructor. @@ -410,15 +409,13 @@ public class PluginManager { * @param dataResourceContext The context of the dataResource request * @return Return the resource request that will be loaded. The returned request may be modified or unchanged. */ - public DataResource handleDataResourceRequestWithPlugins(DataResource dataResource, DataResourceContext dataResourceContext){ - int repetitions = 0; + public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext){ boolean requestModified = true; - while(requestModified && repetitions < MAX_REPITIONS) { + while(requestModified) { requestModified = false; - repetitions ++; for (PluginEntry entry : this.entries.values()) { if (entry.plugin != null) { - DataResource ret = entry.plugin.handleDataResourceRequest(dataResource, dataResourceContext); + DataResource ret = entry.plugin.shouldInterceptDataResourceRequest(dataResource, dataResourceContext); if(ret != null) { dataResource = ret; requestModified = true;