mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-01 02:12:58 +08:00
javascript and native side of a URL caching plugin + android plugin framework is complete
This commit is contained in:
parent
742910f369
commit
2b2b4f5dd4
18
framework/assets/js/cache.js
Normal file
18
framework/assets/js/cache.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
PhoneGap.addPlugin = function(name, obj) {
|
||||||
|
if ( !window.plugins ) {
|
||||||
|
window.plugins = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !window.plugins[name] ) {
|
||||||
|
window.plugins[name] = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Cache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache.prototype.getCachedPathForURI = function(uri, success, fail) {
|
||||||
|
PhoneGap.execAsync(success, fail, 'com.phonegap.api.impl.Cache', 'getCachedPathForURI', [uri]);
|
||||||
|
};
|
||||||
|
|
||||||
|
PhoneGap.addPlugin('cache', new Cache());
|
@ -6,7 +6,7 @@ if (typeof(DeviceInfo) != 'object')
|
|||||||
* information about the state of PhoneGap.
|
* information about the state of PhoneGap.
|
||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
PhoneGap = {
|
var PhoneGap = {
|
||||||
queue: {
|
queue: {
|
||||||
ready: true,
|
ready: true,
|
||||||
commands: [],
|
commands: [],
|
||||||
@ -205,6 +205,8 @@ document.addEventListener = function(evt, handler, capture) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PhoneGap.callbackId = 0;
|
||||||
|
PhoneGap.callbacks = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a PhoneGap command in a queued fashion, to ensure commands do not
|
* Execute a PhoneGap command in a queued fashion, to ensure commands do not
|
||||||
@ -213,12 +215,28 @@ document.addEventListener = function(evt, handler, capture) {
|
|||||||
* @param {String} command Command to be run in PhoneGap, e.g. "ClassName.method"
|
* @param {String} command Command to be run in PhoneGap, e.g. "ClassName.method"
|
||||||
* @param {String[]} [args] Zero or more arguments to pass to the method
|
* @param {String[]} [args] Zero or more arguments to pass to the method
|
||||||
*/
|
*/
|
||||||
PhoneGap.exec = function() {
|
PhoneGap.exec = function(clazz, action, args) {
|
||||||
PhoneGap.queue.commands.push(arguments);
|
CommandManager.exec(clazz, action, callbackId, args.join('__PHONEGAP__'), false);
|
||||||
if (PhoneGap.queue.timer == null)
|
|
||||||
PhoneGap.queue.timer = setInterval(PhoneGap.run_command, 10);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PhoneGap.execAsync = function(success, fail, clazz, action, args) {
|
||||||
|
var callbackId = clazz + PhoneGap.callbackId++;
|
||||||
|
PhoneGap.callbacks[callbackId] = {success:success, fail:fail};
|
||||||
|
CommandManager.exec(clazz, action, callbackId, args.join('__PHONEGAP__'), true);
|
||||||
|
return callbackId;
|
||||||
|
};
|
||||||
|
|
||||||
|
PhoneGap.callbackSuccess = function(callbackId, args) {
|
||||||
|
PhoneGap.callbacks[callbackId].success.apply(this, JSON.parse(args));
|
||||||
|
delete PhoneGap.callbacks[callbackId];
|
||||||
|
};
|
||||||
|
|
||||||
|
PhoneGap.callbackFailure = function(callbackId, args) {
|
||||||
|
PhoneGap.callbacks[callbackId].fail.apply(this, JSON.parse(args));
|
||||||
|
delete PhoneGap.callbacks[callbackId];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function used to dispatch the request to PhoneGap. It processes the
|
* Internal function used to dispatch the request to PhoneGap. It processes the
|
||||||
* command queue and executes the next command on the list. If one of the
|
* command queue and executes the next command on the list. If one of the
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<jardesc>
|
|
||||||
<jar path="PhoneGap/PhoneGap.jar"/>
|
|
||||||
<options buildIfNeeded="true" compress="true" descriptionLocation="/PhoneGap/export-phonegap.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
|
|
||||||
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
|
|
||||||
<selectedProjects/>
|
|
||||||
<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
|
|
||||||
<sealing sealJar="false">
|
|
||||||
<packagesToSeal/>
|
|
||||||
<packagesToUnSeal/>
|
|
||||||
</sealing>
|
|
||||||
</manifest>
|
|
||||||
<selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
|
|
||||||
<javaElement handleIdentifier="=PhoneGap/src"/>
|
|
||||||
<javaElement handleIdentifier="=PhoneGap/gen"/>
|
|
||||||
</selectedElements>
|
|
||||||
</jardesc>
|
|
@ -25,6 +25,9 @@ package com.phonegap;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import com.phonegap.api.Command;
|
||||||
|
import com.phonegap.api.CommandManager;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@ -73,6 +76,7 @@ public class DroidGap extends Activity {
|
|||||||
private BrowserKey mKey;
|
private BrowserKey mKey;
|
||||||
private AudioHandler audio;
|
private AudioHandler audio;
|
||||||
private CallbackServer callbackServer;
|
private CallbackServer callbackServer;
|
||||||
|
private CommandManager commandManager;
|
||||||
|
|
||||||
private Uri imageUri;
|
private Uri imageUri;
|
||||||
|
|
||||||
@ -231,6 +235,7 @@ public class DroidGap extends Activity {
|
|||||||
private void bindBrowser(WebView appView)
|
private void bindBrowser(WebView appView)
|
||||||
{
|
{
|
||||||
callbackServer = new CallbackServer();
|
callbackServer = new CallbackServer();
|
||||||
|
commandManager = new CommandManager(appView, this);
|
||||||
gap = new Device(appView, this);
|
gap = new Device(appView, this);
|
||||||
accel = new AccelListener(appView, this);
|
accel = new AccelListener(appView, this);
|
||||||
launcher = new CameraLauncher(appView, this);
|
launcher = new CameraLauncher(appView, this);
|
||||||
@ -243,6 +248,7 @@ public class DroidGap extends Activity {
|
|||||||
audio = new AudioHandler(appView, this);
|
audio = new AudioHandler(appView, this);
|
||||||
|
|
||||||
// This creates the new javascript interfaces for PhoneGap
|
// This creates the new javascript interfaces for PhoneGap
|
||||||
|
appView.addJavascriptInterface(commandManager, "CommandManager");
|
||||||
appView.addJavascriptInterface(gap, "DroidGap");
|
appView.addJavascriptInterface(gap, "DroidGap");
|
||||||
appView.addJavascriptInterface(accel, "Accel");
|
appView.addJavascriptInterface(accel, "Accel");
|
||||||
appView.addJavascriptInterface(launcher, "GapCam");
|
appView.addJavascriptInterface(launcher, "GapCam");
|
||||||
@ -264,7 +270,6 @@ public class DroidGap extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void loadUrl(String url)
|
public void loadUrl(String url)
|
||||||
{
|
{
|
||||||
appView.loadUrl(url);
|
appView.loadUrl(url);
|
||||||
@ -288,7 +293,6 @@ public class DroidGap extends Activity {
|
|||||||
return this.callbackServer.getPort();
|
return this.callbackServer.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a hook for calling "alert" from javascript. Useful for
|
* Provides a hook for calling "alert" from javascript. Useful for
|
||||||
* debugging your javascript.
|
* debugging your javascript.
|
||||||
|
24
framework/src/com/phonegap/api/Command.java
Normal file
24
framework/src/com/phonegap/api/Command.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.phonegap.api;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
public interface Command {
|
||||||
|
/**
|
||||||
|
* Executes the request and returns JS code to change client state.
|
||||||
|
*
|
||||||
|
* @param action the command to execute
|
||||||
|
* @return a string with JavaScript code or null
|
||||||
|
*/
|
||||||
|
CommandResult execute(String action, String[] args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this command can process a request.
|
||||||
|
*
|
||||||
|
* @param action the command to execute
|
||||||
|
*
|
||||||
|
* @return true if this command understands the petition
|
||||||
|
*/
|
||||||
|
boolean accept(String action);
|
||||||
|
|
||||||
|
void setContext(Context ctx);
|
||||||
|
}
|
80
framework/src/com/phonegap/api/CommandManager.java
Normal file
80
framework/src/com/phonegap/api/CommandManager.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package com.phonegap.api;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
|
||||||
|
import com.phonegap.DroidGap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a execution request detects matching {@link Command} and executes it.
|
||||||
|
*/
|
||||||
|
public final class CommandManager {
|
||||||
|
private static final String EXCEPTION_PREFIX = "[PhoneGap] *ERROR* Exception executing command [";
|
||||||
|
private static final String EXCEPTION_SUFFIX = "]: ";
|
||||||
|
|
||||||
|
private Command[] commands;
|
||||||
|
|
||||||
|
private final Context ctx;
|
||||||
|
private final WebView app;
|
||||||
|
|
||||||
|
public CommandManager(WebView app, Context ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a request for execution and fulfills it as long as one of
|
||||||
|
* the configured {@link Command} can understand it. Command precedence
|
||||||
|
* is important (just one of them will be executed).
|
||||||
|
*
|
||||||
|
* @param instruction any API command
|
||||||
|
* @return JS code to execute by the client or null
|
||||||
|
*/
|
||||||
|
public String exec(final String clazz, final String action, final String callbackId,
|
||||||
|
final String args, final boolean async) {
|
||||||
|
CommandResult cr = null;
|
||||||
|
try {
|
||||||
|
//final WebView wv = this.app;
|
||||||
|
final String _callbackId = callbackId;
|
||||||
|
final String[] aargs = args.split("__PHONEGAP__");
|
||||||
|
Class c = Class.forName(clazz);
|
||||||
|
Class[] interfaces = c.getInterfaces();
|
||||||
|
for (int j=0; j<interfaces.length; j++) {
|
||||||
|
if (interfaces[j].getName().equals("com.phonegap.api.Command")) {
|
||||||
|
final Command ci = (Command)c.newInstance();
|
||||||
|
ci.setContext(this.ctx);
|
||||||
|
if (async) {
|
||||||
|
// Run this async on the UI thread
|
||||||
|
app.post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
CommandResult cr = ci.execute(action, aargs);
|
||||||
|
if (cr.getStatus() == 0) {
|
||||||
|
app.loadUrl("javascript:PhoneGap.callbackSuccess('"+callbackId+"', " + cr.getResult()+ ");");
|
||||||
|
} else {
|
||||||
|
app.loadUrl("javascript:PhoneGap.callbackFailure('"+callbackId+"', " + cr.getResult() + ");");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
cr = ci.execute(action, aargs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
cr = new CommandResult(CommandResult.Status.CLASSNOTFOUNDEXCEPTION,
|
||||||
|
"{ message: 'ClassNotFoundException', status: "+CommandResult.Status.CLASSNOTFOUNDEXCEPTION.ordinal()+" }");
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
cr = new CommandResult(CommandResult.Status.ILLEGALACCESSEXCEPTION,
|
||||||
|
"{ message: 'IllegalAccessException', status: "+CommandResult.Status.ILLEGALACCESSEXCEPTION.ordinal()+" }");
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
cr = new CommandResult(CommandResult.Status.INSTANTIATIONEXCEPTION,
|
||||||
|
"{ message: 'InstantiationException', status: "+CommandResult.Status.INSTANTIATIONEXCEPTION.ordinal()+" }");
|
||||||
|
}
|
||||||
|
// if async we have already returned at this point unless there was an error...
|
||||||
|
if (async) {
|
||||||
|
app.loadUrl("javascript:PhoneGap.callbackFailure('"+callbackId+"', " + cr.getResult() + ");");
|
||||||
|
}
|
||||||
|
return ( cr != null ? cr.getResult() : "{ status: 0, message: 'all good' }" );
|
||||||
|
}
|
||||||
|
}
|
29
framework/src/com/phonegap/api/CommandResult.java
Normal file
29
framework/src/com/phonegap/api/CommandResult.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.phonegap.api;
|
||||||
|
|
||||||
|
public class CommandResult {
|
||||||
|
private final int status;
|
||||||
|
private final String result;
|
||||||
|
|
||||||
|
public CommandResult(Status status, String result) {
|
||||||
|
this.status = status.ordinal();
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
OK,
|
||||||
|
CLASSNOTFOUNDEXCEPTION,
|
||||||
|
ILLEGALACCESSEXCEPTION,
|
||||||
|
INSTANTIATIONEXCEPTION,
|
||||||
|
MALFORMEDURLEXCEPTION,
|
||||||
|
IOEXCEPTION,
|
||||||
|
INVALIDACTION
|
||||||
|
}
|
||||||
|
}
|
110
framework/src/com/phonegap/api/impl/Cache.java
Normal file
110
framework/src/com/phonegap/api/impl/Cache.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package com.phonegap.api.impl;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.phonegap.api.Command;
|
||||||
|
import com.phonegap.api.CommandResult;
|
||||||
|
|
||||||
|
public final class Cache implements Command {
|
||||||
|
|
||||||
|
private Context ctx;
|
||||||
|
|
||||||
|
public boolean accept(String action) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContext(Context ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResult execute(String action, String[] args) {
|
||||||
|
|
||||||
|
CommandResult.Status status = CommandResult.Status.OK;
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
String uri = args[0];
|
||||||
|
String fileName = md5(uri);
|
||||||
|
|
||||||
|
if (action.equals("getCachedPathForURI") && args.length == 1)
|
||||||
|
{
|
||||||
|
// First check if the file exists already
|
||||||
|
String fileDir = ctx.getFilesDir().getAbsolutePath();
|
||||||
|
String filePath = fileDir + "/" + fileName;
|
||||||
|
|
||||||
|
File f = new File(filePath);
|
||||||
|
// f.exists()
|
||||||
|
if (false) {
|
||||||
|
result = "{ file: '"+filePath+"', status: 0 }";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
URL u;
|
||||||
|
InputStream is = null;
|
||||||
|
DataInputStream dis;
|
||||||
|
FileOutputStream out = null;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int length = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
u = new URL(uri);
|
||||||
|
is = u.openStream(); // throws an IOException
|
||||||
|
dis = new DataInputStream(new BufferedInputStream(is));
|
||||||
|
out = ctx.openFileOutput(fileName, Context.MODE_PRIVATE);
|
||||||
|
while ((length = dis.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
result = "{ file: '"+fileName+"', status: 0 }";
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
status = CommandResult.Status.MALFORMEDURLEXCEPTION;
|
||||||
|
result = "{ message: 'MalformedURLException', status: "+status.ordinal()+" }";
|
||||||
|
} catch (IOException e) {
|
||||||
|
status = CommandResult.Status.IOEXCEPTION;
|
||||||
|
result = "{ message: 'IOException', status: "+status.ordinal()+" }";
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
status = CommandResult.Status.IOEXCEPTION;
|
||||||
|
result = "{ message: 'IOException', status: "+status.ordinal()+" }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = CommandResult.Status.INVALIDACTION;
|
||||||
|
result = "{ message: 'InvalidAction', status: "+status.ordinal()+" }";
|
||||||
|
}
|
||||||
|
return new CommandResult(status, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String md5(String s) {
|
||||||
|
try {
|
||||||
|
// Create MD5 Hash
|
||||||
|
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
|
||||||
|
digest.update(s.getBytes());
|
||||||
|
byte messageDigest[] = digest.digest();
|
||||||
|
|
||||||
|
// Create Hex String
|
||||||
|
StringBuffer hexString = new StringBuffer();
|
||||||
|
for (int i=0; i<messageDigest.length; i++)
|
||||||
|
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
|
||||||
|
return hexString.toString();
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user