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:23 UTC
[12/13] cordova-plugin-file git commit: CB-6428 android: Add support
for file:///android_asset URLs
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