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 2013/07/05 14:48:20 UTC

[39/51] [partial] Merge master2->master

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ac0c95be/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
deleted file mode 100644
index c1ca15c..0000000
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
+++ /dev/null
@@ -1,959 +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;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLDecoder;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-import android.webkit.CookieManager;
-
-public class FileTransfer extends CordovaPlugin {
-
-    private static final String LOG_TAG = "FileTransfer";
-    private static final String LINE_START = "--";
-    private static final String LINE_END = "\r\n";
-    private static final String BOUNDARY =  "+++++";
-
-    public static int FILE_NOT_FOUND_ERR = 1;
-    public static int INVALID_URL_ERR = 2;
-    public static int CONNECTION_ERR = 3;
-    public static int ABORTED_ERR = 4;
-
-    private static HashMap<String, RequestContext> activeRequests = new HashMap<String, RequestContext>();
-    private static final int MAX_BUFFER_SIZE = 16 * 1024;
-
-    private static final class RequestContext {
-        String source;
-        String target;
-        File targetFile;
-        CallbackContext callbackContext;
-        InputStream currentInputStream;
-        OutputStream currentOutputStream;
-        boolean aborted;
-        RequestContext(String source, String target, CallbackContext callbackContext) {
-            this.source = source;
-            this.target = target;
-            this.callbackContext = callbackContext;
-        }
-        void sendPluginResult(PluginResult pluginResult) {
-            synchronized (this) {
-                if (!aborted) {
-                    callbackContext.sendPluginResult(pluginResult);
-                }
-            }
-        }
-    }
-
-    /**
-     * Adds an interface method to an InputStream to return the number of bytes
-     * read from the raw stream. This is used to track total progress against
-     * the HTTP Content-Length header value from the server.
-     */
-    private static abstract class TrackingInputStream extends FilterInputStream {
-    	public TrackingInputStream(final InputStream in) {
-    		super(in);
-    	}
-        public abstract long getTotalRawBytesRead();
-	}
-
-    private static class ExposedGZIPInputStream extends GZIPInputStream {
-	    public ExposedGZIPInputStream(final InputStream in) throws IOException {
-	    	super(in);
-	    }
-	    public Inflater getInflater() {
-	    	return inf;
-	    }
-	}
-
-    /**
-     * Provides raw bytes-read tracking for a GZIP input stream. Reports the
-     * total number of compressed bytes read from the input, rather than the
-     * number of uncompressed bytes.
-     */
-    private static class TrackingGZIPInputStream extends TrackingInputStream {
-    	private ExposedGZIPInputStream gzin;
-	    public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
-	    	super(gzin);
-	    	this.gzin = gzin;
-	    }
-	    public long getTotalRawBytesRead() {
-	    	return gzin.getInflater().getBytesRead();
-	    }
-	}
-
-    /**
-     * Provides simple total-bytes-read tracking for an existing InputStream
-     */
-    private static class TrackingHTTPInputStream extends TrackingInputStream {
-        private long bytesRead = 0;
-        public TrackingHTTPInputStream(InputStream stream) {
-            super(stream);
-        }
-
-        private int updateBytesRead(int newBytesRead) {
-        	if (newBytesRead != -1) {
-        		bytesRead += newBytesRead;
-        	}
-        	return newBytesRead;
-        }
-
-        @Override
-        public int read() throws IOException {
-            return updateBytesRead(super.read());
-        }
-
-        @Override
-        public int read(byte[] buffer) throws IOException {
-            return updateBytesRead(super.read(buffer));
-        }
-
-        @Override
-        public int read(byte[] bytes, int offset, int count) throws IOException {
-            return updateBytesRead(super.read(bytes, offset, count));
-        }
-
-        public long getTotalRawBytesRead() {
-        	return bytesRead;
-        }
-    }
-
-    /**
-     * Works around a bug on Android 2.3.
-     * http://code.google.com/p/android/issues/detail?id=14562
-     */
-    private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
-        private boolean done;
-        
-        public DoneHandlerInputStream(InputStream stream) {
-            super(stream);
-        }
-        
-        @Override
-        public int read() throws IOException {
-            int result = done ? -1 : super.read();
-            done = (result == -1);
-            return result;
-        }
-
-        @Override
-        public int read(byte[] buffer) throws IOException {
-            int result = done ? -1 : super.read(buffer);
-            done = (result == -1);
-            return result;
-        }
-
-        @Override
-        public int read(byte[] bytes, int offset, int count) throws IOException {
-            int result = done ? -1 : super.read(bytes, offset, count);
-            done = (result == -1);
-            return result;
-        }
-    }
-    
-    @Override
-    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
-        if (action.equals("upload") || action.equals("download")) {
-            String source = args.getString(0);
-            String target = args.getString(1);
-
-            if (action.equals("upload")) {
-                try {
-                    source = URLDecoder.decode(source, "UTF-8");
-                    upload(source, target, args, callbackContext);
-                } catch (UnsupportedEncodingException e) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, "UTF-8 error."));
-                }
-            } else {
-                download(source, target, args, callbackContext);
-            }
-            return true;
-        } else if (action.equals("abort")) {
-            String objectId = args.getString(0);
-            abort(objectId);
-            callbackContext.success();
-            return true;
-        }
-        return false;
-    }
-
-    private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
-        try {
-            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
-                String headerKey = iter.next().toString();
-                JSONArray headerValues = headers.optJSONArray(headerKey);
-                if (headerValues == null) {
-                    headerValues = new JSONArray();
-                    headerValues.put(headers.getString(headerKey));
-                }
-                connection.setRequestProperty(headerKey, headerValues.getString(0));
-                for (int i = 1; i < headerValues.length(); ++i) {
-                    connection.addRequestProperty(headerKey, headerValues.getString(i));
-                }
-            }
-        } catch (JSONException e1) {
-          // No headers to be manipulated!
-        }
-    }
-
-    /**
-     * Uploads the specified file to the server URL provided using an HTTP multipart request.
-     * @param source        Full path of the file on the file system
-     * @param target        URL of the server to receive the file
-     * @param args          JSON Array of args
-     * @param callbackContext    callback id for optional progress reports
-     *
-     * args[2] fileKey       Name of file request parameter
-     * args[3] fileName      File name to be used on server
-     * args[4] mimeType      Describes file content type
-     * args[5] params        key:value pairs of user-defined parameters
-     * @return FileUploadResult containing result of upload request
-     */
-    private void upload(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        Log.d(LOG_TAG, "upload " + source + " to " +  target);
-
-        // Setup the options
-        final String fileKey = getArgument(args, 2, "file");
-        final String fileName = getArgument(args, 3, "image.jpg");
-        final String mimeType = getArgument(args, 4, "image/jpeg");
-        final JSONObject params = args.optJSONObject(5) == null ? new JSONObject() : args.optJSONObject(5);
-        final boolean trustEveryone = args.optBoolean(6);
-        // Always use chunked mode unless set to false as per API
-        final boolean chunkedMode = args.optBoolean(7) || args.isNull(7);
-        // Look for headers on the params map for backwards compatibility with older Cordova versions.
-        final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
-        final String objectId = args.getString(9);
-        final String httpMethod = getArgument(args, 10, "POST");
-
-        Log.d(LOG_TAG, "fileKey: " + fileKey);
-        Log.d(LOG_TAG, "fileName: " + fileName);
-        Log.d(LOG_TAG, "mimeType: " + mimeType);
-        Log.d(LOG_TAG, "params: " + params);
-        Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
-        Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
-        Log.d(LOG_TAG, "headers: " + headers);
-        Log.d(LOG_TAG, "objectId: " + objectId);
-        Log.d(LOG_TAG, "httpMethod: " + httpMethod);
-        
-        final URL url;
-        try {
-            url = new URL(target);
-        } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-        final boolean useHttps = url.getProtocol().equals("https");
-
-        final RequestContext context = new RequestContext(source, target, callbackContext);
-        synchronized (activeRequests) {
-            activeRequests.put(objectId, context);
-        }
-        
-        cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                if (context.aborted) {
-                    return;
-                }
-                HttpURLConnection conn = null;
-                HostnameVerifier oldHostnameVerifier = null;
-                SSLSocketFactory oldSocketFactory = null;
-                int totalBytes = 0;
-                int fixedLength = -1;
-                try {
-                    // Create return object
-                    FileUploadResult result = new FileUploadResult();
-                    FileProgressResult progress = new FileProgressResult();
-
-                    //------------------ CLIENT REQUEST
-                    // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow self signed certificate
-                        if (!trustEveryone) {
-                            conn = (HttpsURLConnection) url.openConnection();
-                        }
-                        // Use our HTTPS connection that blindly trusts everyone.
-                        // This should only be used in debug environments
-                        else {
-                            // Setup the HTTPS connection class to trust everyone
-                            HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
-                            oldSocketFactory  = trustAllHosts(https);
-                            // Save the current hostnameVerifier
-                            oldHostnameVerifier = https.getHostnameVerifier();
-                            // Setup the connection not to verify hostnames
-                            https.setHostnameVerifier(DO_NOT_VERIFY);
-                            conn = https;
-                        }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                        conn = (HttpURLConnection) url.openConnection();
-                    }
-
-                    // Allow Inputs
-                    conn.setDoInput(true);
-
-                    // Allow Outputs
-                    conn.setDoOutput(true);
-
-                    // Don't use a cached copy.
-                    conn.setUseCaches(false);
-
-                    // Use a post method.
-                    conn.setRequestMethod(httpMethod);
-                    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
-
-                    // Set the cookies on the response
-                    String cookie = CookieManager.getInstance().getCookie(target);
-                    if (cookie != null) {
-                        conn.setRequestProperty("Cookie", cookie);
-                    }
-
-                    // Handle the other headers
-                    if (headers != null) {
-                        addHeadersToRequest(conn, headers);
-                    }
-
-                    /*
-                        * Store the non-file portions of the multipart data as a string, so that we can add it
-                        * to the contentSize, since it is part of the body of the HTTP request.
-                        */
-                    StringBuilder beforeData = new StringBuilder();
-                    try {
-                        for (Iterator<?> iter = params.keys(); iter.hasNext();) {
-                            Object key = iter.next();
-                            if(!String.valueOf(key).equals("headers"))
-                            {
-                              beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
-                              beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
-                              beforeData.append(LINE_END).append(LINE_END);
-                              beforeData.append(params.getString(key.toString()));
-                              beforeData.append(LINE_END);
-                            }
-                        }
-                    } catch (JSONException e) {
-                        Log.e(LOG_TAG, e.getMessage(), e);
-                    }
-
-                    beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
-                    beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
-                    beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
-                    beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
-                    byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
-                    byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
-
-                    
-                    // Get a input stream of the file on the phone
-                    InputStream sourceInputStream = getPathFromUri(source);
-                    
-                    int stringLength = beforeDataBytes.length + tailParamsBytes.length;
-                    if (sourceInputStream instanceof FileInputStream) {
-                        fixedLength = (int) ((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
-                        progress.setLengthComputable(true);
-                        progress.setTotal(fixedLength);
-                    }
-                    Log.d(LOG_TAG, "Content Length: " + fixedLength);
-                    // setFixedLengthStreamingMode causes and OutOfMemoryException on pre-Froyo devices.
-                    // http://code.google.com/p/android/issues/detail?id=3164
-                    // It also causes OOM if HTTPS is used, even on newer devices.
-                    boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
-                    useChunkedMode = useChunkedMode || (fixedLength == -1);
-
-                    if (useChunkedMode) {
-                        conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
-                        // Although setChunkedStreamingMode sets this header, setting it explicitly here works
-                        // around an OutOfMemoryException when using https.
-                        conn.setRequestProperty("Transfer-Encoding", "chunked");
-                    } else {
-                        conn.setFixedLengthStreamingMode(fixedLength);
-                    }
-
-                    conn.connect();
-                    
-                    OutputStream sendStream = null;
-                    try {
-                        sendStream = conn.getOutputStream();
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentOutputStream = sendStream;
-                        }
-                        //We don't want to change encoding, we just want this to write for all Unicode.
-                        sendStream.write(beforeDataBytes);
-                        totalBytes += beforeDataBytes.length;
-    
-                        // create a buffer of maximum size
-                        int bytesAvailable = sourceInputStream.available();
-                        int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
-                        byte[] buffer = new byte[bufferSize];
-    
-                        // read file and write it into form...
-                        int bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-    
-                        long prevBytesRead = 0;
-                        while (bytesRead > 0) {
-                            result.setBytesSent(totalBytes);
-                            sendStream.write(buffer, 0, bytesRead);
-                            totalBytes += bytesRead;
-                            if (totalBytes > prevBytesRead + 102400) {
-                                prevBytesRead = totalBytes;
-                                Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
-                            }
-                            bytesAvailable = sourceInputStream.available();
-                            bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
-                            bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-
-                            // Send a progress event.
-                            progress.setLoaded(totalBytes);
-                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
-                            progressResult.setKeepCallback(true);
-                            context.sendPluginResult(progressResult);
-                        }
-    
-                        // send multipart form data necessary after file data...
-                        sendStream.write(tailParamsBytes);
-                        totalBytes += tailParamsBytes.length;
-                        sendStream.flush();
-                    } finally {
-                        safeClose(sourceInputStream);
-                        safeClose(sendStream);
-                    }
-                    context.currentOutputStream = null;
-                    Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
-
-                    //------------------ read the SERVER RESPONSE
-                    String responseString;
-                    int responseCode = conn.getResponseCode();
-                    Log.d(LOG_TAG, "response code: " + responseCode);
-                    Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
-                    TrackingInputStream inStream = null;
-                    try {
-                        inStream = getInputStream(conn);
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentInputStream = inStream;
-                        }
-                        
-                        ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
-                        byte[] buffer = new byte[1024];
-                        int bytesRead = 0;
-                        // write bytes to file
-                        while ((bytesRead = inStream.read(buffer)) > 0) {
-                            out.write(buffer, 0, bytesRead);
-                        }
-                        responseString = out.toString("UTF-8");
-                    } finally {
-                        context.currentInputStream = null;
-                        safeClose(inStream);
-                    }
-                    
-                    Log.d(LOG_TAG, "got response from server");
-                    Log.d(LOG_TAG, responseString.substring(0, Math.min(256, responseString.length())));
-                    
-                    // send request and retrieve response
-                    result.setResponseCode(responseCode);
-                    result.setResponse(responseString);
-
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
-                } catch (FileNotFoundException e) {
-                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } catch (IOException e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } catch (JSONException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
-                } catch (Throwable t) {
-                    // Shouldn't happen, but will
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), t);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } finally {
-                    synchronized (activeRequests) {
-                        activeRequests.remove(objectId);
-                    }
-
-                    if (conn != null) {
-                        // Revert back to the proper verifier and socket factories
-                        // Revert back to the proper verifier and socket factories
-                        if (trustEveryone && useHttps) {
-                            HttpsURLConnection https = (HttpsURLConnection) conn;
-                            https.setHostnameVerifier(oldHostnameVerifier);
-                            https.setSSLSocketFactory(oldSocketFactory);
-                        }
-                    }
-                }                
-            }
-        });
-    }
-
-    private static void safeClose(Closeable stream) {
-        if (stream != null) {
-            try {
-                stream.close();
-            } catch (IOException e) {
-            }
-        }
-    }
-
-    private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-            return new DoneHandlerInputStream(conn.getInputStream());
-        }
-        String encoding = conn.getContentEncoding();
-        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
-        	return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
-        }
-        return new TrackingHTTPInputStream(conn.getInputStream());
-    }
-
-    // always verify the host - don't check for certificate
-    private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
-        public boolean verify(String hostname, SSLSession session) {
-            return true;
-        }
-    };
-    // Create a trust manager that does not validate certificate chains
-    private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
-        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
-            return new java.security.cert.X509Certificate[] {};
-        }
-        
-        public void checkClientTrusted(X509Certificate[] chain,
-                String authType) throws CertificateException {
-        }
-        
-        public void checkServerTrusted(X509Certificate[] chain,
-                String authType) throws CertificateException {
-        }
-    } };
-
-    /**
-     * This function will install a trust manager that will blindly trust all SSL
-     * certificates.  The reason this code is being added is to enable developers
-     * to do development using self signed SSL certificates on their web server.
-     *
-     * The standard HttpsURLConnection class will throw an exception on self
-     * signed certificates if this code is not run.
-     */
-    private static SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
-        // Install the all-trusting trust manager
-        SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
-        try {
-            // Install our all trusting manager
-            SSLContext sc = SSLContext.getInstance("TLS");
-            sc.init(null, trustAllCerts, new java.security.SecureRandom());
-            SSLSocketFactory newFactory = sc.getSocketFactory();
-            connection.setSSLSocketFactory(newFactory);
-        } catch (Exception e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return oldFactory;
-    }
-
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
-
-        int httpStatus = 0;
-        StringBuilder bodyBuilder = new StringBuilder();
-        String body = null;
-        if (connection != null) {
-            try {
-                if (connection instanceof HttpURLConnection) {
-                    httpStatus = ((HttpURLConnection)connection).getResponseCode();
-                    InputStream err = ((HttpURLConnection) connection).getErrorStream();
-                    if(err != null)
-                    {
-                        BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
-                        String line = reader.readLine();
-                        while(line != null)
-                        {
-                            bodyBuilder.append(line);
-                            line = reader.readLine();
-                            if(line != null)
-                                bodyBuilder.append('\n');
-                        }
-                        body = bodyBuilder.toString();
-                    }
-                }
-            } catch (IOException e) {
-                Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
-            }
-        }
-
-        return createFileTransferError(errorCode, source, target, body, httpStatus);
-    }
-
-        /**
-        * Create an error object based on the passed in errorCode
-        * @param errorCode 	the error
-        * @return JSONObject containing the error
-        */
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
-        JSONObject error = null;
-        try {
-            error = new JSONObject();
-            error.put("code", errorCode);
-            error.put("source", source);
-            error.put("target", target);
-            if(body != null)
-            {
-                error.put("body", body);
-            }   
-            if (httpStatus != null) {
-                error.put("http_status", httpStatus);
-            }
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return error;
-    }
-
-    /**
-     * Convenience method to read a parameter from the list of JSON args.
-     * @param args			the args passed to the Plugin
-     * @param position		the position to retrieve the arg from
-     * @param defaultString the default to be used if the arg does not exist
-     * @return String with the retrieved value
-     */
-    private static String getArgument(JSONArray args, int position, String defaultString) {
-        String arg = defaultString;
-        if (args.length() >= position) {
-            arg = args.optString(position);
-            if (arg == null || "null".equals(arg)) {
-                arg = defaultString;
-            }
-        }
-        return arg;
-    }
-
-    /**
-     * Downloads a file form a given URL and saves it to the specified directory.
-     *
-     * @param source        URL of the server to receive the file
-     * @param target      	Full path of the file on the file system
-     */
-    private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        Log.d(LOG_TAG, "download " + source + " to " +  target);
-
-        final boolean trustEveryone = args.optBoolean(2);
-        final String objectId = args.getString(3);
-        final JSONObject headers = args.optJSONObject(4);
-
-        final URL url;
-        try {
-            url = new URL(source);
-        } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-        final boolean useHttps = url.getProtocol().equals("https");
-
-        if (!Config.isUrlWhiteListed(source)) {
-            Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
-            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-
-        
-        final RequestContext context = new RequestContext(source, target, callbackContext);
-        synchronized (activeRequests) {
-            activeRequests.put(objectId, context);
-        }
-        
-        cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                if (context.aborted) {
-                    return;
-                }
-                URLConnection connection = null;
-                HostnameVerifier oldHostnameVerifier = null;
-                SSLSocketFactory oldSocketFactory = null;
-                File file = null;
-                PluginResult result = null;
-
-                try {
-                    file = getFileFromPath(target);
-                    context.targetFile = file;
-                    // create needed directories
-                    file.getParentFile().mkdirs();
-        
-                    // connect to server
-                    // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow self signed certificate
-                        if (!trustEveryone) {
-                            connection = (HttpsURLConnection) url.openConnection();
-                        }
-                        // Use our HTTPS connection that blindly trusts everyone.
-                        // This should only be used in debug environments
-                        else {
-                            // Setup the HTTPS connection class to trust everyone
-                            HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
-                            oldSocketFactory = trustAllHosts(https);
-                            // Save the current hostnameVerifier
-                            oldHostnameVerifier = https.getHostnameVerifier();
-                            // Setup the connection not to verify hostnames
-                            https.setHostnameVerifier(DO_NOT_VERIFY);
-                            connection = https;
-                        }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                          connection = url.openConnection();
-                    }
-    
-                    if (connection instanceof HttpURLConnection) {
-                        ((HttpURLConnection)connection).setRequestMethod("GET");
-                    }
-    
-                    //Add cookie support
-                    String cookie = CookieManager.getInstance().getCookie(source);
-                    if(cookie != null)
-                    {
-                        connection.setRequestProperty("cookie", cookie);
-                    }
-                    
-                    // This must be explicitly set for gzip progress tracking to work.
-                    connection.setRequestProperty("Accept-Encoding", "gzip");
-
-                    // Handle the other headers
-                    if (headers != null) {
-                        addHeadersToRequest(connection, headers);
-                    }
-    
-                    connection.connect();
-    
-                    Log.d(LOG_TAG, "Download file:" + url);
-
-                    FileProgressResult progress = new FileProgressResult();
-                    if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
-                        // Only trust content-length header if we understand
-                        // the encoding -- identity or gzip
-                        progress.setLengthComputable(true);
-                        progress.setTotal(connection.getContentLength());
-                    }
-                    
-                    FileOutputStream outputStream = null;
-                    TrackingInputStream inputStream = null;
-                    
-                    try {
-                        inputStream = getInputStream(connection);
-                        outputStream = new FileOutputStream(file);
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentInputStream = inputStream;
-                        }
-                        
-                        // write bytes to file
-                        byte[] buffer = new byte[MAX_BUFFER_SIZE];
-                        int bytesRead = 0;
-                        while ((bytesRead = inputStream.read(buffer)) > 0) {
-                            outputStream.write(buffer, 0, bytesRead);
-                            // Send a progress event.
-                            progress.setLoaded(inputStream.getTotalRawBytesRead());
-                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
-                            progressResult.setKeepCallback(true);
-                            context.sendPluginResult(progressResult);
-                        }
-                    } finally {
-                        context.currentInputStream = null;
-                        safeClose(inputStream);
-                        safeClose(outputStream);
-                    }
-    
-                    Log.d(LOG_TAG, "Saved file: " + target);
-    
-                    // create FileEntry object
-                    JSONObject fileEntry = FileUtils.getEntry(file);
-                    
-                    result = new PluginResult(PluginResult.Status.OK, fileEntry);
-                } catch (FileNotFoundException e) {
-                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } catch (IOException e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } catch (JSONException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                    result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
-                } catch (Throwable e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } finally {
-                    synchronized (activeRequests) {
-                        activeRequests.remove(objectId);
-                    }
-
-                    if (connection != null) {
-                        // Revert back to the proper verifier and socket factories
-                        if (trustEveryone && useHttps) {
-                            HttpsURLConnection https = (HttpsURLConnection) connection;
-                            https.setHostnameVerifier(oldHostnameVerifier);
-                            https.setSSLSocketFactory(oldSocketFactory);
-                        }
-                    }
-
-                    if (result == null) {
-                        result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
-                    }
-                    // Remove incomplete download.
-                    if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
-                        file.delete();
-                    }
-                    context.sendPluginResult(result);
-                }
-            }
-        });
-    }
-
-    /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path foo
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content:")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else if (path.startsWith("file://")) {
-            int question = path.indexOf("?");
-            if (question == -1) {
-                return new FileInputStream(path.substring(7));
-            } else {
-                return new FileInputStream(path.substring(7, question));
-            }
-        }
-        else {
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Get a File object from the passed in path
-     *
-     * @param path file path
-     * @return file object
-     */
-    private File getFileFromPath(String path) throws FileNotFoundException {
-        File file;
-        String prefix = "file://";
-
-        if (path.startsWith(prefix)) {
-            file = new File(path.substring(prefix.length()));
-        } else {
-            file = new File(path);
-        }
-
-        if (file.getParent() == null) {
-            throw new FileNotFoundException();
-        }
-
-        return file;
-    }
-
-    /**
-     * Abort an ongoing upload or download.
-     */
-    private void abort(String objectId) {
-        final RequestContext context;
-        synchronized (activeRequests) {
-            context = activeRequests.remove(objectId);
-        }
-        if (context != null) {
-            File file = context.targetFile;
-            if (file != null) {
-                file.delete();
-            }
-            // Trigger the abort callback immediately to minimize latency between it and abort() being called.
-            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
-            synchronized (context) {
-                context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
-                context.aborted = true;
-            }
-            // Closing the streams can block, so execute on a background thread.
-            cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    synchronized (context) {
-                        safeClose(context.currentInputStream);
-                        safeClose(context.currentOutputStream);
-                    }
-                }
-            });
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ac0c95be/lib/cordova-android/framework/src/org/apache/cordova/FileUploadResult.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileUploadResult.java b/lib/cordova-android/framework/src/org/apache/cordova/FileUploadResult.java
deleted file mode 100644
index b556869..0000000
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileUploadResult.java
+++ /dev/null
@@ -1,73 +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;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Encapsulates the result and/or status of uploading a file to a remote server.
- */
-public class FileUploadResult {
-
-    private long bytesSent = 0;         // bytes sent
-    private int responseCode = -1;      // HTTP response code
-    private String response = null;     // HTTP response
-    private String objectId = null;     // FileTransfer object id
-
-    public long getBytesSent() {
-        return bytesSent;
-    }
-
-    public void setBytesSent(long bytes) {
-        this.bytesSent = bytes;
-    }
-
-    public int getResponseCode() {
-        return responseCode;
-    }
-
-    public void setResponseCode(int responseCode) {
-        this.responseCode = responseCode;
-    }
-
-    public String getResponse() {
-        return response;
-    }
-
-    public void setResponse(String response) {
-        this.response = response;
-    }
-
-    public String getObjectId() {
-        return objectId;
-    }
-
-    public void setObjectId(String objectId) {
-        this.objectId = objectId;
-    }
-
-    public JSONObject toJSONObject() throws JSONException {
-        return new JSONObject(
-                "{bytesSent:" + bytesSent +
-                ",responseCode:" + responseCode +
-                ",response:" + JSONObject.quote(response) +
-                ",objectId:" + JSONObject.quote(objectId) + "}");
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ac0c95be/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
deleted file mode 100755
index 2135be9..0000000
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
+++ /dev/null
@@ -1,1059 +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;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.apache.cordova.file.EncodingException;
-import org.apache.cordova.file.FileExistsException;
-import org.apache.cordova.file.InvalidModificationException;
-import org.apache.cordova.file.NoModificationAllowedException;
-import org.apache.cordova.file.TypeMismatchException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-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.InputStream;
-import java.io.RandomAccessFile;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.FileChannel;
-
-/**
- * This class provides SD card file and directory services to JavaScript.
- * Only files on the SD card can be accessed.
- */
-public class FileUtils extends CordovaPlugin {
-    private static final String LOG_TAG = "FileUtils";
-
-    public static int NOT_FOUND_ERR = 1;
-    public static int SECURITY_ERR = 2;
-    public static int ABORT_ERR = 3;
-
-    public static int NOT_READABLE_ERR = 4;
-    public static int ENCODING_ERR = 5;
-    public static int NO_MODIFICATION_ALLOWED_ERR = 6;
-    public static int INVALID_STATE_ERR = 7;
-    public static int SYNTAX_ERR = 8;
-    public static int INVALID_MODIFICATION_ERR = 9;
-    public static int QUOTA_EXCEEDED_ERR = 10;
-    public static int TYPE_MISMATCH_ERR = 11;
-    public static int PATH_EXISTS_ERR = 12;
-
-    public static int TEMPORARY = 0;
-    public static int PERSISTENT = 1;
-    public static int RESOURCE = 2;
-    public static int APPLICATION = 3;
-
-    /**
-     * Constructor.
-     */
-    public FileUtils() {
-    }
-
-    /**
-     * Executes the request and returns whether the action was valid.
-     *
-     * @param action 		The action to execute.
-     * @param args 		JSONArray of arguments for the plugin.
-     * @param callbackContext	The callback context used when calling back into JavaScript.
-     * @return 			True if the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        try {
-            if (action.equals("testSaveLocationExists")) {
-                boolean b = DirectoryManager.testSaveLocationExists();
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("getFreeDiskSpace")) {
-                long l = DirectoryManager.getFreeDiskSpace(false);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
-            }
-            else if (action.equals("testFileExists")) {
-                boolean b = DirectoryManager.testFileExists(args.getString(0));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("testDirectoryExists")) {
-                boolean b = DirectoryManager.testFileExists(args.getString(0));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("readAsText")) {
-                String encoding = args.getString(1);
-                int start = args.getInt(2);
-                int end = args.getInt(3);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
-            }
-            else if (action.equals("readAsDataURL")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, -1);
-            }
-            else if (action.equals("readAsArrayBuffer")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
-            }
-            else if (action.equals("readAsBinaryString")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
-            }
-            else if (action.equals("write")) {
-                long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
-            }
-            else if (action.equals("truncate")) {
-                long fileSize = this.truncateFile(args.getString(0), args.getLong(1));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
-            }
-            else if (action.equals("requestFileSystem")) {
-                long size = args.optLong(1);
-                if (size != 0 && size > (DirectoryManager.getFreeDiskSpace(true) * 1024)) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR));
-                } else {
-                    JSONObject obj = requestFileSystem(args.getInt(0));
-                    callbackContext.success(obj);
-                }
-            }
-            else if (action.equals("resolveLocalFileSystemURI")) {
-                JSONObject obj = resolveLocalFileSystemURI(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getMetadata")) {
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getMetadata(args.getString(0))));
-            }
-            else if (action.equals("getFileMetadata")) {
-                JSONObject obj = getFileMetadata(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getParent")) {
-                JSONObject obj = getParent(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getDirectory")) {
-                JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), true);
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getFile")) {
-                JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), false);
-                callbackContext.success(obj);
-            }
-            else if (action.equals("remove")) {
-                boolean success;
-
-                success = remove(args.getString(0));
-
-                if (success) {
-                    notifyDelete(args.getString(0));
-                    callbackContext.success();
-                } else {
-                    callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-                }
-            }
-            else if (action.equals("removeRecursively")) {
-                boolean success = removeRecursively(args.getString(0));
-                if (success) {
-                    callbackContext.success();
-                } else {
-                    callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-                }
-            }
-            else if (action.equals("moveTo")) {
-                JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), true);
-                callbackContext.success(entry);
-            }
-            else if (action.equals("copyTo")) {
-                JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), false);
-                callbackContext.success(entry);
-            }
-            else if (action.equals("readEntries")) {
-                JSONArray entries = readEntries(args.getString(0));
-                callbackContext.success(entries);
-            }
-            else {
-                return false;
-            }
-        } catch (FileNotFoundException e) {
-            callbackContext.error(FileUtils.NOT_FOUND_ERR);
-        } catch (FileExistsException e) {
-            callbackContext.error(FileUtils.PATH_EXISTS_ERR);
-        } catch (NoModificationAllowedException e) {
-            callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-        } catch (InvalidModificationException e) {
-            callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
-        } catch (MalformedURLException e) {
-            callbackContext.error(FileUtils.ENCODING_ERR);
-        } catch (IOException e) {
-            callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
-        } catch (EncodingException e) {
-            callbackContext.error(FileUtils.ENCODING_ERR);
-        } catch (TypeMismatchException e) {
-            callbackContext.error(FileUtils.TYPE_MISMATCH_ERR);
-        }
-        return true;
-    }
-
-    /**
-     * 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
-     * @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
-     */
-    @SuppressWarnings("deprecation")
-    private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
-        String decoded = URLDecoder.decode(url, "UTF-8");
-
-        File fp = null;
-
-        // Handle the special case where you get an Android content:// uri.
-        if (decoded.startsWith("content:")) {
-            Cursor cursor = this.cordova.getActivity().managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
-            // Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
-            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
-            cursor.moveToFirst();
-            fp = new File(cursor.getString(column_index));
-        } else {
-            // Test to see if this is a valid URL first
-            @SuppressWarnings("unused")
-            URL testUrl = new URL(decoded);
-
-            if (decoded.startsWith("file://")) {
-                int questionMark = decoded.indexOf("?");
-                if (questionMark < 0) {
-                    fp = new File(decoded.substring(7, decoded.length()));
-                } else {
-                    fp = new File(decoded.substring(7, questionMark));
-                }
-            } else {
-                fp = new File(decoded);
-            }
-        }
-
-        if (!fp.exists()) {
-            throw new FileNotFoundException();
-        }
-        if (!fp.canRead()) {
-            throw new IOException();
-        }
-        return getEntry(fp);
-    }
-
-    /**
-     * 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
-     */
-    private JSONArray readEntries(String fileName) throws FileNotFoundException, JSONException {
-        File fp = createFileObject(fileName);
-
-        if (!fp.exists()) {
-            // The directory we are listing doesn't exist so we should fail.
-            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(getEntry(files[i]));
-                }
-            }
-        }
-
-        return entries;
-    }
-
-    /**
-     * 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
-     * @throws NoModificationAllowedException
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws EncodingException
-     * @throws JSONException
-     * @throws FileExistsException
-     */
-    private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        String newFileName = FileHelper.getRealPath(fileName, cordova);
-        newParent = FileHelper.getRealPath(newParent, cordova);
-
-        // Check for invalid file name
-        if (newName != null && newName.contains(":")) {
-            throw new EncodingException("Bad file name");
-        }
-
-        File source = new File(newFileName);
-
-        if (!source.exists()) {
-            // The file/directory we are copying doesn't exist so we should fail.
-            throw new FileNotFoundException("The source does not exist");
-        }
-
-        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
-        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");
-        }
-
-        if (source.isDirectory()) {
-            if (move) {
-                return moveDirectory(source, destination);
-            } else {
-                return copyDirectory(source, destination);
-            }
-        } else {
-            if (move) {
-                JSONObject newFileEntry = moveFile(source, destination);
-
-                // If we've moved a file given its content URI, we need to clean up.
-                if (fileName.startsWith("content://")) {
-                    notifyDelete(fileName);
-                }
-
-                return newFileEntry;
-            } else {
-                return copyFile(source, destination);
-            }
-        }
-    }
-
-    /**
-     * Creates the destination File object based on name passed in
-     *
-     * @param newName for the file directory to be called, if null use existing file name
-     * @param fp represents the source file
-     * @param destination represents the destination file
-     * @return a File object that represents the destination
-     */
-    private File createDestination(String newName, File fp, File destination) {
-        File destFile = null;
-
-        // I know this looks weird but it is to work around a JSON bug.
-        if ("null".equals(newName) || "".equals(newName)) {
-            newName = null;
-        }
-
-        if (newName != null) {
-            destFile = new File(destination.getAbsolutePath() + File.separator + newName);
-        } else {
-            destFile = new File(destination.getAbsolutePath() + File.separator + fp.getName());
-        }
-        return destFile;
-    }
-
-    /**
-     * 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");
-        }
-
-        copyAction(srcFile, destFile);
-
-        return getEntry(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();
-
-        try {
-            input.transferTo(0, input.size(), output);
-        } finally {
-            istream.close();
-            ostream.close();
-            input.close();
-            output.close();
-        }
-    }
-
-    /**
-     * 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");
-        }
-
-        // See if the destination directory exists. If not create it.
-        if (!destinationDir.exists()) {
-            if (!destinationDir.mkdir()) {
-                // If we can't create the directory then fail
-                throw new NoModificationAllowedException("Couldn't create the destination directory");
-            }
-        }
-
-        for (File file : srcDir.listFiles()) {
-            if (file.isDirectory()) {
-                copyDirectory(file, destinationDir);
-            } else {
-                File destination = new File(destinationDir.getAbsoluteFile() + File.separator + file.getName());
-                copyFile(file, destination);
-            }
-        }
-
-        return getEntry(destinationDir);
-    }
-
-    /**
-     * 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.
-     *
-     * @param srcDir
-     * @param destinationDir
-     * @return
-     */
-    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
-        if (dest.startsWith(src) && dest.indexOf(File.separator, src.length() - 1) != -1) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * 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");
-            }
-        }
-
-        return getEntry(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 getEntry(destinationDir);
-    }
-
-    /**
-     * Deletes a directory and all of its contents, if any. In the event of an error
-     * [e.g. trying to delete a directory that contains a file that cannot be removed],
-     * 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
-     */
-    private boolean removeRecursively(String filePath) throws FileExistsException {
-        File fp = createFileObject(filePath);
-
-        // You can't delete the root directory.
-        if (atRootDirectory(filePath)) {
-            return false;
-        }
-
-        return removeDirRecursively(fp);
-    }
-
-    /**
-     * Loops through a directory deleting all the files.
-     *
-     * @param directory to be removed
-     * @return a boolean representing success of failure
-     * @throws FileExistsException
-     */
-    private boolean removeDirRecursively(File directory) throws FileExistsException {
-        if (directory.isDirectory()) {
-            for (File file : directory.listFiles()) {
-                removeDirRecursively(file);
-            }
-        }
-
-        if (!directory.delete()) {
-            throw new FileExistsException("could not delete: " + directory.getName());
-        } else {
-            return true;
-        }
-    }
-
-    /**
-     * 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
-     */
-    private boolean remove(String filePath) throws NoModificationAllowedException, InvalidModificationException {
-        File fp = createFileObject(filePath);
-
-        // You can't delete the root directory.
-        if (atRootDirectory(filePath)) {
-            throw new NoModificationAllowedException("You can't delete the root directory");
-        }
-
-        // You can't delete a directory that is not empty
-        if (fp.isDirectory() && fp.list().length > 0) {
-            throw new InvalidModificationException("You can't delete a directory that is not empty.");
-        }
-
-        return fp.delete();
-    }
-
-    /**
-     * Creates or looks up a file.
-     *
-     * @param dirPath base directory
-     * @param fileName file/directory to lookup or create
-     * @param options specify whether to create or not
-     * @param directory if true look up directory, if false look up file
-     * @return a Entry object
-     * @throws FileExistsException
-     * @throws IOException
-     * @throws TypeMismatchException
-     * @throws EncodingException
-     * @throws JSONException
-     */
-    private JSONObject getFile(String dirPath, String fileName, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
-        boolean create = false;
-        boolean exclusive = false;
-        if (options != null) {
-            create = options.optBoolean("create");
-            if (create) {
-                exclusive = options.optBoolean("exclusive");
-            }
-        }
-
-        // Check for a ":" character in the file to line up with BB and iOS
-        if (fileName.contains(":")) {
-            throw new EncodingException("This file has a : in it's name");
-        }
-
-        File fp = createFileObject(dirPath, fileName);
-
-        if (create) {
-            if (exclusive && fp.exists()) {
-                throw new FileExistsException("create/exclusive fails");
-            }
-            if (directory) {
-                fp.mkdir();
-            } else {
-                fp.createNewFile();
-            }
-            if (!fp.exists()) {
-                throw new FileExistsException("create fails");
-            }
-        }
-        else {
-            if (!fp.exists()) {
-                throw new FileNotFoundException("path does not exist");
-            }
-            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");
-                }
-            }
-        }
-
-        // Return the directory
-        return getEntry(fp);
-    }
-
-    /**
-     * If the path starts with a '/' just return that file object. If not construct the file
-     * object from the path passed in and the file name.
-     *
-     * @param dirPath root directory
-     * @param fileName new file name
-     * @return
-     */
-    private File createFileObject(String dirPath, String fileName) {
-        File fp = null;
-        if (fileName.startsWith("/")) {
-            fp = new File(fileName);
-        } else {
-            dirPath = FileHelper.getRealPath(dirPath, cordova);
-            fp = new File(dirPath + File.separator + fileName);
-        }
-        return fp;
-    }
-
-    /**
-     * 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
-     */
-    private JSONObject getParent(String filePath) throws JSONException {
-        filePath = FileHelper.getRealPath(filePath, cordova);
-
-        if (atRootDirectory(filePath)) {
-            return getEntry(filePath);
-        }
-        return getEntry(new File(filePath).getParent());
-    }
-
-    /**
-     * Checks to see if we are at the root directory.  Useful since we are
-     * not allow to delete this directory.
-     *
-     * @param filePath to directory
-     * @return true if we are at the root, false otherwise.
-     */
-    private boolean atRootDirectory(String filePath) {
-        filePath = FileHelper.getRealPath(filePath, cordova);
-
-        if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
-                filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
-                filePath.equals("/data/data/" + cordova.getActivity().getPackageName())) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Create a File object from the passed in path
-     *
-     * @param filePath
-     * @return
-     */
-    private File createFileObject(String filePath) {
-        filePath = FileHelper.getRealPath(filePath, cordova);
-
-        File file = new File(filePath);
-        return file;
-    }
-
-    /**
-     * Look up metadata about this entry.
-     *
-     * @param filePath to entry
-     * @return a long
-     * @throws FileNotFoundException
-     */
-    private long getMetadata(String filePath) throws FileNotFoundException {
-        File file = createFileObject(filePath);
-
-        if (!file.exists()) {
-            throw new FileNotFoundException("Failed to find file in getMetadata");
-        }
-
-        return file.lastModified();
-    }
-
-    /**
-     * 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
-     */
-    private JSONObject getFileMetadata(String filePath) throws FileNotFoundException, JSONException {
-        File file = createFileObject(filePath);
-
-        if (!file.exists()) {
-            throw new FileNotFoundException("File: " + filePath + " does not exist.");
-        }
-
-        JSONObject metadata = new JSONObject();
-        metadata.put("size", file.length());
-        metadata.put("type", FileHelper.getMimeType(filePath, cordova));
-        metadata.put("name", file.getName());
-        metadata.put("fullPath", filePath);
-        metadata.put("lastModifiedDate", file.lastModified());
-
-        return metadata;
-    }
-
-    /**
-     * 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 JSONObject requestFileSystem(int type) throws IOException, JSONException {
-        JSONObject fs = new JSONObject();
-        if (type == TEMPORARY) {
-            File fp;
-            fs.put("name", "temporary");
-            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-                fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
-                        "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/");
-                // Create the cache dir if it doesn't exist.
-                fp.mkdirs();
-                fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() +
-                        "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/"));
-            } else {
-                fp = new File("/data/data/" + cordova.getActivity().getPackageName() + "/cache/");
-                // Create the cache dir if it doesn't exist.
-                fp.mkdirs();
-                fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName() + "/cache/"));
-            }
-        }
-        else if (type == PERSISTENT) {
-            fs.put("name", "persistent");
-            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-                fs.put("root", getEntry(Environment.getExternalStorageDirectory()));
-            } else {
-                fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName()));
-            }
-        }
-        else {
-            throw new IOException("No filesystem of type requested");
-        }
-
-        return fs;
-    }
-
-    /**
-     * Returns a JSON object representing the given File.
-     *
-     * @param file the File to convert
-     * @return a JSON representation of the given File
-     * @throws JSONException
-     */
-    public static JSONObject getEntry(File file) throws JSONException {
-        JSONObject entry = new JSONObject();
-
-        entry.put("isFile", file.isFile());
-        entry.put("isDirectory", file.isDirectory());
-        entry.put("name", file.getName());
-        entry.put("fullPath", "file://" + file.getAbsolutePath());
-        // The file system can't be specified, as it would lead to an infinite loop.
-        // entry.put("filesystem", null);
-
-        return entry;
-    }
-
-    /**
-     * Returns a JSON Object representing a directory on the device's file system
-     *
-     * @param path to the directory
-     * @return
-     * @throws JSONException
-     */
-    private JSONObject getEntry(String path) throws JSONException {
-        return getEntry(new File(path));
-    }
-
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * 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.
-     */
-    public void readFileAs(final String filename, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) {
-        this.cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                try {
-                    byte[] bytes = readAsBinaryHelper(filename, start, end);
-                    
-                    PluginResult result;
-                    switch (resultType) {
-                        case PluginResult.MESSAGE_TYPE_STRING:
-                            result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
-                            break;
-                        case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
-                            result = new PluginResult(PluginResult.Status.OK, bytes);
-                            break;
-                        case PluginResult.MESSAGE_TYPE_BINARYSTRING:
-                            result = new PluginResult(PluginResult.Status.OK, bytes, true);
-                            break;
-                        default: // Base64.
-                            String contentType = FileHelper.getMimeType(filename, cordova);
-                            byte[] base64 = Base64.encodeBase64(bytes);
-                            String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
-                            result = new PluginResult(PluginResult.Status.OK, s);
-                    }
-
-                    callbackContext.sendPluginResult(result);
-                } catch (FileNotFoundException e) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
-                } catch (IOException e) {
-                    Log.d(LOG_TAG, e.getLocalizedMessage());
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
-                }
-            }
-        });
-    }
-
-    /**
-     * Read the contents of a file as binary.
-     * This is done synchronously; the result is returned.
-     *
-     * @param filename          The name of the file.
-     * @param start             Start position in the file.
-     * @param end               End position to stop at (exclusive).
-     * @return                  Contents of the file as a byte[].
-     * @throws IOException
-     */
-    private byte[] readAsBinaryHelper(String filename, int start, int end) throws IOException {
-        int numBytesToRead = end - start;
-        byte[] bytes = new byte[numBytesToRead];
-        InputStream inputStream = FileHelper.getInputStreamFromUriString(filename, cordova);
-        int numBytesRead = 0;
-
-        if (start > 0) {
-            inputStream.skip(start);
-        }
-
-        while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
-            numBytesToRead -= numBytesRead;
-        }
-
-        return bytes;
-    }
-
-    /**
-     * 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.
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
-     */
-    /**/
-    public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
-        if (filename.startsWith("content://")) {
-            throw new NoModificationAllowedException("Couldn't write to file given its content URI");
-        }
-
-        filename = FileHelper.getRealPath(filename, cordova);
-
-        boolean append = false;
-        if (offset > 0) {
-            this.truncateFile(filename, offset);
-            append = true;
-        }
-
-        byte[] rawData = data.getBytes();
-        ByteArrayInputStream in = new ByteArrayInputStream(rawData);
-        FileOutputStream out = new FileOutputStream(filename, append);
-        byte buff[] = new byte[rawData.length];
-        in.read(buff, 0, buff.length);
-        out.write(buff, 0, rawData.length);
-        out.flush();
-        out.close();
-
-        return rawData.length;
-    }
-
-    /**
-     * Truncate the file to size
-     *
-     * @param filename
-     * @param size
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
-     */
-    private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-        if (filename.startsWith("content://")) {
-            throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
-        }
-
-        filename = FileHelper.getRealPath(filename, cordova);
-
-        RandomAccessFile raf = new RandomAccessFile(filename, "rw");
-        try {
-            if (raf.length() >= size) {
-                FileChannel channel = raf.getChannel();
-                channel.truncate(size);
-                return size;
-            }
-
-            return raf.length();
-        } finally {
-            raf.close();
-        }
-    }
-}