You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ia...@apache.org on 2014/01/07 16:28:05 UTC

git commit: Android: Better support for content urls and cross-filesystem copy/move ops

Updated Branches:
  refs/heads/dev b7882772b -> 68b29ccb4


Android: Better support for content urls and cross-filesystem copy/move ops


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/68b29ccb
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/68b29ccb
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/68b29ccb

Branch: refs/heads/dev
Commit: 68b29ccb4b5b0a115f018a058651daf0111cd709
Parents: b788277
Author: Ian Clelland <ic...@chromium.org>
Authored: Tue Jan 7 10:12:57 2014 -0500
Committer: Ian Clelland <ic...@chromium.org>
Committed: Tue Jan 7 10:27:30 2014 -0500

----------------------------------------------------------------------
 src/android/ContentFilesystem.java | 63 +++++++++++++++++++++++--
 src/android/FileUtils.java         | 25 ++--------
 src/android/Filesystem.java        |  2 +
 src/android/LocalFilesystem.java   | 81 ++++++++++++++++-----------------
 src/android/ReadFileCallback.java  |  4 +-
 5 files changed, 107 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/68b29ccb/src/android/ContentFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/ContentFilesystem.java b/src/android/ContentFilesystem.java
index e19f5bc..03a1939 100644
--- a/src/android/ContentFilesystem.java
+++ b/src/android/ContentFilesystem.java
@@ -1,8 +1,10 @@
 package org.apache.cordova.file;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 
 import org.apache.cordova.CordovaInterface;
 import org.json.JSONArray;
@@ -51,39 +53,63 @@ public class ContentFilesystem implements Filesystem {
     	  throw new IOException();
       }
 	}
+
 	@Override
 	public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
 			String fileName, JSONObject options, boolean directory) throws IOException {
 		throw new IOException("Cannot create content url");
 	}
+
 	@Override
 	public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL)
 			throws NoModificationAllowedException {
-		throw new NoModificationAllowedException("Cannot remove content url");
+
+		String filePath = filesystemPathForURL(inputURL);
+		File file = new File(filePath);
+		try {
+			this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+					MediaStore.Images.Media.DATA + " = ?",
+					new String[] { filePath });
+		} 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.
+		}
+		return file.delete();
 	}
+
 	@Override
 	public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL)
 			throws NoModificationAllowedException {
 		throw new NoModificationAllowedException("Cannot remove content url");
 	}
+
 	@Override
 	public JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL)
 			throws FileNotFoundException {
 		// TODO Auto-generated method stub
 		return null;
 	}
+
 	@Override
 	public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
 		// TODO Auto-generated method stub
 		return null;
 	}
+
 	@Override
 	public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL)
 			throws IOException {
-		// TODO Auto-generated method stub
-		// Can probably use same impl as LFS
-		return null;
+		LocalFilesystemURL newURL = new LocalFilesystemURL(inputURL.URL);
+
+    	if (!("".equals(inputURL.fullPath) || "/".equals(inputURL.fullPath))) {
+    		int end = inputURL.fullPath.endsWith("/") ? 1 : 0;
+            int lastPathStartsAt = inputURL.fullPath.lastIndexOf('/', inputURL.fullPath.length()-end)+1;
+    		newURL.fullPath = newURL.fullPath.substring(0,lastPathStartsAt);
+    	}
+    	return getEntryForLocalURL(newURL);
 	}
+
 	@Override
 	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
 			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move)
@@ -92,12 +118,32 @@ public class ContentFilesystem implements Filesystem {
 		// TODO Auto-generated method stub
 		return null;
 	}
+
 	@Override
 	public void readFileAtURL(LocalFilesystemURL inputURL, int start, int end,
 			ReadFileCallback readFileCallback) throws IOException {
-		// TODO Auto-generated method stub
+		int numBytesToRead = end - start;
+		byte[] bytes = new byte[numBytesToRead];
+		String contentType;
+		
+		File file = new File(this.filesystemPathForURL(inputURL));
+		contentType = FileHelper.getMimeTypeForExtension(file.getAbsolutePath());
 		
+		InputStream inputStream = new FileInputStream(file);
+		int numBytesRead = 0;
+		try {
+			if (start > 0) {
+				inputStream.skip(start);
+			}
+			while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
+				numBytesToRead -= numBytesRead;
+			}
+		} finally {
+			inputStream.close();
+		}
+		readFileCallback.handleData(bytes, contentType);
 	}
+
 	@Override
 	public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
 			int offset, boolean isBinary) throws NoModificationAllowedException {
@@ -135,4 +181,11 @@ public class ContentFilesystem implements Filesystem {
 		// TODO Auto-generated method stub
 		return null;
 	}
+
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		String path = filesystemPathForURL(inputURL);
+		File file = new File(path);
+		return file.exists();
+	}
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/68b29ccb/src/android/FileUtils.java
----------------------------------------------------------------------
diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java
index 25ea6b4..20a2700 100644
--- a/src/android/FileUtils.java
+++ b/src/android/FileUtils.java
@@ -61,6 +61,8 @@ 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;
 
     public static int TEMPORARY = 0;
     public static int PERSISTENT = 1;
@@ -312,9 +314,8 @@ public class FileUtils extends CordovaPlugin {
             final String fname=args.getString(0);
             threadhelper( new FileOp( ){
                 public void run() throws NoModificationAllowedException, InvalidModificationException, MalformedURLException {
-                    boolean success= remove(fname);
+                    boolean success = remove(fname);
                     if (success) {
-                        notifyDelete(fname);
                         callbackContext.success();
                     } else {
                         callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
@@ -439,6 +440,8 @@ public class FileUtils extends CordovaPlugin {
                         callbackContext.error(FileUtils.ENCODING_ERR);
                     } else if(e instanceof TypeMismatchException ) {
                         callbackContext.error(FileUtils.TYPE_MISMATCH_ERR);
+                    } else {
+                    	callbackContext.error(FileUtils.UNKNOWN_ERR);
                     }
                 }
             }
@@ -446,24 +449,6 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * Need to check to see if we need to clean up the content store
-     *
-     * @param filePath the path to check
-     */
-    private void notifyDelete(String filePath) {
-        String newFilePath = FileHelper.getRealPath(filePath, cordova);
-        try {
-            this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                    MediaStore.Images.Media.DATA + " = ?",
-                    new String[] { newFilePath });
-        } 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.
-        }
-    }
-
-    /**
      * 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

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/68b29ccb/src/android/Filesystem.java
----------------------------------------------------------------------
diff --git a/src/android/Filesystem.java b/src/android/Filesystem.java
index 7dd99f2..ba2c7bd 100644
--- a/src/android/Filesystem.java
+++ b/src/android/Filesystem.java
@@ -42,4 +42,6 @@ public interface Filesystem {
 
 	LocalFilesystemURL URLforFilesystemPath(String path);
 
+	boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL);
+
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/68b29ccb/src/android/LocalFilesystem.java
----------------------------------------------------------------------
diff --git a/src/android/LocalFilesystem.java b/src/android/LocalFilesystem.java
index 6634661..6c16e45 100644
--- a/src/android/LocalFilesystem.java
+++ b/src/android/LocalFilesystem.java
@@ -83,8 +83,7 @@ public class LocalFilesystem implements Filesystem {
 
 	@Override
 	public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
-      File fp = null;
-              fp = new File(this.fsRoot + inputURL.fullPath); //TODO: Proper fs.join
+      File fp = new File(this.fsRoot + inputURL.fullPath); //TODO: Proper fs.join
 
       if (!fp.exists()) {
           throw new FileNotFoundException();
@@ -282,7 +281,7 @@ public class LocalFilesystem implements Filesystem {
      * @param destination represents the destination file
      * @return a File object that represents the destination
      */
-    private File createDestination(String newName, File fp, File destination) {
+    private File createDestination(String newName, String oldName, File destination) {
         File destFile = null;
 
         // I know this looks weird but it is to work around a JSON bug.
@@ -293,7 +292,7 @@ public class LocalFilesystem implements Filesystem {
         if (newName != null) {
             destFile = new File(destination.getAbsolutePath() + File.separator + newName);
         } else {
-            destFile = new File(destination.getAbsolutePath() + File.separator + fp.getName());
+            destFile = new File(destination.getAbsolutePath() + File.separator + oldName);
         }
         return destFile;
     }
@@ -461,42 +460,33 @@ public class LocalFilesystem implements Filesystem {
 
         return makeEntryForFile(destinationDir, fsType);
     }
-
 	
 	@Override
 	public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
 			Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
-		
 
-        String newFileName = this.filesystemPathForURL(srcURL);
+		// Check to see if the destination directory exists
         String newParent = this.filesystemPathForURL(destURL);
-
-	    
         File destinationDir = new File(newParent);
         if (!destinationDir.exists()) {
             // The destination does not exist so we should fail.
             throw new FileNotFoundException("The source does not exist");
         }
-
+        
+        // Figure out where we should be copying to
+        String originalName = srcURL.URL.getLastPathSegment();
+        final File destination = createDestination(newName, originalName, destinationDir);
 
 	    if (LocalFilesystem.class.isInstance(srcFs)) {
-	    	
 	        /* Same FS, we can shortcut with NSFileManager operations */
-	    	
-
-	        File source = new File(newFileName);
+	        String srcFilesystemPath = this.filesystemPathForURL(srcURL);
+	        File source = new File(srcFilesystemPath);
 
 	        if (!source.exists()) {
 	            // The file/directory we are copying doesn't exist so we should fail.
 	            throw new FileNotFoundException("The source does not exist");
 	        }
 
-	        // Figure out where we should be copying to
-	        File destination = createDestination(newName, source, destinationDir);
-
-	        //Log.d(LOG_TAG, "Source: " + source.getAbsolutePath());
-	        //Log.d(LOG_TAG, "Destin: " + destination.getAbsolutePath());
-
 	        // Check to see if source and destination are the same file
 	        if (source.getAbsolutePath().equals(destination.getAbsolutePath())) {
 	            throw new InvalidModificationException("Can't copy a file onto itself");
@@ -510,36 +500,37 @@ public class LocalFilesystem implements Filesystem {
 	            }
 	        } else {
 	            if (move) {
-	                JSONObject newFileEntry = moveFile(source, destination, destURL.filesystemType);
-
-/*	                // If we've moved a file given its content URI, we need to clean up.
-	                // TODO: Move this to where it belongs, in cross-fs mv code below.
-	                if (srcURL.URL.getScheme().equals("content")) {
-	                    notifyDelete(fileName);
-	                }
-*/
-	                return newFileEntry;
+	                return moveFile(source, destination, destURL.filesystemType);
 	            } else {
 	                return copyFile(source, destination, destURL.filesystemType);
 	            }
 	        }
-
 	    	
 	    } else {
-/*	        // Need to copy the hard way
-	    	srcFs.readFileAtURL(srcURL, 0, -1, new ReadFileCallback() {
-	    		void run(data, mimetype, errorcode) {
-	    			if (data != null) {
-	    				//write data to file
-	    				// send success message -- call original callback?
+	        // Need to copy the hard way
+	    	// First, check to see that we can do it
+	    	if (!move || srcFs.canRemoveFileAtLocalURL(srcURL)) {
+	    		srcFs.readFileAtURL(srcURL, 0, -1, new ReadFileCallback() {
+	    			public void handleData(byte[] data, String contentType) throws IOException {
+	    				if (data != null) {
+	    					//write data to file
+	    					FileOutputStream os = new FileOutputStream(destination);
+	    					os.write(data);
+	    					os.close();
+	    				} else {
+	    					throw new IOException("Cannot read file at source URL");
+	    				}
 	    			}
-	    			// error
-	    		}
-    		});
-	    	return null; // Async, will return later
-*/
+	    		});
+				if (move) {
+					// Delete original
+					srcFs.removeFileAtLocalURL(srcURL);
+				}
+		        return makeEntryForFile(destination, destURL.filesystemType);
+	    	} else {
+	    		throw new NoModificationAllowedException("Cannot move file at source URL");
+	    	}
     	}
-		return null;	    
 	}
 
 	@Override
@@ -632,5 +623,11 @@ public class LocalFilesystem implements Filesystem {
 
 	}
 
+	@Override
+	public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
+		String path = filesystemPathForURL(inputURL);
+		File file = new File(path);
+		return file.exists();
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/68b29ccb/src/android/ReadFileCallback.java
----------------------------------------------------------------------
diff --git a/src/android/ReadFileCallback.java b/src/android/ReadFileCallback.java
index 77bb7da..b8ba02d 100644
--- a/src/android/ReadFileCallback.java
+++ b/src/android/ReadFileCallback.java
@@ -1,5 +1,7 @@
 package org.apache.cordova.file;
 
+import java.io.IOException;
+
 public interface ReadFileCallback {
-	public void handleData(byte[] data, String contentType);
+	public void handleData(byte[] data, String contentType) throws IOException;
 }