File upload.

Implement java side of file upload.  Requires changes to external/
webkit to not break; requires changes to packages/apps/Browser
before it actually is used.

Fix http://b/issue?id=675743
This commit is contained in:
Leon Scroggins
2009-10-02 15:58:55 -04:00
parent 6e15a70c79
commit 70ca3c25b9
4 changed files with 147 additions and 0 deletions

View File

@@ -19,17 +19,21 @@ package android.webkit;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.ParseException;
import android.net.Uri;
import android.net.WebAddress;
import android.net.http.SslCertificate;
import android.os.Handler;
import android.os.Message;
import android.provider.OpenableColumns;
import android.util.Log;
import android.util.TypedValue;
import junit.framework.Assert;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
@@ -462,6 +466,60 @@ class BrowserFrame extends Handler {
mJSInterfaceMap.put(interfaceName, obj);
}
/**
* Called by JNI. Given a URI, find the associated file and return its size
* @param uri A String representing the URI of the desired file.
* @return int The size of the given file.
*/
private int getFileSize(String uri) {
int size = 0;
Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri),
new String[] { OpenableColumns.SIZE },
null,
null,
null);
if (cursor != null) {
try {
if (cursor.moveToNext()) {
size = cursor.getInt(0);
}
} finally {
cursor.close();
}
}
return size;
}
/**
* Called by JNI. Given a URI, a buffer, and an offset into the buffer,
* copy the resource into buffer.
* @param uri A String representing the URI of the desired file.
* @param buffer The byte array to copy the data into.
* @param offset The offet into buffer to place the data.
* @return int The size of the given file, or zero if it fails.
*/
private int getFile(String uri, byte[] buffer, int offset) {
int size = 0;
try {
InputStream stream = mContext.getContentResolver()
.openInputStream(Uri.parse(uri));
size = stream.available();
if (buffer != null && buffer.length - offset >= size) {
stream.read(buffer, offset, size);
} else {
size = 0;
}
stream.close();
} catch (java.io.FileNotFoundException e) {
Log.e(LOGTAG, "FileNotFoundException:" + e);
size = 0;
} catch (java.io.IOException e2) {
Log.e(LOGTAG, "IOException: " + e2);
size = 0;
}
return size;
}
/**
* Start loading a resource.
* @param loaderHandle The native ResourceLoader that is the target of the

View File

@@ -107,6 +107,7 @@ class CallbackProxy extends Handler {
private static final int GEOLOCATION_PERMISSIONS_HIDE_PROMPT = 131;
private static final int RECEIVED_TOUCH_ICON_URL = 132;
private static final int GET_VISITED_HISTORY = 133;
private static final int OPEN_FILE_CHOOSER = 134;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -662,6 +663,12 @@ class CallbackProxy extends Handler {
mWebChromeClient.getVisitedHistory((ValueCallback<String[]>)msg.obj);
}
break;
case OPEN_FILE_CHOOSER:
if (mWebChromeClient != null) {
mWebChromeClient.openFileChooser((UploadFile) msg.obj);
}
break;
}
}
@@ -1348,4 +1355,40 @@ class CallbackProxy extends Handler {
msg.obj = callback;
sendMessage(msg);
}
private class UploadFile implements ValueCallback<Uri> {
private Uri mValue;
public void onReceiveValue(Uri value) {
mValue = value;
synchronized (CallbackProxy.this) {
CallbackProxy.this.notify();
}
}
public Uri getResult() {
return mValue;
}
}
/**
* Called by WebViewCore to open a file chooser.
*/
/* package */ Uri openFileChooser() {
if (mWebChromeClient == null) {
return null;
}
Message myMessage = obtainMessage(OPEN_FILE_CHOOSER);
UploadFile uploadFile = new UploadFile();
myMessage.obj = uploadFile;
synchronized (this) {
sendMessage(myMessage);
try {
wait();
} catch (InterruptedException e) {
Log.e(LOGTAG,
"Caught exception while waiting for openFileChooser");
Log.e(LOGTAG, Log.getStackTraceString(e));
}
}
return uploadFile.getResult();
}
}

View File

@@ -17,6 +17,7 @@
package android.webkit;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Message;
import android.view.View;
@@ -302,4 +303,13 @@ public class WebChromeClient {
public void getVisitedHistory(ValueCallback<String[]> callback) {
}
/**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
* onReceiveValue must be called to wake up the thread.
* @hide
*/
public void openFileChooser(ValueCallback<Uri> uploadFile) {
uploadFile.onReceiveValue(null);
}
}

View File

@@ -18,6 +18,7 @@ package android.webkit;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.DrawFilter;
import android.graphics.Paint;
@@ -26,11 +27,13 @@ import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.provider.Browser;
import android.provider.OpenableColumns;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
@@ -273,6 +276,39 @@ final class WebViewCore {
mCallbackProxy.onJsAlert(url, message);
}
/**
* Called by JNI. Open a file chooser to upload a file.
* @return String version of the URI plus the name of the file.
* FIXME: Just return the URI here, and in FileSystem::pathGetFileName, call
* into Java to get the filename.
*/
private String openFileChooser() {
Uri uri = mCallbackProxy.openFileChooser();
if (uri == null) return "";
// Find out the name, and append it to the URI.
// Webkit will treat the name as the filename, and
// the URI as the path. The URI will be used
// in BrowserFrame to get the actual data.
Cursor cursor = mContext.getContentResolver().query(
uri,
new String[] { OpenableColumns.DISPLAY_NAME },
null,
null,
null);
String name = "";
if (cursor != null) {
try {
if (cursor.moveToNext()) {
name = cursor.getString(0);
}
} finally {
cursor.close();
}
}
return uri.toString() + "/" + name;
}
/**
* Notify the browser that the origin has exceeded it's database quota.
* @param url The URL that caused the overflow.