You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2015/03/11 16:35:12 UTC

[01/13] cordova-plugin-file git commit: CB-8642 android: Fix content URIs not working with resolve / copy

Repository: cordova-plugin-file
Updated Branches:
  refs/heads/master 2ed379c7c -> 80cf1de40


CB-8642 android: Fix content URIs not working with resolve / copy

The issue was fairly fundamental to our cdvfile:// scheme and required
some refactorings:
- Move isDirectory into LocalFilesystemURL
- Add toNativeUri() / toLocalUri() for converting between cdvfile: / file: / content:
- Made toInternalUrl() maintain query params for content: uris
- Moved copyFileToURL(), readFileAtURL(), getOutputStreamForURL() into base Filesystem class

Also added a ContentProvider to the test plugin and unit tests!


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/d6202261
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/d6202261
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/d6202261

Branch: refs/heads/master
Commit: d6202261fec395854050e771d262afcf4d4e86d9
Parents: 9d78908
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 13:54:33 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/ContentFilesystem.java         | 197 +++++++++---------------
 src/android/FileUtils.java                 |  50 +++---
 src/android/Filesystem.java                | 124 ++++++++-------
 src/android/LocalFilesystem.java           | 141 ++++++++---------
 src/android/LocalFilesystemURL.java        |  27 ++--
 tests/plugin.xml                           |  10 ++
 tests/src/android/TestContentProvider.java |  78 ++++++++++
 tests/tests.js                             |  75 ++++++---
 www/Entry.js                               |   2 +-
 www/FileSystem.js                          |   2 +-
 www/android/FileSystem.js                  |  13 +-
 11 files changed, 404 insertions(+), 315 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index a4a2227..25c6489 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -23,14 +23,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
-import org.apache.cordova.CordovaInterface;
 import org.apache.cordova.CordovaResourceApi;
-import org.apache.cordova.CordovaWebView;
-import org.apache.cordova.PluginManager;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -50,68 +43,67 @@ public class ContentFilesystem extends Filesystem {
 		super(Uri.parse("content://"), "content", resourceApi);
         this.context = context;
 	}
-	
-	@Override
-	public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-	    if ("/".equals(inputURL.uri.getPath())) {
-            return LocalFilesystem.makeEntryForURL(inputURL, true, inputURL.uri);
-	    }
 
-		// Get the cursor to validate that the file exists
-		Cursor cursor = openCursorForURL(inputURL);
-		File file = resourceApi.mapUriToFile(inputURL.uri);
-        Uri nativeUrl;
-		if (file == null) {
-            nativeUrl = inputURL.uri;
-		} else {
-            nativeUrl = Uri.fromFile(file);
-		}
-        return makeEntryForURL(inputURL, false /*fp.isDirectory()*/, nativeUrl);
-	}
-	
     @Override
-	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
-			String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException, JSONException {
-        if (options != null) {
-            if (options.optBoolean("create")) {
-        		throw new IOException("Cannot create content url");
-            }
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        String authorityAndPath = inputURL.uri.getEncodedPath().substring(this.name.length() + 2);
+        if (authorityAndPath.length() < 2) {
+            return null;
         }
-        LocalFilesystemURL requestedURL = LocalFilesystemURL.parse(Uri.withAppendedPath(inputURL.uri, fileName));
-        File fp = new File(this.filesystemPathForURL(requestedURL));
-        if (!fp.exists()) {
-            throw new FileNotFoundException("path does not exist");
+        String ret = "content://" + authorityAndPath;
+        String query = inputURL.uri.getEncodedQuery();
+        if (query != null) {
+            ret += '?' + query;
         }
-        if (directory) {
-            if (fp.isFile()) {
-                throw new TypeMismatchException("path doesn't exist or is file");
-            }
-        } else {
-            if (fp.isDirectory()) {
-                throw new TypeMismatchException("path doesn't exist or is directory");
-            }
+        String frag = inputURL.uri.getEncodedFragment();
+        if (frag != null) {
+            ret += '#' + frag;
         }
-        // Return the directory
-        return makeEntryForURL(requestedURL, directory, Uri.fromFile(fp));
+        return Uri.parse(ret);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"content".equals(inputURL.getScheme())) {
+            return null;
+        }
+        String subPath = inputURL.getEncodedPath();
+        if (subPath.length() > 0) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name)
+            .appendPath(inputURL.getAuthority());
+        if (subPath.length() > 0) {
+            b.appendEncodedPath(subPath);
+        }
+        Uri localUri = b.encodedQuery(inputURL.getEncodedQuery())
+            .encodedFragment(inputURL.getEncodedFragment())
+            .build();
+        return LocalFilesystemURL.parse(localUri);
+    }
 
+    @Override
+	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
+			String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException, JSONException {
+        throw new UnsupportedOperationException("getFile() not supported for content:. Use resolveLocalFileSystemURL instead.");
 	}
 
 	@Override
 	public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL)
 			throws NoModificationAllowedException {
-
-		String filePath = filesystemPathForURL(inputURL);
-		File file = new File(filePath);
+        Uri contentUri = toNativeUri(inputURL);
 		try {
-            context.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-					MediaStore.Images.Media.DATA + " = ?",
-					new String[] { filePath });
+            context.getContentResolver().delete(contentUri, null, null);
 		} catch (UnsupportedOperationException t) {
 			// Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
 			// The ContentResolver applies only when the file was registered in the
 			// first case, which is generally only the case with images.
+            throw new NoModificationAllowedException("Deleting not supported for content uri: " + contentUri);
 		}
-		return file.delete();
+        return true;
 	}
 
 	@Override
@@ -123,22 +115,27 @@ public class ContentFilesystem extends Filesystem {
 	@Override
 	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL)
 			throws FileNotFoundException {
-		// TODO Auto-generated method stub
-		return null;
+        throw new UnsupportedOperationException("readEntriesAtLocalURL() not supported for content:. Use resolveLocalFileSystemURL instead.");
 	}
 
 	@Override
 	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
-		Integer size = null;
-		Integer lastModified = null;
-        Cursor cursor = openCursorForURL(inputURL);
+        long size = -1;
+        long lastModified = 0;
+        Uri nativeUri = toNativeUri(inputURL);
+        String mimeType = resourceApi.getMimeType(nativeUri);
+        Cursor cursor = openCursorForURL(nativeUri);
         try {
         	if (cursor != null && cursor.moveToFirst()) {
         		size = resourceSizeForCursor(cursor);
         		lastModified = lastModifiedDateForCursor(cursor);
         	} else {
-    			throw new FileNotFoundException();
+                // Some content providers don't support cursors at all!
+                CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(nativeUri);
+    			size = offr.length;
         	}
+        } catch (IOException e) {
+            throw new FileNotFoundException();
         } finally {
         	if (cursor != null)
         		cursor.close();
@@ -147,9 +144,9 @@ public class ContentFilesystem extends Filesystem {
         JSONObject metadata = new JSONObject();
         try {
         	metadata.put("size", size);
-        	metadata.put("type", resourceApi.getMimeType(inputURL.uri));
+        	metadata.put("type", mimeType);
         	metadata.put("name", name);
-        	metadata.put("fullPath", inputURL.pathAndQuery);
+        	metadata.put("fullPath", inputURL.path);
         	metadata.put("lastModifiedDate", lastModified);
         } catch (JSONException e) {
         	return null;
@@ -158,56 +155,6 @@ public class ContentFilesystem extends Filesystem {
 	}
 
 	@Override
-	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
-			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move)
-                    throws IOException, InvalidModificationException, JSONException,
-                    NoModificationAllowedException, FileExistsException {
-        if (LocalFilesystem.class.isInstance(srcFs)) {
-            /* Same FS, we can shortcut with CordovaResourceApi operations */
-            // Figure out where we should be copying to
-            final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL);
-
-            OutputStream os = resourceApi.openOutputStream(destURL.uri);
-            CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcURL.uri);
-            if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
-                throw new NoModificationAllowedException("Cannot move file at source URL");
-            }
-            try {
-                resourceApi.copyResource(ofrr, os);
-            } catch (IOException e) {
-                throw new IOException("Cannot read file at source URL");
-            }
-            if (move) {
-                srcFs.removeFileAtLocalURL(srcURL);
-            }
-            return makeEntryForURL(destinationURL, false, destinationURL.uri);
-        } else {
-            // Need to copy the hard way
-            return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
-		}
-	}
-
-    
-	@Override
-    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
-			ReadFileCallback readFileCallback) throws IOException {
-		CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(inputURL.uri);
-        if (end < 0) {
-            end = ofrr.length;
-        }
-        long numBytesToRead = end - start;
-		try {
-			if (start > 0) {
-                ofrr.inputStream.skip(start);
-			}
-            LimitedInputStream inputStream = new LimitedInputStream(ofrr.inputStream, numBytesToRead);
-            readFileCallback.handleData(inputStream, ofrr.mimeType);
-		} finally {
-            ofrr.inputStream.close();
-		}
-	}
-
-	@Override
 	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
 			int offset, boolean isBinary) throws NoModificationAllowedException {
         throw new NoModificationAllowedException("Couldn't write to file given its content URI");
@@ -218,30 +165,33 @@ public class ContentFilesystem extends Filesystem {
         throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
 	}
 
-	protected Cursor openCursorForURL(LocalFilesystemURL url) {
+	protected Cursor openCursorForURL(Uri nativeUri) {
         ContentResolver contentResolver = context.getContentResolver();
-        Cursor cursor = contentResolver.query(url.uri, null, null, null, null);
-        return cursor;
+        try {
+            return contentResolver.query(nativeUri, null, null, null, null);
+        } catch (UnsupportedOperationException e) {
+            return null;
+        }
 	}
 
-	protected Integer resourceSizeForCursor(Cursor cursor) {
+	private Long resourceSizeForCursor(Cursor cursor) {
         int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
         if (columnIndex != -1) {
             String sizeStr = cursor.getString(columnIndex);
             if (sizeStr != null) {
-            	return Integer.parseInt(sizeStr,10);
+            	return Long.parseLong(sizeStr);
             }
         }
         return null;
 	}
 	
-	protected Integer lastModifiedDateForCursor(Cursor cursor) {
+	protected Long lastModifiedDateForCursor(Cursor cursor) {
         final String[] LOCAL_FILE_PROJECTION = { MediaStore.MediaColumns.DATE_MODIFIED };
         int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
         if (columnIndex != -1) {
             String dateStr = cursor.getString(columnIndex);
             if (dateStr != null) {
-            	return Integer.parseInt(dateStr,10);
+            	return Long.parseLong(dateStr);
             }
         }
         return null;
@@ -249,7 +199,7 @@ public class ContentFilesystem extends Filesystem {
 
     @Override
     public String filesystemPathForURL(LocalFilesystemURL url) {
-        File f = resourceApi.mapUriToFile(url.uri);
+        File f = resourceApi.mapUriToFile(toNativeUri(url));
         return f == null ? null : f.getAbsolutePath();
     }
 
@@ -261,15 +211,6 @@ public class ContentFilesystem extends Filesystem {
 
 	@Override
 	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
-		String path = filesystemPathForURL(inputURL);
-		File file = new File(path);
-		return file.exists();
+		return true;
 	}
-
-	@Override
-	OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL)
-			throws IOException {
-		OutputStream os = resourceApi.openOutputStream(inputURL.uri);
-		return os;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 2a1e965..a810726 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -41,7 +41,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
-import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -503,6 +502,24 @@ public class FileUtils extends CordovaPlugin {
         return true;
     }
 
+    public LocalFilesystemURL resolveNativeUri(Uri nativeUri) {
+        LocalFilesystemURL localURL = null;
+
+        // Try all installed filesystems. Return the best matching URL
+        // (determined by the shortest resulting URL)
+        for (Filesystem fs : filesystems) {
+            LocalFilesystemURL url = fs.toLocalUri(nativeUri);
+            if (url != null) {
+                // A shorter fullPath implies that the filesystem is a better
+                // match for the local path than the previous best.
+                if (localURL == null || (url.uri.toString().length() < localURL.toString().length())) {
+                    localURL = url;
+                }
+            }
+        }
+        return localURL;
+    }
+
     /*
      * These two native-only methods can be used by other plugins to translate between
      * device file system paths and URLs. By design, there is no direct JavaScript
@@ -529,15 +546,13 @@ public class FileUtils extends CordovaPlugin {
         // Try all installed filesystems. Return the best matching URL
         // (determined by the shortest resulting URL)
         for (Filesystem fs: filesystems) {
-            if (fs != null) {
-                LocalFilesystemURL url = fs.URLforFilesystemPath(localPath);
-                if (url != null) {
-                    // A shorter fullPath implies that the filesystem is a better
-                    // match for the local path than the previous best.
-                    if (localURL == null || (url.pathAndQuery.length() < shortestFullPath)) {
-                        localURL = url;
-                        shortestFullPath = url.pathAndQuery.length();
-                    }
+            LocalFilesystemURL url = fs.URLforFilesystemPath(localPath);
+            if (url != null) {
+                // A shorter fullPath implies that the filesystem is a better
+                // match for the local path than the previous best.
+                if (localURL == null || (url.path.length() < shortestFullPath)) {
+                    localURL = url;
+                    shortestFullPath = url.path.length();
                 }
             }
         }
@@ -592,18 +607,15 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject resolveLocalFileSystemURI(String uriString) throws IOException, JSONException {
-    	LocalFilesystemURL inputURL;
     	if (uriString == null) {
     		throw new MalformedURLException("Unrecognized filesystem URL");
     	}
     	Uri uri = Uri.parse(uriString);
 
-		/* Backwards-compatibility: Check for file:// urls */
-        if ("file".equals(uri.getScheme())) {
-            String path = uri.getPath();
-    		inputURL = this.filesystemURLforLocalPath(path);
-    	} else {
-    		inputURL = LocalFilesystemURL.parse(uri);
+        LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri);
+        if (inputURL == null) {
+    		/* Check for file://, content:// urls */
+    		inputURL = resolveNativeUri(uri);
     	}
 
         try {
@@ -687,7 +699,7 @@ public class FileUtils extends CordovaPlugin {
         try {
         	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	// You can't delete the root directory.
-        	if ("".equals(inputURL.pathAndQuery) || "/".equals(inputURL.pathAndQuery)) {
+        	if ("".equals(inputURL.path) || "/".equals(inputURL.path)) {
         		throw new NoModificationAllowedException("You can't delete the root directory");
         	}
 
@@ -716,7 +728,7 @@ public class FileUtils extends CordovaPlugin {
         try {
         	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	// You can't delete the root directory.
-        	if ("".equals(inputURL.pathAndQuery) || "/".equals(inputURL.pathAndQuery)) {
+        	if ("".equals(inputURL.path) || "/".equals(inputURL.path)) {
 
         		throw new NoModificationAllowedException("You can't delete the root directory");
         	}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 64b78b8..2d64942 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -43,34 +43,36 @@ public abstract class Filesystem {
         this.rootUri = rootUri;
         this.name = name;
         this.resourceApi = resourceApi;
-        rootEntry = makeEntryForPath("/", name, true, rootUri.toString());
+        rootEntry = makeEntryForNativeUri(rootUri);
     }
 
     public interface ReadFileCallback {
 		public void handleData(InputStream inputStream, String contentType) throws IOException;
 	}
 
-	public static JSONObject makeEntryForPath(String path, String fsName, Boolean isDir, String nativeURL) {
+    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Uri nativeURL) {
         try {
-            JSONObject entry = new JSONObject();
-
+            String path = inputURL.path;
             int end = path.endsWith("/") ? 1 : 0;
             String[] parts = path.substring(0, path.length() - end).split("/+");
             String fileName = parts[parts.length - 1];
-            entry.put("isFile", !isDir);
-            entry.put("isDirectory", isDir);
+
+            JSONObject entry = new JSONObject();
+            entry.put("isFile", !inputURL.isDirectory);
+            entry.put("isDirectory", inputURL.isDirectory);
             entry.put("name", fileName);
             entry.put("fullPath", path);
             // The file system can't be specified, as it would lead to an infinite loop,
             // but the filesystem name can be.
-            entry.put("filesystemName", fsName);
+            entry.put("filesystemName", inputURL.fsName);
             // Backwards compatibility
-            entry.put("filesystem", "temporary".equals(fsName) ? 0 : 1);
+            entry.put("filesystem", "temporary".equals(inputURL.fsName) ? 0 : 1);
 
-            if (isDir && !nativeURL.endsWith("/")) {
-                nativeURL += "/";
+            String nativeUrlStr = nativeURL.toString();
+            if (inputURL.isDirectory && !nativeUrlStr.endsWith("/")) {
+                nativeUrlStr += "/";
             }
-            entry.put("nativeURL", nativeURL);
+            entry.put("nativeURL", nativeUrlStr);
             return entry;
         } catch (JSONException e) {
             e.printStackTrace();
@@ -78,13 +80,21 @@ public abstract class Filesystem {
         }
     }
 
-    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Boolean isDir, Uri nativeURL) {
-        return makeEntryForPath(inputURL.pathAndQuery, inputURL.fsName, isDir, nativeURL.toString());
+    public JSONObject makeEntryForURL(LocalFilesystemURL inputURL) {
+        Uri nativeUri = toNativeUri(inputURL);
+        return makeEntryForURL(inputURL, nativeUri);
+    }
+
+    public JSONObject makeEntryForNativeUri(Uri nativeUri) {
+        LocalFilesystemURL inputUrl = toLocalUri(nativeUri);
+        return makeEntryForURL(inputUrl, nativeUri);
     }
 
-	abstract JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException;
+    public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
+        return makeEntryForURL(inputURL);
+    }
 
-	abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path,
+    abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path,
 			JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException;
 
 	abstract boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException;
@@ -99,6 +109,9 @@ public abstract class Filesystem {
         return rootUri;
     }
 
+    public abstract Uri toNativeUri(LocalFilesystemURL inputURL);
+    public abstract LocalFilesystemURL toLocalUri(Uri inputURL);
+
     public JSONObject getRootEntry() {
         return rootEntry;
     }
@@ -126,57 +139,60 @@ public abstract class Filesystem {
         }
         return LocalFilesystemURL.parse(newDest);
     }
-    
+
 	/* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to
 	 * the destination URL on this filesystem, optionally with a new filename.
 	 * If move is true, then this method should either perform an atomic move operation
 	 * or remove the source file when finished.
 	 */
-    JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
+    public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
             Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
-        // This is "the hard way" -- transfer data between arbitrary filesystem urls/
-        // Gets an input stream from src, and writes its contents to an output stream
-        // from dest.
-
         // First, check to see that we can do it
-        if (!move || srcFs.canRemoveFileAtLocalURL(srcURL)) {
-            final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL);
-            srcFs.readFileAtURL(srcURL, 0, -1, new ReadFileCallback() {
-                public void handleData(InputStream inputStream, String contentType) throws IOException {
-                    if (inputStream != null) {
-                        //write data to file
-                        OutputStream os = getOutputStreamForURL(destination);
-                        final int BUFFER_SIZE = 8192;
-                        byte[] buffer = new byte[BUFFER_SIZE];
-
-                        for (;;) {
-                            int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
-
-                            if (bytesRead <= 0) {
-                                break;
-                            }
-                            os.write(buffer, 0, bytesRead);
-                        }
-                        os.close();
-                    } else {
-                        throw new IOException("Cannot read file at source URL");
-                    }
-                }
-            });
-            if (move) {
-                // Delete original
-                srcFs.removeFileAtLocalURL(srcURL);
-            }
-            return getEntryForLocalURL(destination);
-        } else {
+        if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
             throw new NoModificationAllowedException("Cannot move file at source URL");
         }
+        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL);
+
+        Uri srcNativeUri = srcFs.toNativeUri(srcURL);
+
+        CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcNativeUri);
+        OutputStream os = null;
+        try {
+            os = getOutputStreamForURL(destination);
+        } catch (IOException e) {
+            ofrr.inputStream.close();
+            throw e;
+        }
+        // Closes streams.
+        resourceApi.copyResource(ofrr, os);
+
+        if (move) {
+            srcFs.removeFileAtLocalURL(srcURL);
+        }
+        return getEntryForLocalURL(destination);
     }
 
-    abstract OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException;
+    public OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException {
+        return resourceApi.openOutputStream(toNativeUri(inputURL));
+    }
 
-    abstract void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
-			ReadFileCallback readFileCallback) throws IOException;
+    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
+                              ReadFileCallback readFileCallback) throws IOException {
+        CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(toNativeUri(inputURL));
+        if (end < 0) {
+            end = ofrr.length;
+        }
+        long numBytesToRead = end - start;
+        try {
+            if (start > 0) {
+                ofrr.inputStream.skip(start);
+            }
+            LimitedInputStream inputStream = new LimitedInputStream(ofrr.inputStream, numBytesToRead);
+            readFileCallback.handleData(inputStream, ofrr.mimeType);
+        } finally {
+            ofrr.inputStream.close();
+        }
+    }
 
 	abstract long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset,
 			boolean isBinary) throws NoModificationAllowedException, IOException;

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 805eacd..2754b41 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -24,14 +24,11 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.apache.cordova.CordovaInterface;
 import org.apache.cordova.CordovaResourceApi;
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -41,13 +38,12 @@ import android.util.Base64;
 import android.net.Uri;
 import android.content.Context;
 import android.content.Intent;
-import android.app.Activity;
 
 public class LocalFilesystem extends Filesystem {
     private final Context context;
 
     public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, String rootPath) {
-        this(name, context, resourceApi, Uri.fromFile(new File(rootPath)));
+        this(name, context, resourceApi, Uri.fromFile(new File(rootPath)).buildUpon().appendPath("").build());
     }
 	public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, Uri rootUri) {
         super(rootUri, name, resourceApi);
@@ -55,50 +51,91 @@ public class LocalFilesystem extends Filesystem {
 	}
 
     public String filesystemPathForFullPath(String fullPath) {
-	    String path = new File(rootUri.getPath(), fullPath).toString();
-        int questionMark = path.indexOf("?");
-        if (questionMark >= 0) {
-          path = path.substring(0, questionMark);
-        }
-	    if (path.length() > 1 && path.endsWith("/")) {
-	      path = path.substring(0, path.length()-1);
-	    }
-	    return path;
+	    return new File(rootUri.getPath(), fullPath).toString();
 	}
 	
 	@Override
 	public String filesystemPathForURL(LocalFilesystemURL url) {
-		return filesystemPathForFullPath(url.pathAndQuery);
+		return filesystemPathForFullPath(url.path);
 	}
 
 	private String fullPathForFilesystemPath(String absolutePath) {
 		if (absolutePath != null && absolutePath.startsWith(rootUri.getPath())) {
-			return absolutePath.substring(rootUri.getPath().length());
+			return absolutePath.substring(rootUri.getPath().length() - 1);
 		}
 		return null;
 	}
 
+    private Uri nativeUriForFullPath(String fullPath) {
+        Uri ret = null;
+        if (fullPath != null) {
+            String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath();
+            if (encodedPath.startsWith("/")) {
+                encodedPath = encodedPath.substring(1);
+            }
+            ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build();
+        }
+        return ret;
+    }
+
 	protected LocalFilesystemURL URLforFullPath(String fullPath) {
-	    if (fullPath != null) {
-	    	if (fullPath.startsWith("/")) {
-	    		return LocalFilesystemURL.parse(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+fullPath);
-	    	}
-	        return LocalFilesystemURL.parse(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+"/"+fullPath);
+        Uri nativeUri = nativeUriForFullPath(fullPath);
+	    if (nativeUri != null) {
+            return toLocalUri(nativeUri);
 	    }
 	    return null;
-		
 	}
+
+    @Override
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        return nativeUriForFullPath(inputURL.path);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"file".equals(inputURL.getScheme())) {
+            return null;
+        }
+        File f = new File(inputURL.getPath());
+        // Removes and duplicate /s (e.g. file:///a//b/c)
+        Uri resolvedUri = Uri.fromFile(f);
+        String rootUriNoTrailingSlash = rootUri.getEncodedPath();
+        rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
+        if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
+            return null;
+        }
+        String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
+        // Strip leading slash
+        if (!subPath.isEmpty()) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name);
+        if (!subPath.isEmpty()) {
+            b.appendEncodedPath(subPath);
+        }
+        if (f.isDirectory() || inputURL.getPath().endsWith("/")) {
+            // Add trailing / for directories.
+            b.appendEncodedPath("");
+        }
+        return LocalFilesystemURL.parse(b.build());
+    }
 	
 	@Override
 	public LocalFilesystemURL URLforFilesystemPath(String path) {
 	    return this.URLforFullPath(this.fullPathForFilesystemPath(path));
 	}
 
+    /**
+     * Removes multiple repeated //s, and collapses processes ../s.
+     */
 	protected String normalizePath(String rawPath) {
 	    // If this is an absolute path, trim the leading "/" and replace it later
 	    boolean isAbsolutePath = rawPath.startsWith("/");
 	    if (isAbsolutePath) {
-	        rawPath = rawPath.substring(1);
+	        rawPath = rawPath.replaceFirst("/+", "");
 	    }
 	    ArrayList<String> components = new ArrayList<String>(Arrays.asList(rawPath.split("/+")));
 	    for (int index = 0; index < components.size(); ++index) {
@@ -120,18 +157,12 @@ public class LocalFilesystem extends Filesystem {
 	    } else {
 	    	return normalizedPath.toString().substring(1);
 	    }
-
-
 	}
 
 	
 	@Override
-    public JSONObject makeEntryForFile(File file) throws JSONException {
-    	String path = this.fullPathForFilesystemPath(file.getAbsolutePath());
-    	if (path != null) {
-    		return makeEntryForPath(path, this.name, file.isDirectory(), Uri.fromFile(file).toString());
-    	}
-    	return null;
+    public JSONObject makeEntryForFile(File file) {
+        return makeEntryForNativeUri(Uri.fromFile(file));
     }
 
 	@Override
@@ -144,7 +175,7 @@ public class LocalFilesystem extends Filesystem {
       if (!fp.canRead()) {
           throw new IOException();
       }
-      return LocalFilesystem.makeEntryForURL(inputURL, fp.isDirectory(),  Uri.fromFile(fp));
+      return super.getEntryForLocalURL(inputURL);
 	}
 
 	@Override
@@ -168,10 +199,13 @@ public class LocalFilesystem extends Filesystem {
         LocalFilesystemURL requestedURL;
         
         // Check whether the supplied path is absolute or relative
+        if (directory && !path.endsWith("/")) {
+            path += "/";
+        }
         if (path.startsWith("/")) {
-        	requestedURL = URLforFilesystemPath(path);
+        	requestedURL = URLforFilesystemPath(normalizePath(path));
         } else {
-        	requestedURL = URLforFullPath(normalizePath(inputURL.pathAndQuery + "/" + path));
+        	requestedURL = URLforFullPath(normalizePath(inputURL.path + "/" + path));
         }
         
         File fp = new File(this.filesystemPathForURL(requestedURL));
@@ -205,7 +239,7 @@ public class LocalFilesystem extends Filesystem {
         }
 
         // Return the directory
-        return makeEntryForPath(requestedURL.pathAndQuery, requestedURL.fsName, directory, Uri.fromFile(fp).toString());
+        return makeEntryForURL(requestedURL);
 	}
 
 	@Override
@@ -256,7 +290,7 @@ public class LocalFilesystem extends Filesystem {
             File[] files = fp.listFiles();
             for (int i = 0; i < files.length; i++) {
                 if (files[i].canRead()) {
-                    entries.put(makeEntryForPath(fullPathForFilesystemPath(files[i].getAbsolutePath()), inputURL.fsName, files[i].isDirectory(), Uri.fromFile(files[i]).toString()));
+                    entries.put(makeEntryForFile(files[i]));
                 }
             }
         }
@@ -278,7 +312,7 @@ public class LocalFilesystem extends Filesystem {
         	metadata.put("size", file.isDirectory() ? 0 : file.length());
         	metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file)));
         	metadata.put("name", file.getName());
-        	metadata.put("fullPath", inputURL.pathAndQuery);
+        	metadata.put("fullPath", inputURL.path);
         	metadata.put("lastModifiedDate", file.lastModified());
         } catch (JSONException e) {
         	return null;
@@ -514,30 +548,6 @@ public class LocalFilesystem extends Filesystem {
             return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
     	}
 	}
-
-	@Override
-    public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
-			ReadFileCallback readFileCallback) throws IOException {
-
-		File file = new File(this.filesystemPathForURL(inputURL));
-        String contentType = resourceApi.getMimeType(Uri.fromFile(file));
-		
-        if (end < 0) {
-            end = file.length();
-        }
-        long numBytesToRead = end - start;
-
-        InputStream rawInputStream = new FileInputStream(file);
-		try {
-			if (start > 0) {
-                rawInputStream.skip(start);
-			}
-            LimitedInputStream inputStream = new LimitedInputStream(rawInputStream, numBytesToRead);
-            readFileCallback.handleData(inputStream, contentType);
-		} finally {
-            rawInputStream.close();
-		}
-	}
     
 	@Override
 	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
@@ -624,13 +634,4 @@ public class LocalFilesystem extends Filesystem {
 		File file = new File(path);
 		return file.exists();
 	}
-
-	@Override
-	OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
-		String path = filesystemPathForURL(inputURL);
-		File file = new File(path);
-		FileOutputStream os = new FileOutputStream(file);
-		return os;
-	}
-
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/src/android/LocalFilesystemURL.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystemURL.java b/src/android/LocalFilesystemURL.java
index 473b587..b96b6ee 100644
--- a/src/android/LocalFilesystemURL.java
+++ b/src/android/LocalFilesystemURL.java
@@ -18,8 +18,6 @@
  */
 package org.apache.cordova.file;
 
-import java.util.List;
-
 import android.net.Uri;
 
 public class LocalFilesystemURL {
@@ -28,29 +26,32 @@ public class LocalFilesystemURL {
 
     public final Uri uri;
     public final String fsName;
-    public final String pathAndQuery;
+    public final String path;
+    public final boolean isDirectory;
 
-	private LocalFilesystemURL(Uri uri, String fsName, String fsPath) {
+	private LocalFilesystemURL(Uri uri, String fsName, String fsPath, boolean isDirectory) {
 		this.uri = uri;
         this.fsName = fsName;
-        this.pathAndQuery = fsPath;
+        this.path = fsPath;
+        this.isDirectory = isDirectory;
 	}
 
     public static LocalFilesystemURL parse(Uri uri) {
         if (!FILESYSTEM_PROTOCOL.equals(uri.getScheme())) {
             return null;
         }
-        List<String> pathComponents = uri.getPathSegments();
-        if (pathComponents == null || pathComponents.size() == 0) {
+        String path = uri.getPath();
+        if (path.length() < 1) {
             return null;
         }
-        String fsName = pathComponents.get(0);
-        String pathAndQuery = uri.getPath();
-        pathAndQuery = pathAndQuery.substring(pathAndQuery.indexOf('/', 1));
-        if (uri.getQuery() != null) {
-            pathAndQuery = pathAndQuery + "?" + uri.getQuery();
+        int firstSlashIdx = path.indexOf('/', 1);
+        if (firstSlashIdx < 0) {
+            return null;
         }
-        return new LocalFilesystemURL(uri, fsName, pathAndQuery);
+        String fsName = path.substring(1, firstSlashIdx);
+        path = path.substring(firstSlashIdx);
+        boolean isDirectory = path.charAt(path.length() - 1) == '/';
+        return new LocalFilesystemURL(uri, fsName, path, isDirectory);
     }
 
     public static LocalFilesystemURL parse(String uri) {

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/tests/plugin.xml
----------------------------------------------------------------------
diff --git a/tests/plugin.xml b/tests/plugin.xml
index ba1b01c..80adb4e 100644
--- a/tests/plugin.xml
+++ b/tests/plugin.xml
@@ -29,4 +29,14 @@
 
     <js-module src="tests.js" name="tests">
     </js-module>
+
+    <platform name="android">
+        <source-file src="src/android/TestContentProvider.java" target-dir="src/org/apache/cordova/file/test" />
+        <config-file target="AndroidManifest.xml" parent="/*/application">
+            <provider
+                android:name="org.apache.cordova.file.test.TestContentProvider"
+                android:authorities="org.apache.cordova.file.testprovider"
+                android:exported="false" />
+        </config-file>
+    </platform>
 </plugin>

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/tests/src/android/TestContentProvider.java
----------------------------------------------------------------------
diff --git a/tests/src/android/TestContentProvider.java b/tests/src/android/TestContentProvider.java
new file mode 100644
index 0000000..1aa4783
--- /dev/null
+++ b/tests/src/android/TestContentProvider.java
@@ -0,0 +1,78 @@
+package org.apache.cordova.file.test;
+
+import android.content.ContentProvider;
+import android.net.Uri;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.os.ParcelFileDescriptor;
+
+import org.apache.cordova.CordovaResourceApi;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+public class TestContentProvider extends ContentProvider {
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        String fileName = uri.getQueryParameter("realPath");
+        if (fileName == null) {
+            fileName = uri.getPath();
+        }
+        if (fileName == null || fileName.length() < 1) {
+            throw new FileNotFoundException();
+        }
+        CordovaResourceApi resourceApi = new CordovaResourceApi(getContext(), null);
+        try {
+            File f = File.createTempFile("test-content-provider", ".tmp");
+            resourceApi.copyResource(Uri.parse("file:///android_asset" + fileName), Uri.fromFile(f));
+            FileInputStream fis = new FileInputStream(f);
+            String thisIsDumb = fis.getFD().toString();
+            int fd = Integer.parseInt(thisIsDumb.substring("FileDescriptor[".length(), thisIsDumb.length() - 1));
+            return ParcelFileDescriptor.adoptFd(fd);
+        } catch (FileNotFoundException e) {
+            throw e;
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new FileNotFoundException("IO error: " + e.toString());
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        return false;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "text/html";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index 1478aaf..adaa9ab 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -2090,8 +2090,7 @@ exports.defineAutoTests = function () {
                             expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
                         }
                         // cleanup
-                        deleteEntry(file1);
-                        done();
+                        deleteEntry(file1, done);
                     });
                 }, failed.bind(null, done, 'createFile - Error creating file: ' + file1));
             });
@@ -2904,8 +2903,7 @@ exports.defineAutoTests = function () {
                         expect(fileEntry.name).toBe(fileName);
                         expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath +'/' + fileName);
                         // cleanup
-                        deleteEntry(fileName);
-                        done();
+                        deleteEntry(fileName, done);
                     }, failed.bind(null, done, 'root.getFile - Error getting file: ../' + fileName));
                 }, failed.bind(null, done, 'createFile - Error creating file: ../' + fileName));
             });
@@ -3131,8 +3129,7 @@ exports.defineAutoTests = function () {
                         : expect(entry.filesystem.name).toEqual("persistent");
                     // cleanup
                     deleteEntry(entry.name);
-                    deleteEntry(sourceEntry.name);
-                    done();
+                    deleteEntry(sourceEntry.name, done);
                 },
                 createSourceAndTransfer = function () {
                     temp_root.getFile(file1, {
@@ -3166,8 +3163,7 @@ exports.defineAutoTests = function () {
                         : expect(entry.filesystem.name).toEqual("temporary");
                     // cleanup
                     deleteEntry(entry.name);
-                    deleteEntry(sourceEntry.name);
-                    done();
+                    deleteEntry(sourceEntry.name, done);
                 },
                 createSourceAndTransfer = function () {
                     persistent_root.getFile(file1, {
@@ -3204,8 +3200,7 @@ exports.defineAutoTests = function () {
                         : expect(entry.filesystem.name).toEqual("persistent");
                     // cleanup
                     deleteEntry(entry.name);
-                    deleteEntry(sourceEntry.name);
-                    done();
+                    deleteEntry(sourceEntry.name, done);
                 },
                 createSourceAndTransfer = function () {
                     temp_root.getFile(file1, {
@@ -3239,8 +3234,7 @@ exports.defineAutoTests = function () {
                         : expect(entry.filesystem.name).toEqual("temporary");
                     // cleanup
                     deleteEntry(entry.name);
-                    deleteEntry(sourceEntry.name);
-                    done();
+                    deleteEntry(sourceEntry.name, done);
                 },
                 createSourceAndTransfer = function () {
                     persistent_root.getFile(file1, {
@@ -3314,8 +3308,7 @@ exports.defineAutoTests = function () {
                     expect(directory.name).toCanonicallyMatch(nestedName);
                     expect(directory.fullPath).toCanonicallyMatch('/' + path + '/');
                     deleteEntry(directory.name);
-                    deleteEntry(parentName);
-                    done();
+                    deleteEntry(parentName, done);
                 };
 
                 createDirectory(parentName, function() {
@@ -3334,8 +3327,7 @@ exports.defineAutoTests = function () {
                     expect(fileEntry.isFile).toBe(true);
                     expect(fileEntry.isDirectory).toBe(false);
                     expect(fileEntry.name).toCanonicallyMatch(secondFileName);
-                    deleteEntry(fileEntry.name);
-                    done();
+                    deleteEntry(fileEntry.name, done);
                 };
 
                 createFile(deletedFileName, function (deletedFile) {
@@ -3359,8 +3351,7 @@ exports.defineAutoTests = function () {
                     expect(directory.isFile).toBe(false);
                     expect(directory.isDirectory).toBe(true);
                     expect(directory.name).toCanonicallyMatch(secondDirName);
-                    deleteEntry(directory.name);
-                    done();
+                    deleteEntry(directory.name, done);
                 };
 
                 createDirectory(deletedDirName, function (deletedDir) {
@@ -3383,8 +3374,7 @@ exports.defineAutoTests = function () {
                     expect(directory.isFile).toBe(false);
                     expect(directory.isDirectory).toBe(true);
                     expect(directory.name).toCanonicallyMatch(parentName);
-                    deleteEntry(directory.name);
-                    done();
+                    deleteEntry(directory.name, done);
                 };
 
                 createDirectory(parentName, function(parent){
@@ -3405,8 +3395,7 @@ exports.defineAutoTests = function () {
                     expect(directory.isFile).toBe(false);
                     expect(directory.isDirectory).toBe(true);
                     expect(directory.name).toCanonicallyMatch(dirName);
-                    deleteEntry(directory.name);
-                    done();
+                    deleteEntry(directory.name, done);
                 };
 
                 createDirectory(dirName, function(){
@@ -3415,9 +3404,47 @@ exports.defineAutoTests = function () {
                 }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + dirName));
             });
         });
-        // IndexedDB-based impl
+        // Content and Asset URLs
+        if (cordova.platformId == 'android') {
+            describe('content: URLs', function() {
+                function testContentCopy(src, done) {
+                    var file2 = "entry.copy.file2b",
+                    fullPath = joinURL(temp_root.fullPath, file2),
+                    validateFile = function (entry) {
+                        expect(entry.isFile).toBe(true);
+                        expect(entry.isDirectory).toBe(false);
+                        expect(entry.name).toCanonicallyMatch(file2);
+                        expect(entry.fullPath).toCanonicallyMatch(fullPath);
+                        expect(entry.filesystem.name).toEqual("temporary");
+                        // cleanup
+                        deleteEntry(entry.name, done);
+                    },
+                    transfer = function () {
+                        resolveLocalFileSystemURL(src, function(entry) {
+                            expect(entry).toBeDefined();
+                            expect(entry.filesystem.name).toEqual("content");
+                            entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2));
+                        }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider'));
+                    };
+                    // Delete any existing file to start things off
+                    temp_root.getFile(file2, {}, function (entry) {
+                        entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
+                    }, transfer);
+                }
+                it("file.spec.138 copyTo: content", function(done) {
+                    testContentCopy('content://org.apache.cordova.file.testprovider/www/index.html', done);
+                });
+                it("file.spec.139 copyTo: content /w space and query", function(done) {
+                    testContentCopy('content://org.apache.cordova.file.testprovider/?name=foo%20bar&realPath=%2Fwww%2Findex.html', done);
+                });
+                it("file.spec.140 delete: content should fail", function(done) {
+                    resolveLocalFileSystemURL('content://org.apache.cordova.file.testprovider/www/index.html', function(entry) {
+                        entry.remove(failed.bind(null, done, 'expected delete to fail'), done);
+                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider'));
+                });
+            });
+        }
     });
-    //File API describe
 
 };
 //******************************************************************************************

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/www/Entry.js
----------------------------------------------------------------------
diff --git a/www/Entry.js b/www/Entry.js
index 12f6227..c23f8e2 100644
--- a/www/Entry.js
+++ b/www/Entry.js
@@ -180,7 +180,7 @@ Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallbac
  */
 Entry.prototype.toInternalURL = function() {
     if (this.filesystem && this.filesystem.__format__) {
-      return this.filesystem.__format__(this.fullPath);
+      return this.filesystem.__format__(this.fullPath, this.nativeURL);
     }
 };
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/www/FileSystem.js
----------------------------------------------------------------------
diff --git a/www/FileSystem.js b/www/FileSystem.js
index efa6740..36bffbb 100644
--- a/www/FileSystem.js
+++ b/www/FileSystem.js
@@ -37,7 +37,7 @@ var FileSystem = function(name, root) {
     }
 };
 
-FileSystem.prototype.__format__ = function(fullPath) {
+FileSystem.prototype.__format__ = function(fullPath, nativeUrl) {
     return fullPath;
 };
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/d6202261/www/android/FileSystem.js
----------------------------------------------------------------------
diff --git a/www/android/FileSystem.js b/www/android/FileSystem.js
index fde9c7a..518e4c4 100644
--- a/www/android/FileSystem.js
+++ b/www/android/FileSystem.js
@@ -22,12 +22,15 @@
 FILESYSTEM_PROTOCOL = "cdvfile";
 
 module.exports = {
-    __format__: function(fullPath) {
-        if (this.name === 'content') {
-            return 'content:/' + fullPath;
+    __format__: function(fullPath, nativeUrl) {
+        var path = '/' + this.name + '/' + encodeURI(fullPath);
+        path = path.replace('//','/');
+        var ret = FILESYSTEM_PROTOCOL + '://localhost' + path;
+        var m = /\?.*/.exec(nativeUrl);
+        if (m) {
+          ret += m[0];
         }
-        var path = ('/'+this.name+(fullPath[0]==='/'?'':'/')+encodeURI(fullPath)).replace('//','/');
-        return FILESYSTEM_PROTOCOL + '://localhost' + path;
+        return ret;
     }
 };
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[07/13] cordova-plugin-file git commit: android: Move CordovaResourceApi into Filesystem base class

Posted by ag...@apache.org.
android: Move CordovaResourceApi into Filesystem base class


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/bad4242a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/bad4242a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/bad4242a

Branch: refs/heads/master
Commit: bad4242a304ad883144856417d81d972669a42ba
Parents: 81ea13c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 14:22:04 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/ContentFilesystem.java | 33 +++++++--------------------------
 src/android/FileUtils.java         |  2 +-
 src/android/Filesystem.java        |  5 ++++-
 src/android/LocalFilesystem.java   |  5 +----
 4 files changed, 13 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/bad4242a/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index f577054..3e967f3 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -36,6 +36,7 @@ import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.ContentResolver;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore;
@@ -43,31 +44,11 @@ import android.provider.OpenableColumns;
 
 public class ContentFilesystem extends Filesystem {
 
-	private CordovaInterface cordova;
-	private CordovaResourceApi resourceApi;
-	
-	public ContentFilesystem(CordovaInterface cordova, CordovaWebView webView) {
-		super(Uri.parse("content://"), "content");
-		this.cordova = cordova;
+    private final Context context;
 
-		Class webViewClass = webView.getClass();
-		PluginManager pm = null;
-		try {
-			Method gpm = webViewClass.getMethod("getPluginManager");
-			pm = (PluginManager) gpm.invoke(webView);
-		} catch (NoSuchMethodException e) {
-		} catch (IllegalAccessException e) {
-		} catch (InvocationTargetException e) {
-		}
-		if (pm == null) {
-			try {
-				Field pmf = webViewClass.getField("pluginManager");
-				pm = (PluginManager)pmf.get(webView);
-			} catch (NoSuchFieldException e) {
-			} catch (IllegalAccessException e) {
-			}
-		}
-		this.resourceApi = new CordovaResourceApi(webView.getContext(), pm);
+	public ContentFilesystem(Context context, CordovaResourceApi resourceApi) {
+		super(Uri.parse("content://"), "content", resourceApi);
+        this.context = context;
 	}
 	
 	@Override
@@ -130,7 +111,7 @@ public class ContentFilesystem extends Filesystem {
 		String filePath = filesystemPathForURL(inputURL);
 		File file = new File(filePath);
 		try {
-			this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+            context.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
 					MediaStore.Images.Media.DATA + " = ?",
 					new String[] { filePath });
 		} catch (UnsupportedOperationException t) {
@@ -246,7 +227,7 @@ public class ContentFilesystem extends Filesystem {
 	}
 
 	protected Cursor openCursorForURL(LocalFilesystemURL url) {
-        ContentResolver contentResolver = this.cordova.getActivity().getContentResolver();
+        ContentResolver contentResolver = context.getContentResolver();
         Cursor cursor = contentResolver.query(url.URL, null, null, null, null);
         return cursor;
 	}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/bad4242a/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 0063b43..043bdca 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -194,7 +194,7 @@ public class FileUtils extends CordovaPlugin {
     		// per spec.
     		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tempRoot));
     		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRoot));
-    		this.registerFilesystem(new ContentFilesystem(cordova, webView));
+    		this.registerFilesystem(new ContentFilesystem(webView.getContext(), webView.getResourceApi()));
 
             registerExtraFileSystems(getExtraFileSystemsPreference(activity), getAvailableFileSystems(activity));
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/bad4242a/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index c4a0f8a..d1cbc27 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.cordova.CordovaResourceApi;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -34,12 +35,14 @@ import org.json.JSONObject;
 public abstract class Filesystem {
 
     protected final Uri rootUri;
+    protected final CordovaResourceApi resourceApi;
     public final String name;
     private final JSONObject rootEntry;
 
-    public Filesystem(Uri rootUri, String name) {
+    public Filesystem(Uri rootUri, String name, CordovaResourceApi resourceApi) {
         this.rootUri = rootUri;
         this.name = name;
+        this.resourceApi = resourceApi;
         rootEntry = makeEntryForPath("/", name, true, rootUri.toString());
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/bad4242a/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 884771c..544663d 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -44,17 +44,14 @@ import android.content.Intent;
 import android.app.Activity;
 
 public class LocalFilesystem extends Filesystem {
-
-    private final CordovaResourceApi resourceApi;
     private final Context context;
 
     public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, String rootPath) {
         this(name, context, resourceApi, Uri.fromFile(new File(rootPath)));
     }
 	public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, Uri rootUri) {
-        super(rootUri, name);
+        super(rootUri, name, resourceApi);
 		this.context = context;
-        this.resourceApi = resourceApi;
 	}
 
     public String filesystemPathForFullPath(String fullPath) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[03/13] cordova-plugin-file git commit: android: Ensure LocalFilesystemURL can only be created with "cdvfile" URLs

Posted by ag...@apache.org.
android: Ensure LocalFilesystemURL can only be created with "cdvfile" URLs


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/8f7b013b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/8f7b013b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/8f7b013b

Branch: refs/heads/master
Commit: 8f7b013baad2545eb7ed83e12ad924d354c5f1b2
Parents: bad4242
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 14:44:32 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/ContentFilesystem.java  | 48 +++++++++-------------
 src/android/FileUtils.java          | 38 +++++++++---------
 src/android/Filesystem.java         | 22 +++++-----
 src/android/LocalFilesystem.java    | 20 ++++-----
 src/android/LocalFilesystemURL.java | 69 ++++++++++++++------------------
 5 files changed, 88 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/8f7b013b/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index 3e967f3..a4a2227 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -53,28 +53,20 @@ public class ContentFilesystem extends Filesystem {
 	
 	@Override
 	public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-	    if ("/".equals(inputURL.fullPath)) {
-            return LocalFilesystem.makeEntryForURL(inputURL, true, inputURL.URL.toString());
+	    if ("/".equals(inputURL.uri.getPath())) {
+            return LocalFilesystem.makeEntryForURL(inputURL, true, inputURL.uri);
 	    }
 
 		// Get the cursor to validate that the file exists
 		Cursor cursor = openCursorForURL(inputURL);
-		String filePath = null;
-		try {
-			if (cursor == null || !cursor.moveToFirst()) {
-				throw new FileNotFoundException();
-			}
-			filePath = filesystemPathForCursor(cursor);
-		} finally {
-			if (cursor != null)
-				cursor.close();
-		}
-		if (filePath == null) {
-			filePath = inputURL.URL.toString();
+		File file = resourceApi.mapUriToFile(inputURL.uri);
+        Uri nativeUrl;
+		if (file == null) {
+            nativeUrl = inputURL.uri;
 		} else {
-			filePath = "file://" + filePath;
+            nativeUrl = Uri.fromFile(file);
 		}
-        return makeEntryForPath(inputURL.fullPath, inputURL.filesystemName, false /*fp.isDirectory()*/, filePath);
+        return makeEntryForURL(inputURL, false /*fp.isDirectory()*/, nativeUrl);
 	}
 	
     @Override
@@ -85,7 +77,7 @@ public class ContentFilesystem extends Filesystem {
         		throw new IOException("Cannot create content url");
             }
         }
-        LocalFilesystemURL requestedURL = new LocalFilesystemURL(Uri.withAppendedPath(inputURL.URL, fileName));
+        LocalFilesystemURL requestedURL = LocalFilesystemURL.parse(Uri.withAppendedPath(inputURL.uri, fileName));
         File fp = new File(this.filesystemPathForURL(requestedURL));
         if (!fp.exists()) {
             throw new FileNotFoundException("path does not exist");
@@ -100,7 +92,7 @@ public class ContentFilesystem extends Filesystem {
             }
         }
         // Return the directory
-        return makeEntryForPath(requestedURL.fullPath, requestedURL.filesystemName, directory, Uri.fromFile(fp).toString());
+        return makeEntryForURL(requestedURL, directory, Uri.fromFile(fp));
 
 	}
 
@@ -155,9 +147,9 @@ public class ContentFilesystem extends Filesystem {
         JSONObject metadata = new JSONObject();
         try {
         	metadata.put("size", size);
-        	metadata.put("type", resourceApi.getMimeType(inputURL.URL));
-        	metadata.put("name", inputURL.filesystemName);
-        	metadata.put("fullPath", inputURL.fullPath);
+        	metadata.put("type", resourceApi.getMimeType(inputURL.uri));
+        	metadata.put("name", name);
+        	metadata.put("fullPath", inputURL.pathAndQuery);
         	metadata.put("lastModifiedDate", lastModified);
         } catch (JSONException e) {
         	return null;
@@ -175,8 +167,8 @@ public class ContentFilesystem extends Filesystem {
             // Figure out where we should be copying to
             final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL);
 
-            OutputStream os = resourceApi.openOutputStream(destURL.URL);
-            CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcURL.URL);
+            OutputStream os = resourceApi.openOutputStream(destURL.uri);
+            CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcURL.uri);
             if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
                 throw new NoModificationAllowedException("Cannot move file at source URL");
             }
@@ -188,7 +180,7 @@ public class ContentFilesystem extends Filesystem {
             if (move) {
                 srcFs.removeFileAtLocalURL(srcURL);
             }
-            return makeEntryForURL(destinationURL, false, destinationURL.URL.toString());
+            return makeEntryForURL(destinationURL, false, destinationURL.uri);
         } else {
             // Need to copy the hard way
             return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
@@ -199,7 +191,7 @@ public class ContentFilesystem extends Filesystem {
 	@Override
     public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
 			ReadFileCallback readFileCallback) throws IOException {
-		CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(inputURL.URL);
+		CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(inputURL.uri);
         if (end < 0) {
             end = ofrr.length;
         }
@@ -228,7 +220,7 @@ public class ContentFilesystem extends Filesystem {
 
 	protected Cursor openCursorForURL(LocalFilesystemURL url) {
         ContentResolver contentResolver = context.getContentResolver();
-        Cursor cursor = contentResolver.query(url.URL, null, null, null, null);
+        Cursor cursor = contentResolver.query(url.uri, null, null, null, null);
         return cursor;
 	}
 
@@ -257,7 +249,7 @@ public class ContentFilesystem extends Filesystem {
 
     @Override
     public String filesystemPathForURL(LocalFilesystemURL url) {
-        File f = resourceApi.mapUriToFile(url.URL);
+        File f = resourceApi.mapUriToFile(url.uri);
         return f == null ? null : f.getAbsolutePath();
     }
 
@@ -277,7 +269,7 @@ public class ContentFilesystem extends Filesystem {
 	@Override
 	OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL)
 			throws IOException {
-		OutputStream os = resourceApi.openOutputStream(inputURL.URL);
+		OutputStream os = resourceApi.openOutputStream(inputURL.uri);
 		return os;
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/8f7b013b/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 043bdca..2a1e965 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -214,7 +214,7 @@ public class FileUtils extends CordovaPlugin {
 
 	private Filesystem filesystemForURL(LocalFilesystemURL localURL) {
     	if (localURL == null) return null;
-    	return filesystemForName(localURL.filesystemName);
+    	return filesystemForName(localURL.fsName);
     }
     
     @Override
@@ -224,7 +224,7 @@ public class FileUtils extends CordovaPlugin {
             return null;
         }
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(uri);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(uri);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		return null;
@@ -511,7 +511,7 @@ public class FileUtils extends CordovaPlugin {
 
     public String filesystemPathForURL(String localURLstr) throws MalformedURLException {
         try {
-            LocalFilesystemURL inputURL = new LocalFilesystemURL(localURLstr);
+            LocalFilesystemURL inputURL = LocalFilesystemURL.parse(localURLstr);
             Filesystem fs = this.filesystemForURL(inputURL);
             if (fs == null) {
                 throw new MalformedURLException("No installed handlers for this URL");
@@ -534,9 +534,9 @@ public class FileUtils extends CordovaPlugin {
                 if (url != null) {
                     // A shorter fullPath implies that the filesystem is a better
                     // match for the local path than the previous best.
-                    if (localURL == null || (url.fullPath.length() < shortestFullPath)) {
+                    if (localURL == null || (url.pathAndQuery.length() < shortestFullPath)) {
                         localURL = url;
-                        shortestFullPath = url.fullPath.length();
+                        shortestFullPath = url.pathAndQuery.length();
                     }
                 }
             }
@@ -603,7 +603,7 @@ public class FileUtils extends CordovaPlugin {
             String path = uri.getPath();
     		inputURL = this.filesystemURLforLocalPath(path);
     	} else {
-    		inputURL = new LocalFilesystemURL(uri);
+    		inputURL = LocalFilesystemURL.parse(uri);
     	}
 
         try {
@@ -627,7 +627,7 @@ public class FileUtils extends CordovaPlugin {
      */
     private JSONArray readEntries(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -658,8 +658,8 @@ public class FileUtils extends CordovaPlugin {
         	throw new FileNotFoundException();
         }
 
-        LocalFilesystemURL srcURL = new LocalFilesystemURL(srcURLstr);
-        LocalFilesystemURL destURL = new LocalFilesystemURL(destURLstr);
+        LocalFilesystemURL srcURL = LocalFilesystemURL.parse(srcURLstr);
+        LocalFilesystemURL destURL = LocalFilesystemURL.parse(destURLstr);
 
         Filesystem srcFs = this.filesystemForURL(srcURL);
         Filesystem destFs = this.filesystemForURL(destURL);
@@ -685,9 +685,9 @@ public class FileUtils extends CordovaPlugin {
      */
     private boolean removeRecursively(String baseURLstr) throws FileExistsException, NoModificationAllowedException, MalformedURLException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	// You can't delete the root directory.
-        	if ("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath)) {
+        	if ("".equals(inputURL.pathAndQuery) || "/".equals(inputURL.pathAndQuery)) {
         		throw new NoModificationAllowedException("You can't delete the root directory");
         	}
 
@@ -714,9 +714,9 @@ public class FileUtils extends CordovaPlugin {
      */
     private boolean remove(String baseURLstr) throws NoModificationAllowedException, InvalidModificationException, MalformedURLException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	// You can't delete the root directory.
-        	if ("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath)) {
+        	if ("".equals(inputURL.pathAndQuery) || "/".equals(inputURL.pathAndQuery)) {
 
         		throw new NoModificationAllowedException("You can't delete the root directory");
         	}
@@ -748,7 +748,7 @@ public class FileUtils extends CordovaPlugin {
      */
     private JSONObject getFile(String baseURLstr, String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -767,7 +767,7 @@ public class FileUtils extends CordovaPlugin {
      */
     private JSONObject getParent(String baseURLstr) throws JSONException, IOException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -786,7 +786,7 @@ public class FileUtils extends CordovaPlugin {
      */
     private JSONObject getFileMetadata(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(baseURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(baseURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -913,7 +913,7 @@ public class FileUtils extends CordovaPlugin {
      */
     public void readFileAs(final String srcURLstr, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) throws MalformedURLException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(srcURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -982,7 +982,7 @@ public class FileUtils extends CordovaPlugin {
     /**/
     public long write(String srcURLstr, String data, int offset, boolean isBinary) throws FileNotFoundException, IOException, NoModificationAllowedException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(srcURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
@@ -1000,7 +1000,7 @@ public class FileUtils extends CordovaPlugin {
      */
     private long truncateFile(String srcURLstr, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
         try {
-        	LocalFilesystemURL inputURL = new LocalFilesystemURL(srcURLstr);
+        	LocalFilesystemURL inputURL = LocalFilesystemURL.parse(srcURLstr);
         	Filesystem fs = this.filesystemForURL(inputURL);
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/8f7b013b/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index d1cbc27..64b78b8 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -78,8 +78,8 @@ public abstract class Filesystem {
         }
     }
 
-    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Boolean isDir, String nativeURL) {
-        return makeEntryForPath(inputURL.fullPath, inputURL.filesystemName, isDir, nativeURL);
+    public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Boolean isDir, Uri nativeURL) {
+        return makeEntryForPath(inputURL.pathAndQuery, inputURL.fsName, isDir, nativeURL.toString());
     }
 
 	abstract JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException;
@@ -104,29 +104,27 @@ public abstract class Filesystem {
     }
 
 	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-		LocalFilesystemURL newURL = new LocalFilesystemURL(inputURL.URL);
-	
-		if (!("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath))) {
-			String dirURL = inputURL.fullPath.replaceAll("/+$", "");
-			int lastPathStartsAt = dirURL.lastIndexOf('/')+1;
-			newURL.fullPath = newURL.fullPath.substring(0,lastPathStartsAt);
+        Uri parentUri = inputURL.uri;
+        String parentPath = new File(inputURL.uri.getPath()).getParent();
+        if (!"/".equals(parentPath)) {
+            parentUri = inputURL.uri.buildUpon().path(parentPath + '/').build();
 		}
-		return getEntryForLocalURL(newURL);
+		return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri));
 	}
 
     protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL) {
         // I know this looks weird but it is to work around a JSON bug.
         if ("null".equals(newName) || "".equals(newName)) {
-            newName = srcURL.URL.getLastPathSegment();;
+            newName = srcURL.uri.getLastPathSegment();;
         }
 
-        String newDest = destURL.URL.toString();
+        String newDest = destURL.uri.toString();
         if (newDest.endsWith("/")) {
             newDest = newDest + newName;
         } else {
             newDest = newDest + "/" + newName;
         }
-        return new LocalFilesystemURL(newDest);
+        return LocalFilesystemURL.parse(newDest);
     }
     
 	/* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/8f7b013b/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 544663d..805eacd 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -68,7 +68,7 @@ public class LocalFilesystem extends Filesystem {
 	
 	@Override
 	public String filesystemPathForURL(LocalFilesystemURL url) {
-		return filesystemPathForFullPath(url.fullPath);
+		return filesystemPathForFullPath(url.pathAndQuery);
 	}
 
 	private String fullPathForFilesystemPath(String absolutePath) {
@@ -81,9 +81,9 @@ public class LocalFilesystem extends Filesystem {
 	protected LocalFilesystemURL URLforFullPath(String fullPath) {
 	    if (fullPath != null) {
 	    	if (fullPath.startsWith("/")) {
-	    		return new LocalFilesystemURL(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+fullPath);
+	    		return LocalFilesystemURL.parse(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+fullPath);
 	    	}
-	        return new LocalFilesystemURL(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+"/"+fullPath);
+	        return LocalFilesystemURL.parse(LocalFilesystemURL.FILESYSTEM_PROTOCOL + "://localhost/"+this.name+"/"+fullPath);
 	    }
 	    return null;
 		
@@ -144,7 +144,7 @@ public class LocalFilesystem extends Filesystem {
       if (!fp.canRead()) {
           throw new IOException();
       }
-      return LocalFilesystem.makeEntryForURL(inputURL, fp.isDirectory(),  Uri.fromFile(fp).toString());
+      return LocalFilesystem.makeEntryForURL(inputURL, fp.isDirectory(),  Uri.fromFile(fp));
 	}
 
 	@Override
@@ -171,7 +171,7 @@ public class LocalFilesystem extends Filesystem {
         if (path.startsWith("/")) {
         	requestedURL = URLforFilesystemPath(path);
         } else {
-        	requestedURL = URLforFullPath(normalizePath(inputURL.fullPath + "/" + path));
+        	requestedURL = URLforFullPath(normalizePath(inputURL.pathAndQuery + "/" + path));
         }
         
         File fp = new File(this.filesystemPathForURL(requestedURL));
@@ -205,7 +205,7 @@ public class LocalFilesystem extends Filesystem {
         }
 
         // Return the directory
-        return makeEntryForPath(requestedURL.fullPath, requestedURL.filesystemName, directory, Uri.fromFile(fp).toString());
+        return makeEntryForPath(requestedURL.pathAndQuery, requestedURL.fsName, directory, Uri.fromFile(fp).toString());
 	}
 
 	@Override
@@ -256,7 +256,7 @@ public class LocalFilesystem extends Filesystem {
             File[] files = fp.listFiles();
             for (int i = 0; i < files.length; i++) {
                 if (files[i].canRead()) {
-                    entries.put(makeEntryForPath(fullPathForFilesystemPath(files[i].getAbsolutePath()), inputURL.filesystemName, files[i].isDirectory(), Uri.fromFile(files[i]).toString()));
+                    entries.put(makeEntryForPath(fullPathForFilesystemPath(files[i].getAbsolutePath()), inputURL.fsName, files[i].isDirectory(), Uri.fromFile(files[i]).toString()));
                 }
             }
         }
@@ -269,7 +269,7 @@ public class LocalFilesystem extends Filesystem {
         File file = new File(filesystemPathForURL(inputURL));
 
         if (!file.exists()) {
-            throw new FileNotFoundException("File at " + inputURL.URL + " does not exist.");
+            throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
         }
 
         JSONObject metadata = new JSONObject();
@@ -278,7 +278,7 @@ public class LocalFilesystem extends Filesystem {
         	metadata.put("size", file.isDirectory() ? 0 : file.length());
         	metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file)));
         	metadata.put("name", file.getName());
-        	metadata.put("fullPath", inputURL.fullPath);
+        	metadata.put("fullPath", inputURL.pathAndQuery);
         	metadata.put("lastModifiedDate", file.lastModified());
         } catch (JSONException e) {
         	return null;
@@ -599,7 +599,7 @@ public class LocalFilesystem extends Filesystem {
         File file = new File(filesystemPathForURL(inputURL));
 
         if (!file.exists()) {
-            throw new FileNotFoundException("File at " + inputURL.URL + " does not exist.");
+            throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
         }
         
         RandomAccessFile raf = new RandomAccessFile(filesystemPathForURL(inputURL), "rw");

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/8f7b013b/src/android/LocalFilesystemURL.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystemURL.java b/src/android/LocalFilesystemURL.java
index 2bf40c3..473b587 100644
--- a/src/android/LocalFilesystemURL.java
+++ b/src/android/LocalFilesystemURL.java
@@ -25,50 +25,39 @@ import android.net.Uri;
 public class LocalFilesystemURL {
 	
 	public static final String FILESYSTEM_PROTOCOL = "cdvfile";
-	
-	Uri URL;
-	String filesystemName;
-	String fullPath;
 
-	public LocalFilesystemURL(Uri URL) {
-		this.URL = URL;
-		this.filesystemName = this.filesystemNameForLocalURL(URL);
-		this.fullPath = this.fullPathForLocalURL(URL);
-	}
-	
-	private String fullPathForLocalURL(Uri URL) {
-		if (FILESYSTEM_PROTOCOL.equals(URL.getScheme()) && "localhost".equals(URL.getHost())) {
-			String path = URL.getPath();
-            if (URL.getQuery() != null) {
-                path = path + "?" + URL.getQuery();
-            }
-			return path.substring(path.indexOf('/', 1));
-		} else if ("content".equals(URL.getScheme())) {
-			String path = '/' + URL.getHost() + URL.getPath();
-			// Re-encode path component to handle Android 4.4+ Content URLs
-			return Uri.encode(path,"/");
-		}
-		return null;
-	}
+    public final Uri uri;
+    public final String fsName;
+    public final String pathAndQuery;
 
-	private String filesystemNameForLocalURL(Uri URL) {
-		if (FILESYSTEM_PROTOCOL.equals(URL.getScheme()) && "localhost".equals(URL.getHost())) {
-			List<String> pathComponents = URL.getPathSegments();
-			if (pathComponents != null && pathComponents.size() > 0) {
-				return pathComponents.get(0);
-			}
-			return null;
-		} else if ("content".equals(URL.getScheme())) {
-			return "content";
-		}
-		return null;
+	private LocalFilesystemURL(Uri uri, String fsName, String fsPath) {
+		this.uri = uri;
+        this.fsName = fsName;
+        this.pathAndQuery = fsPath;
 	}
 
-	public LocalFilesystemURL(String strURL) {
-		this(Uri.parse(strURL));
-	}
-	
+    public static LocalFilesystemURL parse(Uri uri) {
+        if (!FILESYSTEM_PROTOCOL.equals(uri.getScheme())) {
+            return null;
+        }
+        List<String> pathComponents = uri.getPathSegments();
+        if (pathComponents == null || pathComponents.size() == 0) {
+            return null;
+        }
+        String fsName = pathComponents.get(0);
+        String pathAndQuery = uri.getPath();
+        pathAndQuery = pathAndQuery.substring(pathAndQuery.indexOf('/', 1));
+        if (uri.getQuery() != null) {
+            pathAndQuery = pathAndQuery + "?" + uri.getQuery();
+        }
+        return new LocalFilesystemURL(uri, fsName, pathAndQuery);
+    }
+
+    public static LocalFilesystemURL parse(String uri) {
+        return parse(Uri.parse(uri));
+    }
+
     public String toString() {
-        return "cdvfile://localhost/" + this.filesystemName + this.fullPath;
+        return uri.toString();
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[12/13] cordova-plugin-file git commit: CB-6428 android: Add support for file:///android_asset URLs

Posted by ag...@apache.org.
CB-6428 android: Add support for file:///android_asset URLs

Supports:
- listing
- copying of file


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/356d3343
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/356d3343
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/356d3343

Branch: refs/heads/master
Commit: 356d334382fe7f827b2635e0c3f819453f746bab
Parents: d620226
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 16:25:23 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:08 2015 -0400

----------------------------------------------------------------------
 plugin.xml                       |   1 +
 src/android/AssetFilesystem.java | 222 ++++++++++++++++++++++++++++++++++
 src/android/FileUtils.java       |   6 +-
 src/android/Filesystem.java      |  74 ++++++++++--
 src/android/LocalFilesystem.java |  72 ++---------
 tests/tests.js                   |  37 ++++++
 6 files changed, 337 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 10c0c65..c4b9dcf 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -129,6 +129,7 @@ xmlns:android="http://schemas.android.com/apk/res/android"
         <source-file src="src/android/Filesystem.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/LocalFilesystem.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/ContentFilesystem.java" target-dir="src/org/apache/cordova/file" />
+        <source-file src="src/android/AssetFilesystem.java" target-dir="src/org/apache/cordova/file" />
 
         <!-- android specific file apis -->
         <js-module src="www/android/FileSystem.js" name="androidFileSystem">

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/src/android/AssetFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/AssetFilesystem.java b/src/android/AssetFilesystem.java
new file mode 100644
index 0000000..7a54e43
--- /dev/null
+++ b/src/android/AssetFilesystem.java
@@ -0,0 +1,222 @@
+/*
+       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.file;
+
+import android.content.res.AssetManager;
+import android.net.Uri;
+
+import org.apache.cordova.CordovaResourceApi;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public class AssetFilesystem extends Filesystem {
+
+    private final AssetManager assetManager;
+
+    public AssetFilesystem(AssetManager assetManager, CordovaResourceApi resourceApi) {
+        super(Uri.parse("file:///android_asset/"), "assets", resourceApi);
+        this.assetManager = assetManager;
+	}
+
+    @Override
+    public Uri toNativeUri(LocalFilesystemURL inputURL) {
+        return nativeUriForFullPath(inputURL.path);
+    }
+
+    @Override
+    public LocalFilesystemURL toLocalUri(Uri inputURL) {
+        if (!"file".equals(inputURL.getScheme())) {
+            return null;
+        }
+        File f = new File(inputURL.getPath());
+        // Removes and duplicate /s (e.g. file:///a//b/c)
+        Uri resolvedUri = Uri.fromFile(f);
+        String rootUriNoTrailingSlash = rootUri.getEncodedPath();
+        rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
+        if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
+            return null;
+        }
+        String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
+        // Strip leading slash
+        if (!subPath.isEmpty()) {
+            subPath = subPath.substring(1);
+        }
+        Uri.Builder b = new Uri.Builder()
+            .scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
+            .authority("localhost")
+            .path(name);
+        if (!subPath.isEmpty()) {
+            b.appendEncodedPath(subPath);
+        }
+        if (isDirectory(subPath) || inputURL.getPath().endsWith("/")) {
+            // Add trailing / for directories.
+            b.appendEncodedPath("");
+        }
+        return LocalFilesystemURL.parse(b.build());
+    }
+
+    private Boolean isDirectory(String assetPath) {
+        if (assetPath.startsWith("/")) {
+            assetPath = assetPath.substring(1);
+        }
+        try {
+            return assetManager.list(assetPath).length != 0;
+        } catch (IOException e) {
+        }
+        return false;
+    }
+
+    private LocalFilesystemURL URLforFullPath(String fullPath) {
+        Uri nativeUri = nativeUriForFullPath(fullPath);
+        if (nativeUri != null) {
+            return toLocalUri(nativeUri);
+        }
+        return null;
+    }
+
+
+    @Override
+	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        String[] files;
+        String pathNoSlashes = inputURL.path.substring(1);
+        if (pathNoSlashes.endsWith("/")) {
+            pathNoSlashes = pathNoSlashes.substring(0, pathNoSlashes.length() - 1);
+        }
+
+        try {
+            files = assetManager.list(pathNoSlashes);
+        } catch (IOException e) {
+            throw new FileNotFoundException();
+        }
+
+        JSONArray entries = new JSONArray();
+        if (files != null) {
+            for (String file : files) {
+                Uri newNativeUri = nativeUriForFullPath(new File(inputURL.path, file).getPath());
+                entries.put(makeEntryForNativeUri(newNativeUri));
+            }
+        }
+
+        return entries;
+	}
+
+    @Override
+    public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
+                                         String path, JSONObject options, boolean directory)
+            throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
+        if (options != null && options.optBoolean("create")) {
+            throw new UnsupportedOperationException("Assets are read-only");
+        }
+
+        // Check whether the supplied path is absolute or relative
+        if (directory && !path.endsWith("/")) {
+            path += "/";
+        }
+
+        LocalFilesystemURL requestedURL;
+        if (path.startsWith("/")) {
+            requestedURL = URLforFullPath(normalizePath(path));
+        } else {
+            requestedURL = URLforFullPath(normalizePath(inputURL.path + "/" + path));
+        }
+
+        // Throws a FileNotFoundException if it doesn't exist.
+        getFileMetadataForLocalURL(requestedURL);
+
+        boolean isDir = isDirectory(requestedURL.path);
+        if (directory && !isDir) {
+            throw new TypeMismatchException("path doesn't exist or is file");
+        } else if (!directory && isDir) {
+            throw new TypeMismatchException("path doesn't exist or is directory");
+        }
+
+        // Return the directory
+        return makeEntryForURL(requestedURL);
+    }
+
+
+    @Override
+	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        CordovaResourceApi.OpenForReadResult offr;
+        try {
+            offr = inputURL.isDirectory ? null : resourceApi.openForRead(toNativeUri(inputURL));
+        } catch (IOException e) {
+            throw new FileNotFoundException("File not found: " + inputURL);
+        }
+        JSONObject metadata = new JSONObject();
+        try {
+        	metadata.put("size", inputURL.isDirectory ? 0 : offr.length);
+        	metadata.put("type", inputURL.isDirectory ? "text/directory" : offr.mimeType);
+        	metadata.put("name", new File(inputURL.path).getName());
+        	metadata.put("fullPath", inputURL.path);
+        	metadata.put("lastModifiedDate", 0);
+        } catch (JSONException e) {
+            return null;
+        } finally {
+            if (offr != null) {
+                try {
+                    offr.inputStream.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        return metadata;
+	}
+
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		return false;
+	}
+
+    @Override
+    long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset, boolean isBinary) throws NoModificationAllowedException, IOException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException, NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    String filesystemPathForURL(LocalFilesystemURL url) {
+        return null;
+    }
+
+    @Override
+    LocalFilesystemURL URLforFilesystemPath(String path) {
+        return null;
+    }
+
+    @Override
+    boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+    @Override
+    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException {
+        throw new NoModificationAllowedException("Assets are read-only");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index a810726..67ebbe1 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -194,6 +194,7 @@ public class FileUtils extends CordovaPlugin {
     		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tempRoot));
     		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRoot));
     		this.registerFilesystem(new ContentFilesystem(webView.getContext(), webView.getResourceApi()));
+            this.registerFilesystem(new AssetFilesystem(webView.getContext().getAssets(), webView.getResourceApi()));
 
             registerExtraFileSystems(getExtraFileSystemsPreference(activity), getAvailableFileSystems(activity));
 
@@ -623,10 +624,13 @@ public class FileUtils extends CordovaPlugin {
         	if (fs == null) {
         		throw new MalformedURLException("No installed handlers for this URL");
         	}
-        	return fs.getEntryForLocalURL(inputURL);
+            if (fs.exists(inputURL)) {
+                return fs.getEntryForLocalURL(inputURL);
+            }
         } catch (IllegalArgumentException e) {
         	throw new MalformedURLException("Unrecognized filesystem URL");
         }
+        throw new FileNotFoundException();
     }   
     
     /**

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 2d64942..724976d 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -26,6 +26,8 @@ import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
 
 import org.apache.cordova.CordovaResourceApi;
 import org.json.JSONArray;
@@ -37,13 +39,12 @@ public abstract class Filesystem {
     protected final Uri rootUri;
     protected final CordovaResourceApi resourceApi;
     public final String name;
-    private final JSONObject rootEntry;
+    private JSONObject rootEntry;
 
     public Filesystem(Uri rootUri, String name, CordovaResourceApi resourceApi) {
         this.rootUri = rootUri;
         this.name = name;
         this.resourceApi = resourceApi;
-        rootEntry = makeEntryForNativeUri(rootUri);
     }
 
     public interface ReadFileCallback {
@@ -94,6 +95,10 @@ public abstract class Filesystem {
         return makeEntryForURL(inputURL);
     }
 
+    public JSONObject makeEntryForFile(File file) {
+        return makeEntryForNativeUri(Uri.fromFile(file));
+    }
+
     abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path,
 			JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException;
 
@@ -109,10 +114,67 @@ public abstract class Filesystem {
         return rootUri;
     }
 
+    public boolean exists(LocalFilesystemURL inputURL) {
+        try {
+            getFileMetadataForLocalURL(inputURL);
+        } catch (FileNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    public Uri nativeUriForFullPath(String fullPath) {
+        Uri ret = null;
+        if (fullPath != null) {
+            String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath();
+            if (encodedPath.startsWith("/")) {
+                encodedPath = encodedPath.substring(1);
+            }
+            ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build();
+        }
+        return ret;
+    }
+
+    /**
+     * Removes multiple repeated //s, and collapses processes ../s.
+     */
+    protected static String normalizePath(String rawPath) {
+        // If this is an absolute path, trim the leading "/" and replace it later
+        boolean isAbsolutePath = rawPath.startsWith("/");
+        if (isAbsolutePath) {
+            rawPath = rawPath.replaceFirst("/+", "");
+        }
+        ArrayList<String> components = new ArrayList<String>(Arrays.asList(rawPath.split("/+")));
+        for (int index = 0; index < components.size(); ++index) {
+            if (components.get(index).equals("..")) {
+                components.remove(index);
+                if (index > 0) {
+                    components.remove(index-1);
+                    --index;
+                }
+            }
+        }
+        StringBuilder normalizedPath = new StringBuilder();
+        for(String component: components) {
+            normalizedPath.append("/");
+            normalizedPath.append(component);
+        }
+        if (isAbsolutePath) {
+            return normalizedPath.toString();
+        } else {
+            return normalizedPath.toString().substring(1);
+        }
+    }
+
+
+
     public abstract Uri toNativeUri(LocalFilesystemURL inputURL);
     public abstract LocalFilesystemURL toLocalUri(Uri inputURL);
 
     public JSONObject getRootEntry() {
+        if (rootEntry == null) {
+            rootEntry = makeEntryForNativeUri(rootUri);
+        }
         return rootEntry;
     }
 
@@ -235,12 +297,4 @@ public abstract class Filesystem {
             return numBytesRead;
         }
     }
-
-    /* Create a FileEntry or DirectoryEntry given an actual file on device.
-     * Return null if the file does not exist within this filesystem.
-     */
-	public JSONObject makeEntryForFile(File file) throws JSONException {
-		return null;
-	}
-
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 2754b41..83c1384 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -66,18 +66,6 @@ public class LocalFilesystem extends Filesystem {
 		return null;
 	}
 
-    private Uri nativeUriForFullPath(String fullPath) {
-        Uri ret = null;
-        if (fullPath != null) {
-            String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath();
-            if (encodedPath.startsWith("/")) {
-                encodedPath = encodedPath.substring(1);
-            }
-            ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build();
-        }
-        return ret;
-    }
-
 	protected LocalFilesystemURL URLforFullPath(String fullPath) {
         Uri nativeUri = nativeUriForFullPath(fullPath);
 	    if (nativeUri != null) {
@@ -128,56 +116,6 @@ public class LocalFilesystem extends Filesystem {
 	    return this.URLforFullPath(this.fullPathForFilesystemPath(path));
 	}
 
-    /**
-     * Removes multiple repeated //s, and collapses processes ../s.
-     */
-	protected String normalizePath(String rawPath) {
-	    // If this is an absolute path, trim the leading "/" and replace it later
-	    boolean isAbsolutePath = rawPath.startsWith("/");
-	    if (isAbsolutePath) {
-	        rawPath = rawPath.replaceFirst("/+", "");
-	    }
-	    ArrayList<String> components = new ArrayList<String>(Arrays.asList(rawPath.split("/+")));
-	    for (int index = 0; index < components.size(); ++index) {
-	        if (components.get(index).equals("..")) {
-	            components.remove(index);
-	            if (index > 0) {
-	                components.remove(index-1);
-	                --index;
-	            }
-	        }
-	    }
-	    StringBuilder normalizedPath = new StringBuilder();
-	    for(String component: components) {
-	    	normalizedPath.append("/");
-	    	normalizedPath.append(component);
-	    }
-	    if (isAbsolutePath) {
-	    	return normalizedPath.toString();
-	    } else {
-	    	return normalizedPath.toString().substring(1);
-	    }
-	}
-
-	
-	@Override
-    public JSONObject makeEntryForFile(File file) {
-        return makeEntryForNativeUri(Uri.fromFile(file));
-    }
-
-	@Override
-	public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-      File fp = new File(filesystemPathForURL(inputURL));
-
-      if (!fp.exists()) {
-          throw new FileNotFoundException();
-      }
-      if (!fp.canRead()) {
-          throw new IOException();
-      }
-      return super.getEntryForLocalURL(inputURL);
-	}
-
 	@Override
 	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
 			String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
@@ -203,7 +141,7 @@ public class LocalFilesystem extends Filesystem {
             path += "/";
         }
         if (path.startsWith("/")) {
-        	requestedURL = URLforFilesystemPath(normalizePath(path));
+        	requestedURL = URLforFullPath(normalizePath(path));
         } else {
         	requestedURL = URLforFullPath(normalizePath(inputURL.path + "/" + path));
         }
@@ -255,7 +193,13 @@ public class LocalFilesystem extends Filesystem {
         return fp.delete();
 	}
 
-	@Override
+    @Override
+    public boolean exists(LocalFilesystemURL inputURL) {
+        File fp = new File(filesystemPathForURL(inputURL));
+        return fp.exists();
+    }
+
+    @Override
 	public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException {
         File directory = new File(filesystemPathForURL(inputURL));
     	return removeDirRecursively(directory);

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/356d3343/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index adaa9ab..5735af1 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -3443,6 +3443,43 @@ exports.defineAutoTests = function () {
                     }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider'));
                 });
             });
+            describe('asset: URLs', function() {
+                it("file.spec.141 filePaths.applicationStorage", function() {
+                    expect(cordova.file.applicationDirectory).toEqual('file:///android_asset/');
+                });
+                it("file.spec.142 assets should be enumerable", function(done) {
+                    resolveLocalFileSystemURL('file:///android_asset/www/', function(entry) {
+                        var reader = entry.createReader();
+                        reader.readEntries(function (entries) {
+                            expect(entries.length).not.toBe(0);
+                            done();
+                        }, failed.bind(null, done, 'reader.readEntries - Error during reading of entries from assets directory'));
+                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
+                });
+                it("file.spec.143 copyTo: asset -> temporary", function(done) {
+                    var file2 = "entry.copy.file2b",
+                    fullPath = joinURL(temp_root.fullPath, file2),
+                    validateFile = function (entry) {
+                        expect(entry.isFile).toBe(true);
+                        expect(entry.isDirectory).toBe(false);
+                        expect(entry.name).toCanonicallyMatch(file2);
+                        expect(entry.fullPath).toCanonicallyMatch(fullPath);
+                        expect(entry.filesystem.name).toEqual("temporary");
+                        // cleanup
+                        deleteEntry(entry.name, done);
+                    },
+                    transfer = function () {
+                        resolveLocalFileSystemURL('file:///android_asset/www/index.html', function(entry) {
+                            expect(entry.filesystem.name).toEqual('assets');
+                            entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2));
+                        }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
+                    };
+                    // Delete any existing file to start things off
+                    temp_root.getFile(file2, {}, function (entry) {
+                        entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
+                    }, transfer);
+                });
+            });
         }
     });
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[05/13] cordova-plugin-file git commit: android: Delete invalid JavaDoc (lint errors)

Posted by ag...@apache.org.
android: Delete invalid JavaDoc (lint errors)


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/c35d9135
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/c35d9135
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/c35d9135

Branch: refs/heads/master
Commit: c35d9135b14c16410ba452a9a46fa6dfb8c832fb
Parents: 80f37d6
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 13:17:39 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/FileUtils.java | 29 +----------------------------
 1 file changed, 1 insertion(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/c35d9135/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 676d297..cd6f9c1 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -65,7 +65,7 @@ public class FileUtils extends CordovaPlugin {
     public static int QUOTA_EXCEEDED_ERR = 10;
     public static int TYPE_MISMATCH_ERR = 11;
     public static int PATH_EXISTS_ERR = 12;
-    
+
     public static int UNKNOWN_ERR = 1000;
     
     private boolean configured = false;
@@ -638,7 +638,6 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Read the list of files from this directory.
      *
-     * @param fileName the directory to read from
      * @return a JSONArray containing JSONObjects that represent Entry objects.
      * @throws FileNotFoundException if the directory is not found.
      * @throws JSONException
@@ -661,8 +660,6 @@ public class FileUtils extends CordovaPlugin {
     /**
      * A setup method that handles the move/copy of files/directories
      *
-     * @param fileName to be copied/moved
-     * @param newParent is the location where the file will be copied/moved to
      * @param newName for the file directory to be called, if null use existing file name
      * @param move if false do a copy, if true do a move
      * @return a Entry object
@@ -699,7 +696,6 @@ public class FileUtils extends CordovaPlugin {
      * some of the contents of the directory may be deleted.
      * It is an error to attempt to delete the root directory of a filesystem.
      *
-     * @param filePath the directory to be removed
      * @return a boolean representing success of failure
      * @throws FileExistsException
      * @throws NoModificationAllowedException 
@@ -729,7 +725,6 @@ public class FileUtils extends CordovaPlugin {
      * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty.
      * It is an error to attempt to delete the root directory of a filesystem.
      *
-     * @param filePath file or directory to be removed
      * @return a boolean representing success of failure
      * @throws NoModificationAllowedException
      * @throws InvalidModificationException
@@ -787,11 +782,6 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Look up the parent DirectoryEntry containing this Entry.
      * If this Entry is the root of its filesystem, its parent is itself.
-     *
-     * @param filePath
-     * @return
-     * @throws JSONException
-     * @throws IOException 
      */
     private JSONObject getParent(String baseURLstr) throws JSONException, IOException {
         try {
@@ -810,11 +800,7 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Returns a File that represents the current state of the file that this FileEntry represents.
      *
-     * @param filePath to entry
      * @return returns a JSONObject represent a W3C File object
-     * @throws FileNotFoundException
-     * @throws JSONException
-     * @throws MalformedURLException 
      */
     private JSONObject getFileMetadata(String baseURLstr) throws FileNotFoundException, JSONException, MalformedURLException {
         try {
@@ -858,10 +844,7 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Requests a filesystem in which to store application data.
      *
-     * @param type of file system requested
      * @return a JSONObject representing the file system
-     * @throws IOException
-     * @throws JSONException
      */
     private JSONArray requestAllFileSystems() throws IOException, JSONException {
         JSONArray ret = new JSONArray();
@@ -939,14 +922,12 @@ public class FileUtils extends CordovaPlugin {
      * Read the contents of a file.
      * This is done in a background thread; the result is sent to the callback.
      *
-     * @param filename          The name of the file.
      * @param start             Start position in the file.
      * @param end               End position to stop at (exclusive).
      * @param callbackContext   The context through which to send the result.
      * @param encoding          The encoding to return contents as.  Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
      * @param resultType        The desired type of data to send to the callback.
      * @return                  Contents of file.
-     * @throws MalformedURLException 
      */
     public void readFileAs(final String srcURLstr, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) throws MalformedURLException {
         try {
@@ -1012,12 +993,9 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Write contents of file.
      *
-     * @param filename			The name of the file.
      * @param data				The contents of the file.
      * @param offset			The position to begin writing the file.
      * @param isBinary          True if the file contents are base64-encoded binary data
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
      */
     /**/
     public long write(String srcURLstr, String data, int offset, boolean isBinary) throws FileNotFoundException, IOException, NoModificationAllowedException {
@@ -1037,11 +1015,6 @@ public class FileUtils extends CordovaPlugin {
 
     /**
      * Truncate the file to size
-     *
-     * @param filename
-     * @param size
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
      */
     private long truncateFile(String srcURLstr, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
         try {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[02/13] cordova-plugin-file git commit: Tweak tests to fail if deleteEntry fails (rather than time out)

Posted by ag...@apache.org.
Tweak tests to fail if deleteEntry fails (rather than time out)


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/9d789088
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/9d789088
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/9d789088

Branch: refs/heads/master
Commit: 9d789088bb557357b5651eeecf74eb90774b0525
Parents: 8f7b013
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 10:27:54 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 tests/tests.js | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/9d789088/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index c1471d7..1478aaf 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -131,6 +131,7 @@ exports.defineAutoTests = function () {
             // deletes entry, if it exists
             // entry.remove success callback is required: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#the-entry-interface
             success = success || function() {};
+            error = error || failed.bind(null, success, 'deleteEntry failed.');
 
             window.resolveLocalFileSystemURL(root.toURL() + '/' + name, function (entry) {
                 if (entry.isDirectory === true) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[06/13] cordova-plugin-file git commit: Tweak test case that failed twice on error rather than just once

Posted by ag...@apache.org.
Tweak test case that failed twice on error rather than just once


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/1a79a051
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/1a79a051
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/1a79a051

Branch: refs/heads/master
Commit: 1a79a051ac09dc4c9619644404c687b2229c37e1
Parents: c35d913
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 13:17:59 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 tests/tests.js | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/1a79a051/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index 8710a54..c1471d7 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -2189,7 +2189,6 @@ exports.defineAutoTests = function () {
                 };
                 var reader = new FileReader();
                 reader.onloadend = verifier;
-                reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + blob);
                 reader.readAsText(blob);
             });
             function writeDummyFile(writeBinary, callback, done) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[04/13] cordova-plugin-file git commit: android: Use CordovaResourceApi rather than FileHelper

Posted by ag...@apache.org.
android: Use CordovaResourceApi rather than FileHelper


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/80f37d6c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/80f37d6c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/80f37d6c

Branch: refs/heads/master
Commit: 80f37d6c0389731ccf2bef7c23c064e854699faa
Parents: 2ed379c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 13:12:04 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 plugin.xml                       |   4 +-
 src/android/FileHelper.java      | 158 ----------------------------------
 src/android/FileUtils.java       |   6 +-
 src/android/LocalFilesystem.java |  28 +++---
 4 files changed, 16 insertions(+), 180 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/80f37d6c/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index ac1bc17..10c0c65 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -28,6 +28,9 @@ xmlns:android="http://schemas.android.com/apk/res/android"
     <keywords>cordova,file</keywords>
     <repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-file.git</repo>
     <issue>https://issues.apache.org/jira/browse/CB/component/12320651</issue>
+    <engines>
+        <engine name="cordova-android" version=">=3.1.0" /><!-- Uses CordovaResourceApi -->
+    </engines>
 
     <js-module src="www/DirectoryEntry.js" name="DirectoryEntry">
         <clobbers target="window.DirectoryEntry" />
@@ -121,7 +124,6 @@ xmlns:android="http://schemas.android.com/apk/res/android"
         <source-file src="src/android/NoModificationAllowedException.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/TypeMismatchException.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/FileUtils.java" target-dir="src/org/apache/cordova/file" />
-        <source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/DirectoryManager.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/LocalFilesystemURL.java" target-dir="src/org/apache/cordova/file" />
         <source-file src="src/android/Filesystem.java" target-dir="src/org/apache/cordova/file" />

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/80f37d6c/src/android/FileHelper.java
----------------------------------------------------------------------
diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java
deleted file mode 100644
index 9e8b626..0000000
--- a/src/android/FileHelper.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-       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.file;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.webkit.MimeTypeMap;
-
-import org.apache.cordova.CordovaInterface;
-import org.apache.cordova.LOG;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-
-public class FileHelper {
-    private static final String LOG_TAG = "FileUtils";
-    private static final String _DATA = "_data";
-
-    /**
-     * Returns the real path of the given URI string.
-     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
-     *
-     * @param uriString the URI string of the audio/image/video
-     * @param cordova the current application context
-     * @return the full path to the file
-     */
-    @SuppressWarnings("deprecation")
-    public static String getRealPath(String uriString, CordovaInterface cordova) {
-        String realPath = null;
-
-        if (uriString.startsWith("content://")) {
-            String[] proj = { _DATA };
-            Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
-            int column_index = cursor.getColumnIndexOrThrow(_DATA);
-            cursor.moveToFirst();
-            realPath = cursor.getString(column_index);
-            if (realPath == null) {
-                LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
-            }
-        } else if (uriString.startsWith("file://")) {
-            realPath = uriString.substring(7);
-            if (realPath.startsWith("/android_asset/")) {
-                LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
-                realPath = null;
-            }
-        } else {
-            realPath = uriString;
-        }
-
-        return realPath;
-    }
-
-    /**
-     * Returns the real path of the given URI.
-     * If the given URI is a content:// URI, the real path is retrieved from the media store.
-     *
-     * @param uri the URI of the audio/image/video
-     * @param cordova the current application context
-     * @return the full path to the file
-     */
-    public static String getRealPath(Uri uri, CordovaInterface cordova) {
-        return FileHelper.getRealPath(uri.toString(), cordova);
-    }
-
-    /**
-     * Returns an input stream based on given URI string.
-     *
-     * @param uriString the URI string from which to obtain the input stream
-     * @param cordova the current application context
-     * @return an input stream into the data at the given URI or null if given an invalid URI string
-     * @throws IOException
-     */
-    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
-        if (uriString.startsWith("content")) {
-            Uri uri = Uri.parse(uriString);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        } else if (uriString.startsWith("file://")) {
-            int question = uriString.indexOf("?");
-            if (question > -1) {
-            	uriString = uriString.substring(0,question);
-            }
-            if (uriString.startsWith("file:///android_asset/")) {
-                Uri uri = Uri.parse(uriString);
-                String relativePath = uri.getPath().substring(15);
-                return cordova.getActivity().getAssets().open(relativePath);
-            } else {
-                return new FileInputStream(getRealPath(uriString, cordova));
-            }
-        } else {
-            return new FileInputStream(getRealPath(uriString, cordova));
-        }
-    }
-
-    /**
-     * Removes the "file://" prefix from the given URI string, if applicable.
-     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
-     *
-     * @param uriString the URI string to operate on
-     * @return a path without the "file://" prefix
-     */
-    public static String stripFileProtocol(String uriString) {
-        if (uriString.startsWith("file://")) {
-            uriString = uriString.substring(7);
-        }
-        return uriString;
-    }
-
-    public static String getMimeTypeForExtension(String path) {
-        String extension = path;
-        int lastDot = extension.lastIndexOf('.');
-        if (lastDot != -1) {
-            extension = extension.substring(lastDot + 1);
-        }
-        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
-        extension = extension.toLowerCase(Locale.getDefault());
-        if (extension.equals("3ga")) {
-            return "audio/3gpp";
-        }
-        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
-    }
-    
-    /**
-     * Returns the mime type of the data specified by the given URI string.
-     *
-     * @param uriString the URI string of the data
-     * @return the mime type of the specified data
-     */
-    public static String getMimeType(String uriString, CordovaInterface cordova) {
-        String mimeType = null;
-
-        Uri uri = Uri.parse(uriString);
-        if (uriString.startsWith("content://")) {
-            mimeType = cordova.getActivity().getContentResolver().getType(uri);
-        } else {
-            mimeType = getMimeTypeForExtension(uri.getPath());
-        }
-
-        return mimeType;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/80f37d6c/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 08205d1..676d297 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -112,7 +112,7 @@ public class FileUtils extends CordovaPlugin {
                 if (fsRoot != null) {
                     File newRoot = new File(fsRoot);
                     if (newRoot.mkdirs() || newRoot.isDirectory()) {
-                        registerFilesystem(new LocalFilesystem(fsName, cordova, Uri.fromFile(newRoot)));
+                        registerFilesystem(new LocalFilesystem(fsName, webView.getContext(), webView.getResourceApi(), Uri.fromFile(newRoot)));
                         installedFileSystems.add(fsName);
                     } else {
                        Log.d(LOG_TAG, "Unable to create root dir for filesystem \"" + fsName + "\", skipping");
@@ -192,8 +192,8 @@ public class FileUtils extends CordovaPlugin {
     		// Note: The temporary and persistent filesystems need to be the first two
     		// registered, so that they will match window.TEMPORARY and window.PERSISTENT,
     		// per spec.
-    		this.registerFilesystem(new LocalFilesystem("temporary", cordova, tempRoot));
-    		this.registerFilesystem(new LocalFilesystem("persistent", cordova, persistentRoot));
+    		this.registerFilesystem(new LocalFilesystem("temporary", webView.getContext(), webView.getResourceApi(), tempRoot));
+    		this.registerFilesystem(new LocalFilesystem("persistent", webView.getContext(), webView.getResourceApi(), persistentRoot));
     		this.registerFilesystem(new ContentFilesystem(cordova, webView));
 
             registerExtraFileSystems(getExtraFileSystemsPreference(activity), getAvailableFileSystems(activity));

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/80f37d6c/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 28985fa..884771c 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -32,6 +32,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 
 import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaResourceApi;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -44,14 +45,16 @@ import android.app.Activity;
 
 public class LocalFilesystem extends Filesystem {
 
-	private CordovaInterface cordova;
+    private final CordovaResourceApi resourceApi;
+    private final Context context;
 
-    public LocalFilesystem(String name, CordovaInterface cordova, String rootPath) {
-        this(name, cordova, Uri.fromFile(new File(rootPath)));
+    public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, String rootPath) {
+        this(name, context, resourceApi, Uri.fromFile(new File(rootPath)));
     }
-	public LocalFilesystem(String name, CordovaInterface cordova, Uri rootUri) {
+	public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, Uri rootUri) {
         super(rootUri, name);
-		this.cordova = cordova;
+		this.context = context;
+        this.resourceApi = resourceApi;
 	}
 
     public String filesystemPathForFullPath(String fullPath) {
@@ -276,7 +279,7 @@ public class LocalFilesystem extends Filesystem {
         try {
             // Ensure that directories report a size of 0
         	metadata.put("size", file.isDirectory() ? 0 : file.length());
-        	metadata.put("type", FileHelper.getMimeType(file.getAbsolutePath(), cordova));
+        	metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file)));
         	metadata.put("name", file.getName());
         	metadata.put("fullPath", inputURL.fullPath);
         	metadata.put("lastModifiedDate", file.lastModified());
@@ -520,7 +523,7 @@ public class LocalFilesystem extends Filesystem {
 			ReadFileCallback readFileCallback) throws IOException {
 
 		File file = new File(this.filesystemPathForURL(inputURL));
-        String contentType = FileHelper.getMimeTypeForExtension(file.getAbsolutePath());
+        String contentType = resourceApi.getMimeType(Uri.fromFile(file));
 		
         if (end < 0) {
             end = file.length();
@@ -588,19 +591,8 @@ public class LocalFilesystem extends Filesystem {
     private void broadcastNewFile(LocalFilesystemURL inputURL) {
         File file = new File(this.filesystemPathForURL(inputURL));
         if (file.exists()) {
-            //Get the activity
-            Activity activity = this.cordova.getActivity();
-
-            //Get the context
-            Context context = activity.getApplicationContext();
-
-            //Create the URI
             Uri uri = Uri.fromFile(file);
-
-            //Create the intent
             Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
-
-            //Send broadcast of new file
             context.sendBroadcast(intent);
         }
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[11/13] cordova-plugin-file git commit: CB-6428 android: Add support for directory copies from assets -> filesystem

Posted by ag...@apache.org.
CB-6428 android: Add support for directory copies from assets -> filesystem


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/072acc73
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/072acc73
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/072acc73

Branch: refs/heads/master
Commit: 072acc733182c4736421e1a516706844e37747e0
Parents: 7051ad3
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 22:43:14 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:08 2015 -0400

----------------------------------------------------------------------
 src/android/AssetFilesystem.java |   2 +-
 src/android/Filesystem.java      |   7 +-
 src/android/LocalFilesystem.java | 279 ++++++++++------------------------
 tests/tests.js                   |  34 +++++
 4 files changed, 119 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/AssetFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/AssetFilesystem.java b/src/android/AssetFilesystem.java
index 40968e0..c1c0d6f 100644
--- a/src/android/AssetFilesystem.java
+++ b/src/android/AssetFilesystem.java
@@ -211,7 +211,7 @@ public class AssetFilesystem extends Filesystem {
     }
 
     @Override
-    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException {
+    boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws NoModificationAllowedException {
         throw new NoModificationAllowedException("Assets are read-only");
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 309c0b8..45047c8 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -198,7 +198,7 @@ public abstract class Filesystem {
 		return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri));
 	}
 
-    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL) {
+    protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL, boolean isDirectory) {
         // I know this looks weird but it is to work around a JSON bug.
         if ("null".equals(newName) || "".equals(newName)) {
             newName = srcURL.uri.getLastPathSegment();;
@@ -210,6 +210,9 @@ public abstract class Filesystem {
         } else {
             newDest = newDest + "/" + newName;
         }
+        if (isDirectory) {
+            newDest += '/';
+        }
         return LocalFilesystemURL.parse(newDest);
     }
 
@@ -224,7 +227,7 @@ public abstract class Filesystem {
         if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
             throw new NoModificationAllowedException("Cannot move file at source URL");
         }
-        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL);
+        final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
 
         Uri srcNativeUri = srcFs.toNativeUri(srcURL);
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 93ba2b0..cc0ff57 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -20,17 +20,12 @@ package org.apache.cordova.file;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Arrays;
-
 import org.apache.cordova.CordovaResourceApi;
-import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -263,182 +258,72 @@ public class LocalFilesystem extends Filesystem {
         return metadata;
 	}
 
-    /**
-     * Check to see if the user attempted to copy an entry into its parent without changing its name,
-     * or attempted to copy a directory into a directory that it contains directly or indirectly.
-     */
-    private boolean isCopyOnItself(String src, String dest) {
-
-        // This weird test is to determine if we are copying or moving a directory into itself.
-        // Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
-        // Copy /sdcard/myDir to /sdcard/myDir/backup should throw an INVALID_MODIFICATION_ERR
-        return dest.equals(src) || dest.startsWith(src + File.separator);
-    }
-
-    /**
-     * Copy a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
+    private void copyFile(Filesystem srcFs, LocalFilesystemURL srcURL, File destFile, boolean move) throws IOException, InvalidModificationException, NoModificationAllowedException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcFile = new File(realSrcPath);
+                if (srcFile.renameTo(destFile)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
         }
 
-        copyAction(srcFile, destFile);
-
-        return makeEntryForFile(destFile);
-    }
-
-    /**
-     * Moved this code into it's own method so moveTo could use it when the move is across file systems
-     */
-    private void copyAction(File srcFile, File destFile)
-            throws FileNotFoundException, IOException {
-        FileInputStream istream = new FileInputStream(srcFile);
-        FileOutputStream ostream = new FileOutputStream(destFile);
-        FileChannel input = istream.getChannel();
-        FileChannel output = ostream.getChannel();
+        CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(srcFs.toNativeUri(srcURL));
+        resourceApi.copyResource(offr, new FileOutputStream(destFile));
 
-        try {
-            input.transferTo(0, input.size(), output);
-        } finally {
-            istream.close();
-            ostream.close();
-            input.close();
-            output.close();
+        if (move) {
+            srcFs.removeFileAtLocalURL(srcURL);
         }
     }
 
-    /**
-     * Copy a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws NoModificationAllowedException
-     * @throws InvalidModificationException
-     */
-    private JSONObject copyDirectory(File srcDir, File destinationDir) throws JSONException, IOException, NoModificationAllowedException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't copy itself into itself");
+    private void copyDirectory(Filesystem srcFs, LocalFilesystemURL srcURL, File dstDir, boolean move) throws IOException, NoModificationAllowedException, InvalidModificationException, FileExistsException {
+        if (move) {
+            String realSrcPath = srcFs.filesystemPathForURL(srcURL);
+            if (realSrcPath != null) {
+                File srcDir = new File(realSrcPath);
+                // If the destination directory already exists and is empty then delete it.  This is according to spec.
+                if (dstDir.exists()) {
+                    if (dstDir.list().length > 0) {
+                        throw new InvalidModificationException("directory is not empty");
+                    }
+                    dstDir.delete();
+                }
+                // Try to rename the directory
+                if (srcDir.renameTo(dstDir)) {
+                    return;
+                }
+                // Trying to rename the file failed.  Possibly because we moved across file system on the device.
+            }
         }
 
-        // See if the destination directory exists. If not create it.
-        if (!destinationDir.exists()) {
-            if (!destinationDir.mkdir()) {
+        if (dstDir.exists()) {
+            if (dstDir.list().length > 0) {
+                throw new InvalidModificationException("directory is not empty");
+            }
+        } else {
+            if (!dstDir.mkdir()) {
                 // If we can't create the directory then fail
                 throw new NoModificationAllowedException("Couldn't create the destination directory");
             }
         }
-        
 
-        for (File file : srcDir.listFiles()) {
-            File destination = new File(destinationDir.getAbsoluteFile() + File.separator + file.getName());
-            if (file.isDirectory()) {
-                copyDirectory(file, destination);
+        LocalFilesystemURL[] children = srcFs.listChildren(srcURL);
+        for (LocalFilesystemURL childLocalUrl : children) {
+            File target = new File(dstDir, new File(childLocalUrl.path).getName());
+            if (childLocalUrl.isDirectory) {
+                copyDirectory(srcFs, childLocalUrl, target, false);
             } else {
-                copyFile(file, destination);
+                copyFile(srcFs, childLocalUrl, target, false);
             }
         }
 
-        return makeEntryForFile(destinationDir);
-    }
-
-    /**
-     * Move a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject moveFile(File srcFile, File destFile) throws IOException, JSONException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Try to rename the file
-        if (!srcFile.renameTo(destFile)) {
-            // Trying to rename the file failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old file
-            // 2) delete the src file
-            copyAction(srcFile, destFile);
-            if (destFile.exists()) {
-                srcFile.delete();
-            } else {
-                throw new IOException("moved failed");
-            }
+        if (move) {
+            srcFs.recursiveRemoveFileAtLocalURL(srcURL);
         }
-
-        return makeEntryForFile(destFile);
     }
 
-    /**
-     * Move a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws NoModificationAllowedException
-     * @throws FileExistsException
-     */
-    private JSONObject moveDirectory(File srcDir, File destinationDir) throws IOException, JSONException, InvalidModificationException, NoModificationAllowedException, FileExistsException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't move itself into itself");
-        }
-
-        // If the destination directory already exists and is empty then delete it.  This is according to spec.
-        if (destinationDir.exists()) {
-            if (destinationDir.list().length > 0) {
-                throw new InvalidModificationException("directory is not empty");
-            }
-        }
-
-        // Try to rename the directory
-        if (!srcDir.renameTo(destinationDir)) {
-            // Trying to rename the directory failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old files
-            // 2) delete the src directory
-            copyDirectory(srcDir, destinationDir);
-            if (destinationDir.exists()) {
-                removeDirRecursively(srcDir);
-            } else {
-                throw new IOException("moved failed");
-            }
-        }
-
-        return makeEntryForFile(destinationDir);
-    }
-	
 	@Override
 	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
 			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
@@ -451,45 +336,39 @@ public class LocalFilesystem extends Filesystem {
             throw new FileNotFoundException("The source does not exist");
         }
         
-	    if (LocalFilesystem.class.isInstance(srcFs)) {
-	        /* Same FS, we can shortcut with NSFileManager operations */
-
-            // Figure out where we should be copying to
-            final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL);
-
-	        String srcFilesystemPath = srcFs.filesystemPathForURL(srcURL);
-            File sourceFile = new File(srcFilesystemPath);
-            String destFilesystemPath = this.filesystemPathForURL(destinationURL);
-            File destinationFile = new File(destFilesystemPath);
-
-            if (!sourceFile.exists()) {
-	            // The file/directory we are copying doesn't exist so we should fail.
-	            throw new FileNotFoundException("The source does not exist");
-	        }
-
-	        // Check to see if source and destination are the same file
-            if (sourceFile.getAbsolutePath().equals(destinationFile.getAbsolutePath())) {
-	            throw new InvalidModificationException("Can't copy a file onto itself");
-	        }
-
-            if (sourceFile.isDirectory()) {
-	            if (move) {
-                    return moveDirectory(sourceFile, destinationFile);
-	            } else {
-                    return copyDirectory(sourceFile, destinationFile);
-	            }
-	        } else {
-	            if (move) {
-                    return moveFile(sourceFile, destinationFile);
-	            } else {
-                    return copyFile(sourceFile, destinationFile);
-	            }
-	        }
-	    	
-	    } else {
-	        // Need to copy the hard way
-            return super.copyFileToURL(destURL, newName, srcFs, srcURL, move);
-    	}
+        // Figure out where we should be copying to
+        final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
+
+        Uri dstNativeUri = toNativeUri(destinationURL);
+        Uri srcNativeUri = srcFs.toNativeUri(srcURL);
+        // Check to see if source and destination are the same file
+        if (dstNativeUri.equals(srcNativeUri)) {
+            throw new InvalidModificationException("Can't copy onto itself");
+        }
+
+        if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
+            throw new InvalidModificationException("Source URL is read-only (cannot move)");
+        }
+
+        File destFile = new File(dstNativeUri.getPath());
+        if (destFile.exists()) {
+            if (!srcURL.isDirectory && destFile.isDirectory()) {
+                throw new InvalidModificationException("Can't copy/move a file to an existing directory");
+            } else if (srcURL.isDirectory && destFile.isFile()) {
+                throw new InvalidModificationException("Can't copy/move a directory to an existing file");
+            }
+        }
+
+        if (srcURL.isDirectory) {
+            // E.g. Copy /sdcard/myDir to /sdcard/myDir/backup
+            if (dstNativeUri.toString().startsWith(srcNativeUri.toString() + '/')) {
+                throw new InvalidModificationException("Can't copy directory into itself");
+            }
+            copyDirectory(srcFs, srcURL, destFile, move);
+        } else {
+            copyFile(srcFs, srcURL, destFile, move);
+        }
+        return makeEntryForURL(destinationURL);
 	}
     
 	@Override

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/072acc73/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index 5735af1..239a0d3 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -3480,6 +3480,40 @@ exports.defineAutoTests = function () {
                     }, transfer);
                 });
             });
+            it("file.spec.144 copyTo: asset directory", function (done) {
+                var srcUrl = 'file:///android_asset/www/plugins/org.apache.cordova.file';
+                var dstDir = "entry.copy.dstDir";
+                var dstPath = joinURL(root.fullPath, dstDir);
+                // create a new directory entry to kick off it
+                deleteEntry(dstDir, function () {
+                    resolveLocalFileSystemURL(srcUrl, function(directory) {
+                        directory.copyTo(root, dstDir, function (directory) {
+                            expect(directory).toBeDefined();
+                            expect(directory.isFile).toBe(false);
+                            expect(directory.isDirectory).toBe(true);
+                            expect(directory.fullPath).toCanonicallyMatch(dstPath);
+                            expect(directory.name).toCanonicallyMatch(dstDir);
+                            root.getDirectory(dstDir, {
+                                create : false
+                            }, function (dirEntry) {
+                                expect(dirEntry).toBeDefined();
+                                expect(dirEntry.isFile).toBe(false);
+                                expect(dirEntry.isDirectory).toBe(true);
+                                expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
+                                expect(dirEntry.name).toCanonicallyMatch(dstDir);
+                                dirEntry.getFile('www/File.js', {
+                                    create : false
+                                }, function (fileEntry) {
+                                    expect(fileEntry).toBeDefined();
+                                    expect(fileEntry.isFile).toBe(true);
+                                    // cleanup
+                                    deleteEntry(dstDir, done);
+                                }, failed.bind(null, done, 'dirEntry.getFile - Error getting subfile'));
+                            }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory'));
+                        }, failed.bind(null, done, 'directory.copyTo - Error copying directory'));
+                    }, failed.bind(null, done, 'resolving src dir'));
+                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
+            });
         }
     });
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[09/13] cordova-plugin-file git commit: android: Use `CordovaResourceApi.mapUriToFile()` rather than own custom logic in ContentFilesystem

Posted by ag...@apache.org.
android: Use `CordovaResourceApi.mapUriToFile()` rather than own custom logic in ContentFilesystem


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/81ea13cf
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/81ea13cf
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/81ea13cf

Branch: refs/heads/master
Commit: 81ea13cf783359ee9db26bfd89bebcba241858e0
Parents: 4d1c277
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 14:19:52 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/ContentFilesystem.java | 21 ++-------------------
 1 file changed, 2 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/81ea13cf/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index 79e1ecc..f577054 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -251,15 +251,6 @@ public class ContentFilesystem extends Filesystem {
         return cursor;
 	}
 
-	protected String filesystemPathForCursor(Cursor cursor) {
-        final String[] LOCAL_FILE_PROJECTION = { MediaStore.Images.Media.DATA };
-        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
-        if (columnIndex != -1) {
-            return cursor.getString(columnIndex);
-        }
-        return null;
-	}
-
 	protected Integer resourceSizeForCursor(Cursor cursor) {
         int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
         if (columnIndex != -1) {
@@ -285,16 +276,8 @@ public class ContentFilesystem extends Filesystem {
 
     @Override
     public String filesystemPathForURL(LocalFilesystemURL url) {
-        Cursor cursor = openCursorForURL(url);
-        try {
-        	if (cursor != null && cursor.moveToFirst()) {
-        		return filesystemPathForCursor(cursor);
-        	}
-        } finally {
-            if (cursor != null)
-            	cursor.close();
-        }
-        return null;
+        File f = resourceApi.mapUriToFile(url.URL);
+        return f == null ? null : f.getAbsolutePath();
     }
 
 	@Override


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[10/13] cordova-plugin-file git commit: android: Add `listChildren()`: Java-consumable version of `readEntriesAtLocalURL()`

Posted by ag...@apache.org.
android: Add `listChildren()`: Java-consumable version of `readEntriesAtLocalURL()`


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/7051ad35
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/7051ad35
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/7051ad35

Branch: refs/heads/master
Commit: 7051ad35890bf37d17f18ea56d71d796e160fc0c
Parents: 356d334
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 22:42:06 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:08 2015 -0400

----------------------------------------------------------------------
 src/android/AssetFilesystem.java   | 14 +++++---------
 src/android/ContentFilesystem.java |  7 +++----
 src/android/Filesystem.java        | 13 ++++++++++++-
 src/android/LocalFilesystem.java   | 21 ++++++++++-----------
 4 files changed, 30 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7051ad35/src/android/AssetFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/AssetFilesystem.java b/src/android/AssetFilesystem.java
index 7a54e43..40968e0 100644
--- a/src/android/AssetFilesystem.java
+++ b/src/android/AssetFilesystem.java
@@ -97,27 +97,23 @@ public class AssetFilesystem extends Filesystem {
 
 
     @Override
-	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
-        String[] files;
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
         String pathNoSlashes = inputURL.path.substring(1);
         if (pathNoSlashes.endsWith("/")) {
             pathNoSlashes = pathNoSlashes.substring(0, pathNoSlashes.length() - 1);
         }
 
+        String[] files;
         try {
             files = assetManager.list(pathNoSlashes);
         } catch (IOException e) {
             throw new FileNotFoundException();
         }
 
-        JSONArray entries = new JSONArray();
-        if (files != null) {
-            for (String file : files) {
-                Uri newNativeUri = nativeUriForFullPath(new File(inputURL.path, file).getPath());
-                entries.put(makeEntryForNativeUri(newNativeUri));
-            }
+        LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
+        for (int i = 0; i < files.length; ++i) {
+            entries[i] = URLforFullPath(new File(inputURL.path, files[i]).getPath());
         }
-
         return entries;
 	}
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7051ad35/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index 25c6489..eab0b03 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -112,11 +112,10 @@ public class ContentFilesystem extends Filesystem {
 		throw new NoModificationAllowedException("Cannot remove content url");
 	}
 
-	@Override
-	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL)
-			throws FileNotFoundException {
+    @Override
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
         throw new UnsupportedOperationException("readEntriesAtLocalURL() not supported for content:. Use resolveLocalFileSystemURL instead.");
-	}
+    }
 
 	@Override
 	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7051ad35/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 724976d..309c0b8 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -106,7 +106,18 @@ public abstract class Filesystem {
 
 	abstract boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException;
 
-	abstract JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
+	abstract LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException;
+
+    public final JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+        LocalFilesystemURL[] children = listChildren(inputURL);
+        JSONArray entries = new JSONArray();
+        if (children != null) {
+            for (LocalFilesystemURL url : children) {
+                entries.put(makeEntryForURL(url));
+            }
+        }
+        return entries;
+    }
 
 	abstract JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
 

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/7051ad35/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 83c1384..93ba2b0 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -219,8 +219,8 @@ public class LocalFilesystem extends Filesystem {
         }
 	}
 
-	@Override
-	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
+    @Override
+    public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
         File fp = new File(filesystemPathForURL(inputURL));
 
         if (!fp.exists()) {
@@ -228,15 +228,14 @@ public class LocalFilesystem extends Filesystem {
             throw new FileNotFoundException();
         }
 
-        JSONArray entries = new JSONArray();
-
-        if (fp.isDirectory()) {
-            File[] files = fp.listFiles();
-            for (int i = 0; i < files.length; i++) {
-                if (files[i].canRead()) {
-                    entries.put(makeEntryForFile(files[i]));
-                }
-            }
+        File[] files = fp.listFiles();
+        if (files == null) {
+            // inputURL is a directory
+            return null;
+        }
+        LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
+        for (int i = 0; i < files.length; i++) {
+            entries[i] = URLforFilesystemPath(files[i].getPath());
         }
 
         return entries;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[08/13] cordova-plugin-file git commit: android: Use Uri.parse rather than manual parsing in resolveLocalFileSystemURI

Posted by ag...@apache.org.
android: Use Uri.parse rather than manual parsing in resolveLocalFileSystemURI


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/4d1c2770
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/4d1c2770
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/4d1c2770

Branch: refs/heads/master
Commit: 4d1c27708df6aaff82ff1ebafda330d13cbbfc8b
Parents: 1a79a05
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Mar 9 13:48:58 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:07 2015 -0400

----------------------------------------------------------------------
 src/android/FileUtils.java | 34 ++++++++--------------------------
 1 file changed, 8 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/4d1c2770/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index cd6f9c1..0063b43 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -584,44 +584,26 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Allows the user to look up the Entry for a file or directory referred to by a local URI.
      *
-     * @param url of the file/directory to look up
+     * @param uriString of the file/directory to look up
      * @return a JSONObject representing a Entry from the filesystem
      * @throws MalformedURLException if the url is not valid
      * @throws FileNotFoundException if the file does not exist
      * @throws IOException if the user can't read the file
      * @throws JSONException
      */
-    private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
+    private JSONObject resolveLocalFileSystemURI(String uriString) throws IOException, JSONException {
     	LocalFilesystemURL inputURL;
-    	if (url == null) {
+    	if (uriString == null) {
     		throw new MalformedURLException("Unrecognized filesystem URL");
     	}
-    	
-		/* Backwards-compatibility: Check for file:// urls */
-        if (url.startsWith("file:/")) {
-            if (!url.startsWith("file://")) {
-                url = "file:///" + url.substring(6);
-            }
-            String decoded = URLDecoder.decode(url, "UTF-8");
-    		/* This looks like a file url. Get the path, and see if any handlers recognize it. */
-    		String path;
-	        int questionMark = decoded.indexOf("?");
-            int pathEnd;
-	        if (questionMark < 0) {
-                pathEnd = decoded.length();
-	        } else {
-                pathEnd = questionMark;
-            }
+    	Uri uri = Uri.parse(uriString);
 
-            int thirdSlash = decoded.indexOf("/", 7);
-            if (thirdSlash < 0 || thirdSlash > pathEnd) {
-                path = "";
-            } else {
-                path = decoded.substring(thirdSlash, pathEnd);
-	        }
+		/* Backwards-compatibility: Check for file:// urls */
+        if ("file".equals(uri.getScheme())) {
+            String path = uri.getPath();
     		inputURL = this.filesystemURLforLocalPath(path);
     	} else {
-    		inputURL = new LocalFilesystemURL(url);
+    		inputURL = new LocalFilesystemURL(uri);
     	}
 
         try {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org


[13/13] cordova-plugin-file git commit: android: Don't use LimitedInputStream when reading entire file (optimization)

Posted by ag...@apache.org.
android: Don't use LimitedInputStream when reading entire file (optimization)


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/80cf1de4
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/80cf1de4
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/80cf1de4

Branch: refs/heads/master
Commit: 80cf1de400b43ab64facc821f5354beb34f412f3
Parents: 072acc7
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Mar 10 22:50:58 2015 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 11 11:35:08 2015 -0400

----------------------------------------------------------------------
 src/android/Filesystem.java | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/80cf1de4/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 45047c8..46786f3 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -263,7 +263,10 @@ public abstract class Filesystem {
             if (start > 0) {
                 ofrr.inputStream.skip(start);
             }
-            LimitedInputStream inputStream = new LimitedInputStream(ofrr.inputStream, numBytesToRead);
+            InputStream inputStream = ofrr.inputStream;
+            if (end < ofrr.length) {
+                inputStream = new LimitedInputStream(inputStream, numBytesToRead);
+            }
             readFileCallback.handleData(inputStream, ofrr.mimeType);
         } finally {
             ofrr.inputStream.close();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org