Fixing FileUtils change. We are using contexts now, not CordovaInterfaces. CordovaInterface is a SHOULD, not a MUST

This commit is contained in:
Joe Bowser 2012-05-15 08:55:42 -07:00
commit 79048a5a84
38 changed files with 5495 additions and 5487 deletions

View File

@ -18,6 +18,7 @@
*/ */
package com.phonegap.api; package com.phonegap.api;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.api.CordovaInterface; import org.apache.cordova.api.CordovaInterface;
import android.webkit.WebView; import android.webkit.WebView;
@ -31,6 +32,6 @@ import android.webkit.WebView;
public class PluginManager extends org.apache.cordova.api.PluginManager { public class PluginManager extends org.apache.cordova.api.PluginManager {
public PluginManager(WebView app, CordovaInterface ctx) throws Exception { public PluginManager(WebView app, CordovaInterface ctx) throws Exception {
super(app, ctx); super((CordovaWebView) app, ctx);
} }
} }

View File

@ -27,7 +27,6 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
@ -40,14 +39,14 @@ import android.content.Context;
*/ */
public class AccelListener extends Plugin implements SensorEventListener { public class AccelListener extends Plugin implements SensorEventListener {
public static int STOPPED = 0; public static int STOPPED = 0;
public static int STARTING = 1; public static int STARTING = 1;
public static int RUNNING = 2; public static int RUNNING = 2;
public static int ERROR_FAILED_TO_START = 3; public static int ERROR_FAILED_TO_START = 3;
public float TIMEOUT = 30000; // Timeout in msec to shut off listener public float TIMEOUT = 30000; // Timeout in msec to shut off listener
float x,y,z; // most recent acceleration values float x, y, z; // most recent acceleration values
long timestamp; // time of most recent value long timestamp; // time of most recent value
int status; // status of listener int status; // status of listener
long lastAccessTime; // time the value was last retrieved long lastAccessTime; // time the value was last retrieved
@ -64,128 +63,129 @@ public class AccelListener extends Plugin implements SensorEventListener {
this.z = 0; this.z = 0;
this.timestamp = 0; this.timestamp = 0;
this.setStatus(AccelListener.STOPPED); this.setStatus(AccelListener.STOPPED);
}
/**
* Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity.
*
* @param ctx The context of the main Activity.
*/
public void setContext(Context ctx) {
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
} }
/** /**
* Executes the request and returns PluginResult. * Sets the context of the Command. This can then be used to do things like
* * get file paths associated with the Activity.
* @param action The action to execute. *
* @param args JSONArry of arguments for the plugin. * @param ctx The context of the main Activity.
* @param callbackId The callback id used when calling back into JavaScript. */
* @return A PluginResult object with a status and message.
*/ public void setContext(CordovaInterface ctx) {
public PluginResult execute(String action, JSONArray args, String callbackId) { super.setContext(ctx);
PluginResult.Status status = PluginResult.Status.OK; this.sensorManager = (SensorManager) ctx.getActivity().getSystemService(Context.SENSOR_SERVICE);
String result = ""; }
try { /**
if (action.equals("getStatus")) { * Executes the request and returns PluginResult.
int i = this.getStatus(); *
return new PluginResult(status, i); * @param action The action to execute.
} * @param args JSONArry of arguments for the plugin.
else if (action.equals("start")) { * @param callbackId The callback id used when calling back into JavaScript.
int i = this.start(); * @return A PluginResult object with a status and message.
return new PluginResult(status, i); */
} public PluginResult execute(String action, JSONArray args, String callbackId) {
else if (action.equals("stop")) { PluginResult.Status status = PluginResult.Status.OK;
this.stop(); String result = "";
return new PluginResult(status, 0);
} try {
else if (action.equals("getAcceleration")) { if (action.equals("getStatus")) {
// If not running, then this is an async call, so don't worry about waiting int i = this.getStatus();
if (this.status != AccelListener.RUNNING) { return new PluginResult(status, i);
int r = this.start(); }
if (r == AccelListener.ERROR_FAILED_TO_START) { else if (action.equals("start")) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START); int i = this.start();
} return new PluginResult(status, i);
// Wait until running }
long timeout = 2000; else if (action.equals("stop")) {
while ((this.status == STARTING) && (timeout > 0)) { this.stop();
timeout = timeout - 100; return new PluginResult(status, 0);
try { }
Thread.sleep(100); else if (action.equals("getAcceleration")) {
} catch (InterruptedException e) { // If not running, then this is an async call, so don't worry about waiting
e.printStackTrace(); if (this.status != AccelListener.RUNNING) {
} int r = this.start();
} if (r == AccelListener.ERROR_FAILED_TO_START) {
if (timeout == 0) { return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START); }
} // Wait until running
} long timeout = 2000;
this.lastAccessTime = System.currentTimeMillis(); while ((this.status == STARTING) && (timeout > 0)) {
JSONObject r = new JSONObject(); timeout = timeout - 100;
r.put("x", this.x); try {
r.put("y", this.y); Thread.sleep(100);
r.put("z", this.z); } catch (InterruptedException e) {
// TODO: Should timestamp be sent? e.printStackTrace();
r.put("timestamp", this.timestamp); }
return new PluginResult(status, r); }
} if (timeout == 0) {
else if (action.equals("setTimeout")) { return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
try { }
float timeout = Float.parseFloat(args.getString(0)); }
this.setTimeout(timeout); this.lastAccessTime = System.currentTimeMillis();
return new PluginResult(status, 0); JSONObject r = new JSONObject();
} catch (NumberFormatException e) { r.put("x", this.x);
status = PluginResult.Status.INVALID_ACTION; r.put("y", this.y);
e.printStackTrace(); r.put("z", this.z);
} catch (JSONException e) { // TODO: Should timestamp be sent?
status = PluginResult.Status.JSON_EXCEPTION; r.put("timestamp", this.timestamp);
e.printStackTrace(); return new PluginResult(status, r);
} }
} else if (action.equals("setTimeout")) {
else if (action.equals("getTimeout")) { try {
float f = this.getTimeout(); float timeout = Float.parseFloat(args.getString(0));
return new PluginResult(status, f); this.setTimeout(timeout);
} else { return new PluginResult(status, 0);
// Unsupported action } catch (NumberFormatException e) {
return new PluginResult(PluginResult.Status.INVALID_ACTION); status = PluginResult.Status.INVALID_ACTION;
} e.printStackTrace();
return new PluginResult(status, result); } catch (JSONException e) {
} catch (JSONException e) { status = PluginResult.Status.JSON_EXCEPTION;
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); e.printStackTrace();
} }
} }
else if (action.equals("getTimeout")) {
float f = this.getTimeout();
return new PluginResult(status, f);
} else {
// Unsupported action
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/**
* Identifies if action to be executed returns a value and should be run synchronously.
*
* @param action The action to execute
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("getStatus")) {
return true;
}
else if (action.equals("getAcceleration")) {
// Can only return value if RUNNING
if (this.status == AccelListener.RUNNING) {
return true;
}
}
else if (action.equals("getTimeout")) {
return true;
}
return false;
}
/**
* Identifies if action to be executed returns a value and should be run synchronously.
*
* @param action The action to execute
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("getStatus")) {
return true;
}
else if (action.equals("getAcceleration")) {
// Can only return value if RUNNING
if (this.status == AccelListener.RUNNING) {
return true;
}
}
else if (action.equals("getTimeout")) {
return true;
}
return false;
}
/** /**
* Called by AccelBroker when listener is to be shut down. * Called by AccelBroker when listener is to be shut down.
* Stop listener. * Stop listener.
*/ */
public void onDestroy() { public void onDestroy() {
this.stop(); this.stop();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@ -199,14 +199,14 @@ public class AccelListener extends Plugin implements SensorEventListener {
*/ */
public int start() { public int start() {
// If already starting or running, then just return // If already starting or running, then just return
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) { if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
return this.status; return this.status;
} }
// Get accelerometer from sensor manager // Get accelerometer from sensor manager
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
// If found, then register as listener // If found, then register as listener
if ((list != null) && (list.size() > 0)) { if ((list != null) && (list.size() > 0)) {
this.mSensor = list.get(0); this.mSensor = list.get(0);
@ -214,12 +214,12 @@ public class AccelListener extends Plugin implements SensorEventListener {
this.setStatus(AccelListener.STARTING); this.setStatus(AccelListener.STARTING);
this.lastAccessTime = System.currentTimeMillis(); this.lastAccessTime = System.currentTimeMillis();
} }
// If error, then set status to error // If error, then set status to error
else { else {
this.setStatus(AccelListener.ERROR_FAILED_TO_START); this.setStatus(AccelListener.ERROR_FAILED_TO_START);
} }
return this.status; return this.status;
} }
@ -228,7 +228,7 @@ public class AccelListener extends Plugin implements SensorEventListener {
*/ */
public void stop() { public void stop() {
if (this.status != AccelListener.STOPPED) { if (this.status != AccelListener.STOPPED) {
this.sensorManager.unregisterListener(this); this.sensorManager.unregisterListener(this);
} }
this.setStatus(AccelListener.STOPPED); this.setStatus(AccelListener.STOPPED);
} }
@ -248,29 +248,29 @@ public class AccelListener extends Plugin implements SensorEventListener {
* @param SensorEvent event * @param SensorEvent event
*/ */
public void onSensorChanged(SensorEvent event) { public void onSensorChanged(SensorEvent event) {
// Only look at accelerometer events // Only look at accelerometer events
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) { if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
return; return;
} }
// If not running, then just return // If not running, then just return
if (this.status == AccelListener.STOPPED) { if (this.status == AccelListener.STOPPED) {
return; return;
} }
// Save time that event was received // Save time that event was received
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
this.x = event.values[0]; this.x = event.values[0];
this.y = event.values[1]; this.y = event.values[1];
this.z = event.values[2]; this.z = event.values[2];
this.setStatus(AccelListener.RUNNING); this.setStatus(AccelListener.RUNNING);
// If values haven't been read for TIMEOUT time, then turn off accelerometer sensor to save power // If values haven't been read for TIMEOUT time, then turn off accelerometer sensor to save power
if ((this.timestamp - this.lastAccessTime) > this.TIMEOUT) { if ((this.timestamp - this.lastAccessTime) > this.TIMEOUT) {
this.stop(); this.stop();
} }
} }
/** /**
@ -278,34 +278,34 @@ public class AccelListener extends Plugin implements SensorEventListener {
* *
* @return status * @return status
*/ */
public int getStatus() { public int getStatus() {
return this.status; return this.status;
} }
/** /**
* Set the timeout to turn off accelerometer sensor if getX() hasn't been called. * Set the timeout to turn off accelerometer sensor if getX() hasn't been called.
* *
* @param timeout Timeout in msec. * @param timeout Timeout in msec.
*/ */
public void setTimeout(float timeout) { public void setTimeout(float timeout) {
this.TIMEOUT = timeout; this.TIMEOUT = timeout;
} }
/** /**
* Get the timeout to turn off accelerometer sensor if getX() hasn't been called. * Get the timeout to turn off accelerometer sensor if getX() hasn't been called.
* *
* @return timeout in msec * @return timeout in msec
*/ */
public float getTimeout() { public float getTimeout() {
return this.TIMEOUT; return this.TIMEOUT;
} }
/** /**
* Set the status and send it to JavaScript. * Set the status and send it to JavaScript.
* @param status * @param status
*/ */
private void setStatus(int status) { private void setStatus(int status) {
this.status = status; this.status = status;
} }
} }

View File

@ -25,11 +25,6 @@ import org.apache.cordova.api.PluginResult;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.webkit.WebView;
import android.app.Activity;
import android.view.View;
import java.util.HashMap; import java.util.HashMap;
/** /**
@ -50,38 +45,37 @@ public class App extends Plugin {
String result = ""; String result = "";
try { try {
if (action.equals("clearCache")) { if (action.equals("clearCache")) {
this.clearCache(); this.clearCache();
}
else if (action.equals("show")) {
final CordovaWebView wv = this.webView;
((Activity)this.ctx).runOnUiThread(new Runnable() {
public void run() {
wv.setVisibility(View.VISIBLE);
}
});
}
else if (action.equals("loadUrl")) {
this.loadUrl(args.getString(0), args.optJSONObject(1));
} }
else if (action.equals("cancelLoadUrl")) { else if (action.equals("show")) { // TODO @bc - Not in master branch. When should this be called?
this.cancelLoadUrl(); ctx.getActivity().runOnUiThread(new Runnable() {
public void run() {
webView.postMessage("spinner", "stop");
}
});
} }
else if (action.equals("clearHistory")) { else if (action.equals("loadUrl")) {
this.clearHistory(); this.loadUrl(args.getString(0), args.optJSONObject(1));
}
else if (action.equals("cancelLoadUrl")) {
this.cancelLoadUrl();
}
else if (action.equals("clearHistory")) {
this.clearHistory();
} }
else if (action.equals("backHistory")) { else if (action.equals("backHistory")) {
this.backHistory(); this.backHistory();
} }
else if (action.equals("overrideBackbutton")) { else if (action.equals("overrideBackbutton")) {
this.overrideBackbutton(args.getBoolean(0)); this.overrideBackbutton(args.getBoolean(0));
} }
else if (action.equals("isBackbuttonOverridden")) { else if (action.equals("isBackbuttonOverridden")) {
boolean b = this.isBackbuttonOverridden(); boolean b = this.isBackbuttonOverridden();
return new PluginResult(status, b); return new PluginResult(status, b);
} }
else if (action.equals("exitApp")) { else if (action.equals("exitApp")) {
this.exitApp(); this.exitApp();
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} catch (JSONException e) { } catch (JSONException e) {
@ -93,93 +87,94 @@ public class App extends Plugin {
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Clear the resource cache. * Clear the resource cache.
*/ */
public void clearCache() { public void clearCache() {
webView.clearCache(true); this.webView.clearCache(true);
} }
/**
* Load the url into the webview.
*
* @param url
* @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
* @throws JSONException
*/
public void loadUrl(String url, JSONObject props) throws JSONException {
LOG.d("App", "App.loadUrl("+url+","+props+")");
int wait = 0;
boolean openExternal = false;
boolean clearHistory = false;
// If there are properties, then set them on the Activity /**
HashMap<String, Object> params = new HashMap<String, Object>(); * Load the url into the webview.
if (props != null) { *
JSONArray keys = props.names(); * @param url
for (int i=0; i<keys.length(); i++) { * @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
String key = keys.getString(i); * @throws JSONException
if (key.equals("wait")) { */
wait = props.getInt(key); public void loadUrl(String url, JSONObject props) throws JSONException {
} LOG.d("App", "App.loadUrl(" + url + "," + props + ")");
else if (key.equalsIgnoreCase("openexternal")) { int wait = 0;
openExternal = props.getBoolean(key); boolean openExternal = false;
} boolean clearHistory = false;
else if (key.equalsIgnoreCase("clearhistory")) {
clearHistory = props.getBoolean(key);
}
else {
Object value = props.get(key);
if (value == null) {
} // If there are properties, then set them on the Activity
else if (value.getClass().equals(String.class)) { HashMap<String, Object> params = new HashMap<String, Object>();
params.put(key, (String)value); if (props != null) {
} JSONArray keys = props.names();
else if (value.getClass().equals(Boolean.class)) { for (int i = 0; i < keys.length(); i++) {
params.put(key, (Boolean)value); String key = keys.getString(i);
} if (key.equals("wait")) {
else if (value.getClass().equals(Integer.class)) { wait = props.getInt(key);
params.put(key, (Integer)value); }
} else if (key.equalsIgnoreCase("openexternal")) {
} openExternal = props.getBoolean(key);
} }
} else if (key.equalsIgnoreCase("clearhistory")) {
clearHistory = props.getBoolean(key);
}
else {
Object value = props.get(key);
if (value == null) {
// If wait property, then delay loading }
else if (value.getClass().equals(String.class)) {
params.put(key, (String) value);
}
else if (value.getClass().equals(Boolean.class)) {
params.put(key, (Boolean) value);
}
else if (value.getClass().equals(Integer.class)) {
params.put(key, (Integer) value);
}
}
}
}
if (wait > 0) { // If wait property, then delay loading
try {
synchronized(this) { if (wait > 0) {
this.wait(wait); try {
} synchronized (this) {
} catch (InterruptedException e) { this.wait(wait);
e.printStackTrace(); }
} } catch (InterruptedException e) {
} e.printStackTrace();
webView.showWebPage(url, openExternal, clearHistory, params); }
} }
this.webView.showWebPage(url, openExternal, clearHistory, params);
}
/**
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
*/
@Deprecated
public void cancelLoadUrl() {
this.ctx.cancelLoadUrl();
}
/**
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
*/
public void cancelLoadUrl() {
((DroidGap)this.ctx).cancelLoadUrl();
}
/** /**
* Clear page history for the app. * Clear page history for the app.
*/ */
public void clearHistory() { public void clearHistory() {
webView.clearHistory(); this.webView.clearHistory();
} }
/** /**
* Go to previous page displayed. * Go to previous page displayed.
* This is the same as pressing the backbutton on Android device. * This is the same as pressing the backbutton on Android device.
*/ */
public void backHistory() { public void backHistory() {
webView.backHistory(); this.webView.backHistory();
} }
/** /**
@ -189,8 +184,8 @@ public class App extends Plugin {
* @param override T=override, F=cancel override * @param override T=override, F=cancel override
*/ */
public void overrideBackbutton(boolean override) { public void overrideBackbutton(boolean override) {
LOG.i("DroidGap", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!"); LOG.i("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
((DroidGap)this.ctx).bound = override; this.ctx.bindBackButton(override);
} }
/** /**
@ -199,14 +194,14 @@ public class App extends Plugin {
* @return boolean * @return boolean
*/ */
public boolean isBackbuttonOverridden() { public boolean isBackbuttonOverridden() {
return ((DroidGap)this.ctx).bound; return this.ctx.isBackButtonBound();
} }
/** /**
* Exit the Android application. * Exit the Android application.
*/ */
public void exitApp() { public void exitApp() {
((DroidGap)this.ctx).endActivity(); this.webView.postMessage("exit", null);
} }
} }

View File

@ -22,14 +22,12 @@ import android.content.Context;
import android.media.AudioManager; import android.media.AudioManager;
import java.util.ArrayList; import java.util.ArrayList;
import org.apache.cordova.api.LOG; //import org.apache.cordova.api.LOG;
import org.apache.cordova.api.Plugin; import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult; import org.apache.cordova.api.PluginResult;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry;
/** /**
* This class called by CordovaActivity to play and record audio. * This class called by CordovaActivity to play and record audio.
@ -45,112 +43,113 @@ import java.util.Map.Entry;
public class AudioHandler extends Plugin { public class AudioHandler extends Plugin {
public static String TAG = "AudioHandler"; public static String TAG = "AudioHandler";
HashMap<String,AudioPlayer> players; // Audio player object HashMap<String, AudioPlayer> players; // Audio player object
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
/**
* Constructor.
*/
public AudioHandler() {
this.players = new HashMap<String,AudioPlayer>();
this.pausedForPhone = new ArrayList<AudioPlayer>();
}
/** /**
* Executes the request and returns PluginResult. * Constructor.
* */
* @param action The action to execute. public AudioHandler() {
* @param args JSONArry of arguments for the plugin. this.players = new HashMap<String, AudioPlayer>();
* @param callbackId The callback id used when calling back into JavaScript. this.pausedForPhone = new ArrayList<AudioPlayer>();
* @return A PluginResult object with a status and message. }
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("startRecordingAudio")) {
this.startRecordingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("stopRecordingAudio")) {
this.stopRecordingAudio(args.getString(0));
}
else if (action.equals("startPlayingAudio")) {
this.startPlayingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("seekToAudio")) {
this.seekToAudio(args.getString(0), args.getInt(1));
}
else if (action.equals("pausePlayingAudio")) {
this.pausePlayingAudio(args.getString(0));
}
else if (action.equals("stopPlayingAudio")) {
this.stopPlayingAudio(args.getString(0));
} else if (action.equals("setVolume")) {
try {
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
} catch (NumberFormatException nfe) {
//no-op
}
} else if (action.equals("getCurrentPositionAudio")) {
float f = this.getCurrentPositionAudio(args.getString(0));
return new PluginResult(status, f);
}
else if (action.equals("getDurationAudio")) {
float f = this.getDurationAudio(args.getString(0), args.getString(1));
return new PluginResult(status, f);
}
else if (action.equals("release")) {
boolean b = this.release(args.getString(0));
return new PluginResult(status, b);
}
return new PluginResult(status, result);
} catch (JSONException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Executes the request and returns PluginResult.
* *
* @param action The action to execute * @param action The action to execute.
* @return T=returns value * @param args JSONArry of arguments for the plugin.
*/ * @param callbackId The callback id used when calling back into JavaScript.
public boolean isSynch(String action) { * @return A PluginResult object with a status and message.
if (action.equals("getCurrentPositionAudio")) { */
return true; public PluginResult execute(String action, JSONArray args, String callbackId) {
} PluginResult.Status status = PluginResult.Status.OK;
else if (action.equals("getDurationAudio")) { String result = "";
return true;
}
return false;
}
/** try {
* Stop all audio players and recorders. if (action.equals("startRecordingAudio")) {
*/ this.startRecordingAudio(args.getString(0), args.getString(1));
public void onDestroy() { }
else if (action.equals("stopRecordingAudio")) {
this.stopRecordingAudio(args.getString(0));
}
else if (action.equals("startPlayingAudio")) {
this.startPlayingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("seekToAudio")) {
this.seekToAudio(args.getString(0), args.getInt(1));
}
else if (action.equals("pausePlayingAudio")) {
this.pausePlayingAudio(args.getString(0));
}
else if (action.equals("stopPlayingAudio")) {
this.stopPlayingAudio(args.getString(0));
} else if (action.equals("setVolume")) {
try {
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
} catch (NumberFormatException nfe) {
//no-op
}
} else if (action.equals("getCurrentPositionAudio")) {
float f = this.getCurrentPositionAudio(args.getString(0));
return new PluginResult(status, f);
}
else if (action.equals("getDurationAudio")) {
float f = this.getDurationAudio(args.getString(0), args.getString(1));
return new PluginResult(status, f);
}
else if (action.equals("release")) {
boolean b = this.release(args.getString(0));
return new PluginResult(status, b);
}
return new PluginResult(status, result);
} catch (JSONException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/**
* Identifies if action to be executed returns a value and should be run synchronously.
*
* @param action The action to execute
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("getCurrentPositionAudio")) {
return true;
}
else if (action.equals("getDurationAudio")) {
return true;
}
return false;
}
/**
* Stop all audio players and recorders.
*/
public void onDestroy() {
for (AudioPlayer audio : this.players.values()) { for (AudioPlayer audio : this.players.values()) {
audio.destroy(); audio.destroy();
} }
this.players.clear(); this.players.clear();
} }
/** /**
* Called when a message is sent to plugin. * Called when a message is sent to plugin.
* *
* @param id The message id * @param id The message id
* @param data The message data * @param data The message data
* @return Object to stop propagation or null
*/ */
public void onMessage(String id, Object data) { public Object onMessage(String id, Object data) {
// If phone message // If phone message
if (id.equals("telephone")) { if (id.equals("telephone")) {
// If phone ringing, then pause playing // If phone ringing, then pause playing
if ("ringing".equals(data) || "offhook".equals(data)) { if ("ringing".equals(data) || "offhook".equals(data)) {
// Get all audio players and pause them // Get all audio players and pause them
for (AudioPlayer audio : this.players.values()) { for (AudioPlayer audio : this.players.values()) {
if (audio.getState() == AudioPlayer.MEDIA_RUNNING) { if (audio.getState() == AudioPlayer.MEDIA_RUNNING) {
@ -160,7 +159,7 @@ public class AudioHandler extends Plugin {
} }
} }
// If phone idle, then resume playing those players we paused // If phone idle, then resume playing those players we paused
else if ("idle".equals(data)) { else if ("idle".equals(data)) {
for (AudioPlayer audio : this.pausedForPhone) { for (AudioPlayer audio : this.pausedForPhone) {
@ -169,182 +168,185 @@ public class AudioHandler extends Plugin {
this.pausedForPhone.clear(); this.pausedForPhone.clear();
} }
} }
return null;
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/**
* Release the audio player instance to save memory.
*
* @param id The id of the audio player
*/
private boolean release(String id) {
if (!this.players.containsKey(id)) {
return false;
}
AudioPlayer audio = this.players.get(id);
this.players.remove(id);
audio.destroy();
return true;
}
/** /**
* Start recording and save the specified file. * Release the audio player instance to save memory.
* *
* @param id The id of the audio player * @param id The id of the audio player
* @param file The name of the file */
*/ private boolean release(String id) {
if (!this.players.containsKey(id)) {
return false;
}
AudioPlayer audio = this.players.get(id);
this.players.remove(id);
audio.destroy();
return true;
}
/**
* Start recording and save the specified file.
*
* @param id The id of the audio player
* @param file The name of the file
*/
public void startRecordingAudio(String id, String file) { public void startRecordingAudio(String id, String file) {
// If already recording, then just return; // If already recording, then just return;
if (this.players.containsKey(id)) { if (this.players.containsKey(id)) {
return; return;
} }
AudioPlayer audio = new AudioPlayer(this, id); AudioPlayer audio = new AudioPlayer(this, id);
this.players.put(id, audio); this.players.put(id, audio);
audio.startRecording(file); audio.startRecording(file);
} }
/** /**
* Stop recording and save to the file specified when recording started. * Stop recording and save to the file specified when recording started.
* *
* @param id The id of the audio player * @param id The id of the audio player
*/ */
public void stopRecordingAudio(String id) { public void stopRecordingAudio(String id) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
audio.stopRecording(); audio.stopRecording();
this.players.remove(id); this.players.remove(id);
} }
} }
/** /**
* Start or resume playing audio file. * Start or resume playing audio file.
* *
* @param id The id of the audio player * @param id The id of the audio player
* @param file The name of the audio file. * @param file The name of the audio file.
*/ */
public void startPlayingAudio(String id, String file) { public void startPlayingAudio(String id, String file) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio == null) { if (audio == null) {
audio = new AudioPlayer(this, id); audio = new AudioPlayer(this, id);
this.players.put(id, audio); this.players.put(id, audio);
} }
audio.startPlaying(file); audio.startPlaying(file);
} }
/** /**
* Seek to a location. * Seek to a location.
* *
* *
* @param id The id of the audio player * @param id The id of the audio player
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second * @param miliseconds int: number of milliseconds to skip 1000 = 1 second
*/ */
public void seekToAudio(String id, int milliseconds) { public void seekToAudio(String id, int milliseconds) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
audio.seekToPlaying(milliseconds); audio.seekToPlaying(milliseconds);
} }
} }
/** /**
* Pause playing. * Pause playing.
* *
* @param id The id of the audio player * @param id The id of the audio player
*/ */
public void pausePlayingAudio(String id) { public void pausePlayingAudio(String id) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
audio.pausePlaying(); audio.pausePlaying();
} }
} }
/** /**
* Stop playing the audio file. * Stop playing the audio file.
* *
* @param id The id of the audio player * @param id The id of the audio player
*/ */
public void stopPlayingAudio(String id) { public void stopPlayingAudio(String id) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
audio.stopPlaying(); audio.stopPlaying();
//audio.destroy(); //audio.destroy();
//this.players.remove(id); //this.players.remove(id);
} }
} }
/** /**
* Get current position of playback. * Get current position of playback.
* *
* @param id The id of the audio player * @param id The id of the audio player
* @return position in msec * @return position in msec
*/ */
public float getCurrentPositionAudio(String id) { public float getCurrentPositionAudio(String id) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
return(audio.getCurrentPosition()/1000.0f); return (audio.getCurrentPosition() / 1000.0f);
} }
return -1; return -1;
} }
/** /**
* Get the duration of the audio file. * Get the duration of the audio file.
* *
* @param id The id of the audio player * @param id The id of the audio player
* @param file The name of the audio file. * @param file The name of the audio file.
* @return The duration in msec. * @return The duration in msec.
*/ */
public float getDurationAudio(String id, String file) { public float getDurationAudio(String id, String file) {
// Get audio file // Get audio file
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio != null) { if (audio != null) {
return(audio.getDuration(file)); return (audio.getDuration(file));
} }
// If not already open, then open the file // If not already open, then open the file
else { else {
audio = new AudioPlayer(this, id); audio = new AudioPlayer(this, id);
this.players.put(id, audio); this.players.put(id, audio);
return(audio.getDuration(file)); return (audio.getDuration(file));
} }
} }
/** /**
* Set the audio device to be used for playback. * Set the audio device to be used for playback.
* *
* @param output 1=earpiece, 2=speaker * @param output 1=earpiece, 2=speaker
*/ */
@SuppressWarnings("deprecation")
public void setAudioOutputDevice(int output) { public void setAudioOutputDevice(int output) {
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE); AudioManager audiMgr = (AudioManager) this.ctx.getActivity().getSystemService(Context.AUDIO_SERVICE);
if (output == 2) { if (output == 2) {
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL); audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
} }
else if (output == 1) { else if (output == 1) {
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL); audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
} }
else { else {
System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device."); System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device.");
} }
} }
/** /**
* Get the audio device to be used for playback. * Get the audio device to be used for playback.
* *
* @return 1=earpiece, 2=speaker * @return 1=earpiece, 2=speaker
*/ */
@SuppressWarnings("deprecation")
public int getAudioOutputDevice() { public int getAudioOutputDevice() {
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE); AudioManager audiMgr = (AudioManager) this.ctx.getActivity().getSystemService(Context.AUDIO_SERVICE);
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) { if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
return 1; return 1;
} }
else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) { else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) {
return 2; return 2;
} }
else { else {
return -1; return -1;
} }
} }
/** /**

View File

@ -45,413 +45,411 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
private static final String LOG_TAG = "AudioPlayer"; private static final String LOG_TAG = "AudioPlayer";
// AudioPlayer states // AudioPlayer states
public static int MEDIA_NONE = 0; public static int MEDIA_NONE = 0;
public static int MEDIA_STARTING = 1; public static int MEDIA_STARTING = 1;
public static int MEDIA_RUNNING = 2; public static int MEDIA_RUNNING = 2;
public static int MEDIA_PAUSED = 3; public static int MEDIA_PAUSED = 3;
public static int MEDIA_STOPPED = 4; public static int MEDIA_STOPPED = 4;
// AudioPlayer message ids // AudioPlayer message ids
private static int MEDIA_STATE = 1; private static int MEDIA_STATE = 1;
private static int MEDIA_DURATION = 2; private static int MEDIA_DURATION = 2;
private static int MEDIA_POSITION = 3; private static int MEDIA_POSITION = 3;
private static int MEDIA_ERROR = 9; private static int MEDIA_ERROR = 9;
// Media error codes
private static int MEDIA_ERR_NONE_ACTIVE = 0;
private static int MEDIA_ERR_ABORTED = 1;
private static int MEDIA_ERR_NETWORK = 2;
private static int MEDIA_ERR_DECODE = 3;
private static int MEDIA_ERR_NONE_SUPPORTED = 4;
private AudioHandler handler; // The AudioHandler object
private String id; // The id of this player (used to identify Media object in JavaScript)
private int state = MEDIA_NONE; // State of recording or playback
private String audioFile = null; // File name to play or record to
private float duration = -1; // Duration of audio
private MediaRecorder recorder = null; // Audio recording object // Media error codes
private String tempFile = null; // Temporary recording file name private static int MEDIA_ERR_NONE_ACTIVE = 0;
private static int MEDIA_ERR_ABORTED = 1;
private MediaPlayer mPlayer = null; // Audio player object // private static int MEDIA_ERR_NETWORK = 2;
private boolean prepareOnly = false; // private static int MEDIA_ERR_DECODE = 3;
// private static int MEDIA_ERR_NONE_SUPPORTED = 4;
/** private AudioHandler handler; // The AudioHandler object
* Constructor. private String id; // The id of this player (used to identify Media object in JavaScript)
* private int state = MEDIA_NONE; // State of recording or playback
* @param handler The audio handler object private String audioFile = null; // File name to play or record to
* @param id The id of this audio player private float duration = -1; // Duration of audio
*/
public AudioPlayer(AudioHandler handler, String id) { private MediaRecorder recorder = null; // Audio recording object
this.handler = handler; private String tempFile = null; // Temporary recording file name
this.id = id;
private MediaPlayer mPlayer = null; // Audio player object
private boolean prepareOnly = false;
/**
* Constructor.
*
* @param handler The audio handler object
* @param id The id of this audio player
*/
public AudioPlayer(AudioHandler handler, String id) {
this.handler = handler;
this.id = id;
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3"; this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
} }
/** /**
* Destroy player and stop audio playing or recording. * Destroy player and stop audio playing or recording.
*/ */
public void destroy() { public void destroy() {
// Stop any play or record // Stop any play or record
if (this.mPlayer != null) { if (this.mPlayer != null) {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
this.mPlayer.stop(); this.mPlayer.stop();
this.setState(MEDIA_STOPPED); this.setState(MEDIA_STOPPED);
} }
this.mPlayer.release(); this.mPlayer.release();
this.mPlayer = null; this.mPlayer = null;
} }
if (this.recorder != null) { if (this.recorder != null) {
this.stopRecording(); this.stopRecording();
this.recorder.release(); this.recorder.release();
this.recorder = null; this.recorder = null;
} }
} }
/**
* Start recording the specified file.
*
* @param file The name of the file
*/
public void startRecording(String file) {
if (this.mPlayer != null) {
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
// Make sure we're not already recording
else if (this.recorder == null) {
this.audioFile = file;
this.recorder = new MediaRecorder();
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
this.recorder.setOutputFile(this.tempFile);
try {
this.recorder.prepare();
this.recorder.start();
this.setState(MEDIA_RUNNING);
return;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
else {
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
}
/**
* Save temporary recorded file to specified name
*
* @param file
*/
public void moveFile(String file) {
/* this is a hack to save the file as the specified name */
File f = new File(this.tempFile);
f.renameTo(new File("/sdcard/" + file));
}
/**
* Start recording the specified file.
*
* @param file The name of the file
*/
public void startRecording(String file) {
if (this.mPlayer != null) {
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
}
// Make sure we're not already recording
else if (this.recorder == null) {
this.audioFile = file;
this.recorder = new MediaRecorder();
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
this.recorder.setOutputFile(this.tempFile);
try {
this.recorder.prepare();
this.recorder.start();
this.setState(MEDIA_RUNNING);
return;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
}
else {
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
}
}
/**
* Save temporary recorded file to specified name
*
* @param file
*/
public void moveFile(String file) {
/* this is a hack to save the file as the specified name */
File f = new File(this.tempFile);
f.renameTo(new File("/sdcard/" + file));
}
/** /**
* Stop recording and save to the file specified when recording started. * Stop recording and save to the file specified when recording started.
*/ */
public void stopRecording() { public void stopRecording() {
if (this.recorder != null) { if (this.recorder != null) {
try{ try {
if (this.state == MEDIA_RUNNING) { if (this.state == MEDIA_RUNNING) {
this.recorder.stop(); this.recorder.stop();
this.setState(MEDIA_STOPPED); this.setState(MEDIA_STOPPED);
} }
this.moveFile(this.audioFile); this.moveFile(this.audioFile);
} } catch (Exception e) {
catch (Exception e) { e.printStackTrace();
e.printStackTrace(); }
} }
} }
}
/** /**
* Start or resume playing audio file. * Start or resume playing audio file.
* *
* @param file The name of the audio file. * @param file The name of the audio file.
*/ */
public void startPlaying(String file) { public void startPlaying(String file) {
if (this.recorder != null) { if (this.recorder != null) {
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode."); Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
} }
// If this is a new request to play audio, or stopped // If this is a new request to play audio, or stopped
else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) { else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) {
try { try {
// If stopped, then reset player // If stopped, then reset player
if (this.mPlayer != null) { if (this.mPlayer != null) {
this.mPlayer.reset(); this.mPlayer.reset();
} }
// Otherwise, create a new one // Otherwise, create a new one
else { else {
this.mPlayer = new MediaPlayer(); this.mPlayer = new MediaPlayer();
} }
this.audioFile = file; this.audioFile = file;
// If streaming file // If streaming file
if (this.isStreaming(file)) { if (this.isStreaming(file)) {
this.mPlayer.setDataSource(file); this.mPlayer.setDataSource(file);
this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.setState(MEDIA_STARTING); this.setState(MEDIA_STARTING);
this.mPlayer.setOnPreparedListener(this); this.mPlayer.setOnPreparedListener(this);
this.mPlayer.prepareAsync(); this.mPlayer.prepareAsync();
} }
// If local file // If local file
else { else {
if (file.startsWith("/android_asset/")) { if (file.startsWith("/android_asset/")) {
String f = file.substring(15); String f = file.substring(15);
android.content.res.AssetFileDescriptor fd = this.handler.ctx.getAssets().openFd(f); android.content.res.AssetFileDescriptor fd = this.handler.ctx.getActivity().getAssets().openFd(f);
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength()); this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
} }
else { else {
File fp = new File(file); File fp = new File(file);
if (fp.exists()) { if (fp.exists()) {
FileInputStream fileInputStream = new FileInputStream(file); FileInputStream fileInputStream = new FileInputStream(file);
this.mPlayer.setDataSource(fileInputStream.getFD()); this.mPlayer.setDataSource(fileInputStream.getFD());
} }
else { else {
this.mPlayer.setDataSource("/sdcard/" + file); this.mPlayer.setDataSource("/sdcard/" + file);
} }
} }
this.setState(MEDIA_STARTING); this.setState(MEDIA_STARTING);
this.mPlayer.setOnPreparedListener(this); this.mPlayer.setOnPreparedListener(this);
this.mPlayer.prepare(); this.mPlayer.prepare();
// Get duration // Get duration
this.duration = getDurationInSeconds(); this.duration = getDurationInSeconds();
} }
} } catch (Exception e) {
catch (Exception e) { e.printStackTrace();
e.printStackTrace(); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});"); }
} }
}
// If we have already have created an audio player // If we have already have created an audio player
else { else {
// If player has been paused, then resume playback
if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
this.mPlayer.start();
this.setState(MEDIA_RUNNING);
}
else {
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
}
}
}
/** // If player has been paused, then resume playback
* Seek or jump to a new time in the track. if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
*/ this.mPlayer.start();
public void seekToPlaying(int milliseconds) { this.setState(MEDIA_RUNNING);
if (this.mPlayer != null) { }
this.mPlayer.seekTo(milliseconds); else {
Log.d(LOG_TAG, "Send a onStatus update for the new seek"); Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_POSITION+", "+milliseconds/1000.0f+");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
} }
} }
}
/**
* Pause playing. /**
*/ * Seek or jump to a new time in the track.
public void pausePlaying() { */
public void seekToPlaying(int milliseconds) {
// If playing, then pause if (this.mPlayer != null) {
if (this.state == MEDIA_RUNNING) { this.mPlayer.seekTo(milliseconds);
this.mPlayer.pause(); Log.d(LOG_TAG, "Send a onStatus update for the new seek");
this.setState(MEDIA_PAUSED); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
} }
else { }
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});"); /**
} * Pause playing.
} */
public void pausePlaying() {
// If playing, then pause
if (this.state == MEDIA_RUNNING) {
this.mPlayer.pause();
this.setState(MEDIA_PAUSED);
}
else {
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
}
}
/** /**
* Stop playing the audio file. * Stop playing the audio file.
*/ */
public void stopPlaying() { public void stopPlaying() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
this.mPlayer.stop(); this.mPlayer.stop();
this.setState(MEDIA_STOPPED); this.setState(MEDIA_STOPPED);
} }
else { else {
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state); Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
} }
} }
/** /**
* Callback to be invoked when playback of a media source has completed. * Callback to be invoked when playback of a media source has completed.
* *
* @param mPlayer The MediaPlayer that reached the end of the file * @param mPlayer The MediaPlayer that reached the end of the file
*/ */
public void onCompletion(MediaPlayer mPlayer) { public void onCompletion(MediaPlayer mPlayer) {
this.setState(MEDIA_STOPPED); this.setState(MEDIA_STOPPED);
} }
/** /**
* Get current position of playback. * Get current position of playback.
* *
* @return position in msec or -1 if not playing * @return position in msec or -1 if not playing
*/ */
public long getCurrentPosition() { public long getCurrentPosition() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
int curPos = this.mPlayer.getCurrentPosition(); int curPos = this.mPlayer.getCurrentPosition();
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");");
return curPos; return curPos;
} }
else { else {
return -1; return -1;
} }
} }
/** /**
* Determine if playback file is streaming or local. * Determine if playback file is streaming or local.
* It is streaming if file name starts with "http://" * It is streaming if file name starts with "http://"
*
* @param file The file name
* @return T=streaming, F=local
*/
public boolean isStreaming(String file) {
if (file.contains("http://") || file.contains("https://")) {
return true;
}
else {
return false;
}
}
/**
* Get the duration of the audio file.
* *
* @param file The name of the audio file. * @param file The file name
* @return The duration in msec. * @return T=streaming, F=local
* -1=can't be determined
* -2=not allowed
*/ */
public float getDuration(String file) { public boolean isStreaming(String file) {
if (file.contains("http://") || file.contains("https://")) {
// Can't get duration of recording return true;
if (this.recorder != null) { }
return(-2); // not allowed else {
} return false;
}
// If audio file already loaded and started, then return duration }
if (this.mPlayer != null) {
return this.duration;
}
// If no player yet, then create one
else {
this.prepareOnly = true;
this.startPlaying(file);
// This will only return value for local, since streaming
// file hasn't been read yet.
return this.duration;
}
}
/** /**
* Callback to be invoked when the media source is ready for playback. * Get the duration of the audio file.
* *
* @param mPlayer The MediaPlayer that is ready for playback * @param file The name of the audio file.
*/ * @return The duration in msec.
public void onPrepared(MediaPlayer mPlayer) { * -1=can't be determined
// Listen for playback completion * -2=not allowed
this.mPlayer.setOnCompletionListener(this); */
public float getDuration(String file) {
// If start playing after prepared // Can't get duration of recording
if (!this.prepareOnly) { if (this.recorder != null) {
return (-2); // not allowed
// Start playing }
this.mPlayer.start();
// Set player init flag // If audio file already loaded and started, then return duration
this.setState(MEDIA_RUNNING); if (this.mPlayer != null) {
} return this.duration;
}
// Save off duration
this.duration = getDurationInSeconds();
this.prepareOnly = false;
// Send status notification to JavaScript // If no player yet, then create one
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");"); else {
this.prepareOnly = true;
} this.startPlaying(file);
/** // This will only return value for local, since streaming
* By default Android returns the length of audio in mills but we want seconds // file hasn't been read yet.
* return this.duration;
* @return length of clip in seconds }
*/ }
private float getDurationInSeconds() {
return (this.mPlayer.getDuration() / 1000.0f);
}
/** /**
* Callback to be invoked when there has been an error during an asynchronous operation * Callback to be invoked when the media source is ready for playback.
* (other errors will throw exceptions at method call time). *
* * @param mPlayer The MediaPlayer that is ready for playback
* @param mPlayer the MediaPlayer the error pertains to */
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED) public void onPrepared(MediaPlayer mPlayer) {
* @param arg2 an extra code, specific to the error. // Listen for playback completion
*/ this.mPlayer.setOnCompletionListener(this);
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
// TODO: Not sure if this needs to be sent? // If start playing after prepared
this.mPlayer.stop(); if (!this.prepareOnly) {
this.mPlayer.release();
// Send error notification to JavaScript
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":"+arg1+"});");
return false;
}
/**
* Set the state and send it to JavaScript.
*
* @param state
*/
private void setState(int state) {
if (this.state != state) {
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_STATE+", "+state+");");
}
this.state = state;
}
/**
* Get the audio state.
*
* @return int
*/
public int getState() {
return this.state;
}
/** // Start playing
* Set the volume for audio player this.mPlayer.start();
*
* @param volume // Set player init flag
*/ this.setState(MEDIA_RUNNING);
}
// Save off duration
this.duration = getDurationInSeconds();
this.prepareOnly = false;
// Send status notification to JavaScript
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");");
}
/**
* By default Android returns the length of audio in mills but we want seconds
*
* @return length of clip in seconds
*/
private float getDurationInSeconds() {
return (this.mPlayer.getDuration() / 1000.0f);
}
/**
* Callback to be invoked when there has been an error during an asynchronous operation
* (other errors will throw exceptions at method call time).
*
* @param mPlayer the MediaPlayer the error pertains to
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
* @param arg2 an extra code, specific to the error.
*/
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
// TODO: Not sure if this needs to be sent?
this.mPlayer.stop();
this.mPlayer.release();
// Send error notification to JavaScript
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
return false;
}
/**
* Set the state and send it to JavaScript.
*
* @param state
*/
private void setState(int state) {
if (this.state != state) {
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state + ");");
}
this.state = state;
}
/**
* Get the audio state.
*
* @return int
*/
public int getState() {
return this.state;
}
/**
* Set the volume for audio player
*
* @param volume
*/
public void setVolume(float volume) { public void setVolume(float volume) {
this.mPlayer.setVolume(volume, volume); this.mPlayer.setVolume(volume, volume);
} }

View File

@ -24,7 +24,6 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -32,20 +31,20 @@ import android.content.IntentFilter;
import android.util.Log; import android.util.Log;
public class BatteryListener extends Plugin { public class BatteryListener extends Plugin {
private static final String LOG_TAG = "BatteryManager"; private static final String LOG_TAG = "BatteryManager";
BroadcastReceiver receiver; BroadcastReceiver receiver;
private String batteryCallbackId = null; private String batteryCallbackId = null;
/** /**
* Constructor. * Constructor.
*/ */
public BatteryListener() { public BatteryListener() {
this.receiver = null; this.receiver = null;
} }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
@ -56,43 +55,43 @@ public class BatteryListener extends Plugin {
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.INVALID_ACTION; PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
String result = "Unsupported Operation: " + action; String result = "Unsupported Operation: " + action;
if (action.equals("start")) { if (action.equals("start")) {
if (this.batteryCallbackId != null) { if (this.batteryCallbackId != null) {
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running."); return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
} }
this.batteryCallbackId = callbackId; this.batteryCallbackId = callbackId;
// We need to listen to power events to update battery status // We need to listen to power events to update battery status
IntentFilter intentFilter = new IntentFilter() ; IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
if (this.receiver == null) { if (this.receiver == null) {
this.receiver = new BroadcastReceiver() { this.receiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
updateBatteryInfo(intent); updateBatteryInfo(intent);
} }
}; };
ctx.registerReceiver(this.receiver, intentFilter); ctx.getActivity().registerReceiver(this.receiver, intentFilter);
} }
// Don't return any result now, since status results will be sent when events come in from broadcast receiver // Don't return any result now, since status results will be sent when events come in from broadcast receiver
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT); PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginResult.setKeepCallback(true); pluginResult.setKeepCallback(true);
return pluginResult; return pluginResult;
} }
else if (action.equals("stop")) { else if (action.equals("stop")) {
removeBatteryListener(); removeBatteryListener();
this.sendUpdate(new JSONObject(), false); // release status callback in JS side this.sendUpdate(new JSONObject(), false); // release status callback in JS side
this.batteryCallbackId = null; this.batteryCallbackId = null;
return new PluginResult(PluginResult.Status.OK); return new PluginResult(PluginResult.Status.OK);
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} }
/** /**
* Stop battery receiver. * Stop battery receiver.
*/ */
@ -106,7 +105,7 @@ public class BatteryListener extends Plugin {
private void removeBatteryListener() { private void removeBatteryListener() {
if (this.receiver != null) { if (this.receiver != null) {
try { try {
this.ctx.unregisterReceiver(this.receiver); this.ctx.getActivity().unregisterReceiver(this.receiver);
this.receiver = null; this.receiver = null;
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e); Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
@ -137,20 +136,20 @@ public class BatteryListener extends Plugin {
* @param batteryIntent the current battery information * @param batteryIntent the current battery information
* @return * @return
*/ */
private void updateBatteryInfo(Intent batteryIntent) { private void updateBatteryInfo(Intent batteryIntent) {
sendUpdate(this.getBatteryInfo(batteryIntent), true); sendUpdate(this.getBatteryInfo(batteryIntent), true);
} }
/** /**
* Create a new plugin result and send it back to JavaScript * Create a new plugin result and send it back to JavaScript
* *
* @param connection the network info to set as navigator.connection * @param connection the network info to set as navigator.connection
*/ */
private void sendUpdate(JSONObject info, boolean keepCallback) { private void sendUpdate(JSONObject info, boolean keepCallback) {
if (this.batteryCallbackId != null) { if (this.batteryCallbackId != null) {
PluginResult result = new PluginResult(PluginResult.Status.OK, info); PluginResult result = new PluginResult(PluginResult.Status.OK, info);
result.setKeepCallback(keepCallback); result.setKeepCallback(keepCallback);
this.success(result, this.batteryCallbackId); this.success(result, this.batteryCallbackId);
} }
} }
} }

View File

@ -25,11 +25,8 @@ import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.URLEncoder;
import java.util.LinkedList; import java.util.LinkedList;
import android.util.Log;
/** /**
* This class provides a way for Java to run JavaScript in the web page that has loaded Cordova. * This class provides a way for Java to run JavaScript in the web page that has loaded Cordova.
* The CallbackServer class implements an XHR server and a polling server with a list of JavaScript * The CallbackServer class implements an XHR server and a polling server with a list of JavaScript
@ -55,307 +52,309 @@ import android.util.Log;
* 3. The client repeats #1 in loop. * 3. The client repeats #1 in loop.
*/ */
public class CallbackServer implements Runnable { public class CallbackServer implements Runnable {
private static final String LOG_TAG = "CallbackServer";
/** @SuppressWarnings("unused")
* The list of JavaScript statements to be sent to JavaScript. private static final String LOG_TAG = "CallbackServer";
*/
private LinkedList<String> javascript; /**
* The list of JavaScript statements to be sent to JavaScript.
/** */
* The port to listen on. private LinkedList<String> javascript;
*/
private int port; /**
* The port to listen on.
/** */
* The server thread. private int port;
*/
private Thread serverThread; /**
* The server thread.
/** */
* Indicates the server is running. private Thread serverThread;
*/
private boolean active; /**
* Indicates the server is running.
/** */
* Indicates that the JavaScript statements list is empty private boolean active;
*/
private boolean empty; /**
* Indicates that the JavaScript statements list is empty
/** */
* Indicates that polling should be used instead of XHR. private boolean empty;
*/
private boolean usePolling = true; /**
* Indicates that polling should be used instead of XHR.
/** */
* Security token to prevent other apps from accessing this callback server via XHR private boolean usePolling = true;
*/
private String token; /**
* Security token to prevent other apps from accessing this callback server via XHR
/** */
* Constructor. private String token;
*/
public CallbackServer() { /**
//Log.d(LOG_TAG, "CallbackServer()"); * Constructor.
this.active = false; */
this.empty = true; public CallbackServer() {
this.port = 0; //Log.d(LOG_TAG, "CallbackServer()");
this.javascript = new LinkedList<String>(); this.active = false;
} this.empty = true;
this.port = 0;
/** this.javascript = new LinkedList<String>();
* Init callback server and start XHR if running local app. }
*
* If Cordova app is loaded from file://, then we can use XHR /**
* otherwise we have to use polling due to cross-domain security restrictions. * Init callback server and start XHR if running local app.
* *
* @param url The URL of the Cordova app being loaded * If Cordova app is loaded from file://, then we can use XHR
*/ * otherwise we have to use polling due to cross-domain security restrictions.
public void init(String url) { *
//Log.d(LOG_TAG, "CallbackServer.start("+url+")"); * @param url The URL of the Cordova app being loaded
this.active = false; */
this.empty = true; @SuppressWarnings("deprecation")
this.port = 0; public void init(String url) {
this.javascript = new LinkedList<String>(); //Log.d(LOG_TAG, "CallbackServer.start("+url+")");
this.active = false;
this.empty = true;
this.port = 0;
this.javascript = new LinkedList<String>();
// Determine if XHR or polling is to be used
if ((url != null) && !url.startsWith("file://")) {
this.usePolling = true;
this.stopServer();
}
else if (android.net.Proxy.getDefaultHost() != null) {
this.usePolling = true;
this.stopServer();
}
else {
this.usePolling = false;
this.startServer();
}
}
// Determine if XHR or polling is to be used
if ((url != null) && !url.startsWith("file://")) {
this.usePolling = true;
this.stopServer();
}
else if (android.net.Proxy.getDefaultHost() != null) {
this.usePolling = true;
this.stopServer();
}
else {
this.usePolling = false;
this.startServer();
}
}
/** /**
* Re-init when loading a new HTML page into webview. * Re-init when loading a new HTML page into webview.
* *
* @param url The URL of the Cordova app being loaded * @param url The URL of the Cordova app being loaded
*/ */
public void reinit(String url) { public void reinit(String url) {
this.stopServer(); this.stopServer();
this.init(url); this.init(url);
} }
/**
* Return if polling is being used instead of XHR.
*
* @return
*/
public boolean usePolling() {
return this.usePolling;
}
/**
* Get the port that this server is running on.
*
* @return
*/
public int getPort() {
return this.port;
}
/**
* Get the security token that this server requires when calling getJavascript().
*
* @return
*/
public String getToken() {
return this.token;
}
/**
* Start the server on a new thread.
*/
public void startServer() {
//Log.d(LOG_TAG, "CallbackServer.startServer()");
this.active = false;
// Start server on new thread
this.serverThread = new Thread(this);
this.serverThread.start();
}
/** /**
* Restart the server on a new thread. * Return if polling is being used instead of XHR.
*/ *
public void restartServer() { * @return
*/
// Stop server public boolean usePolling() {
this.stopServer(); return this.usePolling;
}
// Start server again
this.startServer();
}
/** /**
* Start running the server. * Get the port that this server is running on.
* This is called automatically when the server thread is started. *
*/ * @return
public void run() { */
public int getPort() {
// Start server return this.port;
try { }
this.active = true;
String request;
ServerSocket waitSocket = new ServerSocket(0);
this.port = waitSocket.getLocalPort();
//Log.d(LOG_TAG, "CallbackServer -- using port " +this.port);
this.token = java.util.UUID.randomUUID().toString();
//Log.d(LOG_TAG, "CallbackServer -- using token "+this.token);
while (this.active) { /**
//Log.d(LOG_TAG, "CallbackServer: Waiting for data on socket"); * Get the security token that this server requires when calling getJavascript().
Socket connection = waitSocket.accept(); *
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),40); * @return
DataOutputStream output = new DataOutputStream(connection.getOutputStream()); */
request = xhrReader.readLine(); public String getToken() {
String response = ""; return this.token;
//Log.d(LOG_TAG, "CallbackServerRequest="+request); }
if (this.active && (request != null)) {
if (request.contains("GET")) {
// Get requested file
String[] requestParts = request.split(" ");
// Must have security token
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
//Log.d(LOG_TAG, "CallbackServer -- Processing GET request");
// Wait until there is some data to send, or send empty data every 10 sec /**
// to prevent XHR timeout on the client * Start the server on a new thread.
synchronized (this) { */
while (this.empty) { public void startServer() {
try { //Log.d(LOG_TAG, "CallbackServer.startServer()");
this.wait(10000); // prevent timeout from happening this.active = false;
//Log.d(LOG_TAG, "CallbackServer>>> break <<<");
break;
}
catch (Exception e) { }
}
}
// If server is still running // Start server on new thread
if (this.active) { this.serverThread = new Thread(this);
this.serverThread.start();
}
// If no data, then send 404 back to client before it times out /**
if (this.empty) { * Restart the server on a new thread.
//Log.d(LOG_TAG, "CallbackServer -- sending data 0"); */
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space public void restartServer() {
}
else {
//Log.d(LOG_TAG, "CallbackServer -- sending item");
response = "HTTP/1.1 200 OK\r\n\r\n";
String js = this.getJavascript();
if (js != null) {
response += encode(js, "UTF-8");
}
}
}
else {
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
}
}
else {
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
}
}
else {
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
}
//Log.d(LOG_TAG, "CallbackServer: response="+response);
//Log.d(LOG_TAG, "CallbackServer: closing output");
output.writeBytes(response);
output.flush();
}
output.close();
xhrReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
this.active = false;
//Log.d(LOG_TAG, "CallbackServer.startServer() - EXIT");
}
/**
* Stop server.
* This stops the thread that the server is running on.
*/
public void stopServer() {
//Log.d(LOG_TAG, "CallbackServer.stopServer()");
if (this.active) {
this.active = false;
// Break out of server wait // Stop server
synchronized (this) { this.stopServer();
this.notify();
} // Start server again
} this.startServer();
} }
/**
* Start running the server.
* This is called automatically when the server thread is started.
*/
public void run() {
// Start server
try {
this.active = true;
String request;
ServerSocket waitSocket = new ServerSocket(0);
this.port = waitSocket.getLocalPort();
//Log.d(LOG_TAG, "CallbackServer -- using port " +this.port);
this.token = java.util.UUID.randomUUID().toString();
//Log.d(LOG_TAG, "CallbackServer -- using token "+this.token);
while (this.active) {
//Log.d(LOG_TAG, "CallbackServer: Waiting for data on socket");
Socket connection = waitSocket.accept();
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()), 40);
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
request = xhrReader.readLine();
String response = "";
//Log.d(LOG_TAG, "CallbackServerRequest="+request);
if (this.active && (request != null)) {
if (request.contains("GET")) {
// Get requested file
String[] requestParts = request.split(" ");
// Must have security token
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
//Log.d(LOG_TAG, "CallbackServer -- Processing GET request");
// Wait until there is some data to send, or send empty data every 10 sec
// to prevent XHR timeout on the client
synchronized (this) {
while (this.empty) {
try {
this.wait(10000); // prevent timeout from happening
//Log.d(LOG_TAG, "CallbackServer>>> break <<<");
break;
} catch (Exception e) {
}
}
}
// If server is still running
if (this.active) {
// If no data, then send 404 back to client before it times out
if (this.empty) {
//Log.d(LOG_TAG, "CallbackServer -- sending data 0");
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space
}
else {
//Log.d(LOG_TAG, "CallbackServer -- sending item");
response = "HTTP/1.1 200 OK\r\n\r\n";
String js = this.getJavascript();
if (js != null) {
response += encode(js, "UTF-8");
}
}
}
else {
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
}
}
else {
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
}
}
else {
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
}
//Log.d(LOG_TAG, "CallbackServer: response="+response);
//Log.d(LOG_TAG, "CallbackServer: closing output");
output.writeBytes(response);
output.flush();
}
output.close();
xhrReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
this.active = false;
//Log.d(LOG_TAG, "CallbackServer.startServer() - EXIT");
}
/**
* Stop server.
* This stops the thread that the server is running on.
*/
public void stopServer() {
//Log.d(LOG_TAG, "CallbackServer.stopServer()");
if (this.active) {
this.active = false;
// Break out of server wait
synchronized (this) {
this.notify();
}
}
}
/** /**
* Destroy * Destroy
*/ */
public void destroy() { public void destroy() {
this.stopServer(); this.stopServer();
} }
/** /**
* Get the number of JavaScript statements. * Get the number of JavaScript statements.
* *
* @return int * @return int
*/ */
public int getSize() { public int getSize() {
synchronized(this) { synchronized (this) {
int size = this.javascript.size(); int size = this.javascript.size();
return size; return size;
} }
} }
/** /**
* Get the next JavaScript statement and remove from list. * Get the next JavaScript statement and remove from list.
* *
* @return String * @return String
*/ */
public String getJavascript() { public String getJavascript() {
synchronized(this) { synchronized (this) {
if (this.javascript.size() == 0) { if (this.javascript.size() == 0) {
return null; return null;
} }
String statement = this.javascript.remove(0); String statement = this.javascript.remove(0);
if (this.javascript.size() == 0) { if (this.javascript.size() == 0) {
this.empty = true; this.empty = true;
} }
return statement; return statement;
} }
} }
/** /**
* Add a JavaScript statement to the list. * Add a JavaScript statement to the list.
* *
* @param statement * @param statement
*/ */
public void sendJavascript(String statement) { public void sendJavascript(String statement) {
synchronized (this) { synchronized (this) {
this.javascript.add(statement); this.javascript.add(statement);
this.empty = false; this.empty = false;
this.notify(); this.notify();
} }
} }
/* The Following code has been modified from original implementation of URLEncoder */ /* The Following code has been modified from original implementation of URLEncoder */
/* start */ /* start */
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
@ -371,7 +370,7 @@ public class CallbackServer implements Runnable {
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
static final String digits = "0123456789ABCDEF"; static final String digits = "0123456789ABCDEF";
/** /**
* This will encode the return value to JavaScript. We revert the encoding for * This will encode the return value to JavaScript. We revert the encoding for
@ -382,13 +381,13 @@ public class CallbackServer implements Runnable {
* @param enc encoding type * @param enc encoding type
* @return encoded string * @return encoded string
*/ */
public static String encode(String s, String enc) throws UnsupportedEncodingException { public static String encode(String s, String enc) throws UnsupportedEncodingException {
if (s == null || enc == null) { if (s == null || enc == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
// check for UnsupportedEncodingException // check for UnsupportedEncodingException
"".getBytes(enc); "".getBytes(enc);
// Guess a bit bigger for encoded form // Guess a bit bigger for encoded form
StringBuilder buf = new StringBuilder(s.length() + 16); StringBuilder buf = new StringBuilder(s.length() + 16);
int start = -1; int start = -1;
@ -426,6 +425,6 @@ public class CallbackServer implements Runnable {
buf.append(digits.charAt(bytes[j] & 0xf)); buf.append(digits.charAt(bytes[j] & 0xf));
} }
} }
/* end */ /* end */
} }

View File

@ -26,7 +26,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.cordova.api.CordovaInterface; //import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG; import org.apache.cordova.api.LOG;
import org.apache.cordova.api.Plugin; import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult; import org.apache.cordova.api.PluginResult;
@ -35,7 +35,7 @@ import org.json.JSONException;
import android.app.Activity; import android.app.Activity;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; //import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -53,50 +53,50 @@ public class CameraLauncher extends Plugin {
private static final int DATA_URL = 0; // Return base64 encoded string private static final int DATA_URL = 0; // Return base64 encoded string
private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android) private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
private static final int CAMERA = 1; // Take picture from camera private static final int CAMERA = 1; // Take picture from camera
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android) private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL
private static final int ALLMEDIA = 2; // allow selection from all media types private static final int ALLMEDIA = 2; // allow selection from all media types
private static final int JPEG = 0; // Take a picture of type JPEG private static final int JPEG = 0; // Take a picture of type JPEG
private static final int PNG = 1; // Take a picture of type PNG private static final int PNG = 1; // Take a picture of type PNG
private static final String GET_PICTURE = "Get Picture"; private static final String GET_PICTURE = "Get Picture";
private static final String GET_VIDEO = "Get Video"; private static final String GET_VIDEO = "Get Video";
private static final String GET_All = "Get All"; private static final String GET_All = "Get All";
private static final String LOG_TAG = "CameraLauncher"; private static final String LOG_TAG = "CameraLauncher";
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private int targetWidth; // desired width of the image private int targetWidth; // desired width of the image
private int targetHeight; // desired height of the image private int targetHeight; // desired height of the image
private Uri imageUri; // Uri of captured image private Uri imageUri; // Uri of captured image
private int encodingType; // Type of encoding to use private int encodingType; // Type of encoding to use
private int mediaType; // What type of media to retrieve private int mediaType; // What type of media to retrieve
public String callbackId; public String callbackId;
private int numPics; private int numPics;
//This should never be null! //This should never be null!
private CordovaInterface cordova; //private CordovaInterface cordova;
/** /**
* Constructor. * Constructor.
*/ */
public CameraLauncher() { public CameraLauncher() {
} }
public void setContext(Context mCtx) { // public void setContext(CordovaInterface mCtx) {
super.setContext(mCtx); // super.setContext(mCtx);
if(CordovaInterface.class.isInstance(mCtx)) // if (CordovaInterface.class.isInstance(mCtx))
cordova = (CordovaInterface) mCtx; // cordova = (CordovaInterface) mCtx;
else // else
LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity"); // LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
} // }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
@ -107,9 +107,9 @@ public class CameraLauncher extends Plugin {
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.OK;
String result = ""; String result = "";
this.callbackId = callbackId; this.callbackId = callbackId;
try { try {
if (action.equals("takePicture")) { if (action.equals("takePicture")) {
int srcType = CAMERA; int srcType = CAMERA;
@ -127,7 +127,7 @@ public class CameraLauncher extends Plugin {
this.targetHeight = args.getInt(4); this.targetHeight = args.getInt(4);
this.encodingType = args.getInt(5); this.encodingType = args.getInt(5);
this.mediaType = args.getInt(6); this.mediaType = args.getInt(6);
if (srcType == CAMERA) { if (srcType == CAMERA) {
this.takePicture(destType, encodingType); this.takePicture(destType, encodingType);
} }
@ -144,11 +144,11 @@ public class CameraLauncher extends Plugin {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
} }
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Take a picture with the camera. * Take a picture with the camera.
* When an image is captured or the camera view is cancelled, the result is returned * When an image is captured or the camera view is cancelled, the result is returned
@ -166,20 +166,21 @@ public class CameraLauncher extends Plugin {
public void takePicture(int returnType, int encodingType) { public void takePicture(int returnType, int encodingType) {
// Save the number of images currently on disk for later // Save the number of images currently on disk for later
this.numPics = queryImgDB().getCount(); this.numPics = queryImgDB().getCount();
// Display camera // Display camera
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
// TODO: What if there isn't any external storage? // TODO: What if there isn't any external storage?
File photo = createCaptureFile(encodingType); File photo = createCaptureFile(encodingType);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo); this.imageUri = Uri.fromFile(photo);
if(cordova != null) if (this.ctx != null) {
cordova.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1); this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
else }
LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity"); // else
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
} }
/** /**
@ -191,9 +192,9 @@ public class CameraLauncher extends Plugin {
private File createCaptureFile(int encodingType) { private File createCaptureFile(int encodingType) {
File photo = null; File photo = null;
if (encodingType == JPEG) { if (encodingType == JPEG) {
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.jpg"); photo = new File(DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()), "Pic.jpg");
} else if (encodingType == PNG) { } else if (encodingType == PNG) {
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.png"); photo = new File(DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()), "Pic.png");
} else { } else {
throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType); throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
} }
@ -212,23 +213,25 @@ public class CameraLauncher extends Plugin {
Intent intent = new Intent(); Intent intent = new Intent();
String title = GET_PICTURE; String title = GET_PICTURE;
if (this.mediaType == PICTURE) { if (this.mediaType == PICTURE) {
intent.setType("image/*"); intent.setType("image/*");
} }
else if (this.mediaType == VIDEO) { else if (this.mediaType == VIDEO) {
intent.setType("video/*"); intent.setType("video/*");
title = GET_VIDEO; title = GET_VIDEO;
} }
else if (this.mediaType == ALLMEDIA) { else if (this.mediaType == ALLMEDIA) {
// I wanted to make the type 'image/*, video/*' but this does not work on all versions // I wanted to make the type 'image/*, video/*' but this does not work on all versions
// of android so I had to go with the wildcard search. // of android so I had to go with the wildcard search.
intent.setType("*/*"); intent.setType("*/*");
title = GET_All; title = GET_All;
} }
intent.setAction(Intent.ACTION_GET_CONTENT); intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE); intent.addCategory(Intent.CATEGORY_OPENABLE);
cordova.startActivityForResult((Plugin) this, Intent.createChooser(intent, if (this.ctx != null) {
new String(title)), (srcType+1)*16 + returnType + 1); this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
new String(title)), (srcType + 1) * 16 + returnType + 1);
}
} }
/** /**
@ -262,8 +265,8 @@ public class CameraLauncher extends Plugin {
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
// would result in whitespace in the new image. // would result in whitespace in the new image.
else { else {
double newRatio = newWidth / (double)newHeight; double newRatio = newWidth / (double) newHeight;
double origRatio = origWidth / (double)origHeight; double origRatio = origWidth / (double) origHeight;
if (origRatio > newRatio) { if (origRatio > newRatio) {
newHeight = (newWidth * origHeight) / origWidth; newHeight = (newWidth * origHeight) / origWidth;
@ -271,10 +274,10 @@ public class CameraLauncher extends Plugin {
newWidth = (newHeight * origWidth) / origHeight; newWidth = (newHeight * origWidth) / origHeight;
} }
} }
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
} }
/** /**
* Called when the camera view exits. * Called when the camera view exits.
* *
@ -284,22 +287,22 @@ public class CameraLauncher extends Plugin {
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/ */
public void onActivityResult(int requestCode, int resultCode, Intent intent) { public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Get src and dest types from request code // Get src and dest types from request code
int srcType = (requestCode/16) - 1; int srcType = (requestCode / 16) - 1;
int destType = (requestCode % 16) - 1; int destType = (requestCode % 16) - 1;
int rotate = 0; int rotate = 0;
// Create an ExifHelper to save the exif data that is lost during compression // Create an ExifHelper to save the exif data that is lost during compression
ExifHelper exif = new ExifHelper(); ExifHelper exif = new ExifHelper();
try { try {
if (this.encodingType == JPEG) { if (this.encodingType == JPEG) {
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Pic.jpg"); exif.createInFile(DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()) + "/Pic.jpg");
exif.readExifData(); exif.readExifData();
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
// If CAMERA // If CAMERA
if (srcType == CAMERA) { if (srcType == CAMERA) {
@ -309,15 +312,15 @@ public class CameraLauncher extends Plugin {
// Read in bitmap of captured image // Read in bitmap of captured image
Bitmap bitmap; Bitmap bitmap;
try { try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri); bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getActivity().getContentResolver(), imageUri);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Uri uri = intent.getData(); Uri uri = intent.getData();
android.content.ContentResolver resolver = this.ctx.getContentResolver(); android.content.ContentResolver resolver = this.ctx.getActivity().getContentResolver();
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
} }
bitmap = scaleBitmap(bitmap); bitmap = scaleBitmap(bitmap);
// If sending base64 image back // If sending base64 image back
if (destType == DATA_URL) { if (destType == DATA_URL) {
this.processPicture(bitmap); this.processPicture(bitmap);
@ -325,33 +328,33 @@ public class CameraLauncher extends Plugin {
} }
// If sending filename back // If sending filename back
else if (destType == FILE_URI){ else if (destType == FILE_URI) {
// Create entry in media store for image // Create entry in media store for image
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it) // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = null; Uri uri = null;
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); uri = this.ctx.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
LOG.d(LOG_TAG, "Can't write to external media storage."); LOG.d(LOG_TAG, "Can't write to external media storage.");
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values); uri = this.ctx.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException ex) { } catch (UnsupportedOperationException ex) {
LOG.d(LOG_TAG, "Can't write to internal media storage."); LOG.d(LOG_TAG, "Can't write to internal media storage.");
this.failPicture("Error capturing image - no media storage found."); this.failPicture("Error capturing image - no media storage found.");
return; return;
} }
} }
// Add compressed version of captured image to returned media store Uri // Add compressed version of captured image to returned media store Uri
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri); OutputStream os = this.ctx.getActivity().getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
os.close(); os.close();
// Restore exif data to file // Restore exif data to file
if (this.encodingType == JPEG) { if (this.encodingType == JPEG) {
exif.createOutFile(FileUtils.getRealPathFromURI(uri, ((Activity) this.ctx))); exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
exif.writeExifData(); exif.writeExifData();
} }
@ -361,12 +364,12 @@ public class CameraLauncher extends Plugin {
bitmap.recycle(); bitmap.recycle();
bitmap = null; bitmap = null;
System.gc(); System.gc();
checkForDuplicateImage(FILE_URI); checkForDuplicateImage(FILE_URI);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
this.failPicture("Error capturing image."); this.failPicture("Error capturing image.");
} }
} }
// If cancelled // If cancelled
@ -379,37 +382,37 @@ public class CameraLauncher extends Plugin {
this.failPicture("Did not complete!"); this.failPicture("Did not complete!");
} }
} }
// If retrieving photo from library // If retrieving photo from library
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
Uri uri = intent.getData(); Uri uri = intent.getData();
android.content.ContentResolver resolver = this.ctx.getContentResolver(); android.content.ContentResolver resolver = this.ctx.getActivity().getContentResolver();
// If you ask for video or all media type you will automatically get back a file URI // If you ask for video or all media type you will automatically get back a file URI
// and there will be no attempt to resize any returned data // and there will be no attempt to resize any returned data
if (this.mediaType != PICTURE) { if (this.mediaType != PICTURE) {
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
} }
else { else {
// If sending base64 image back // If sending base64 image back
if (destType == DATA_URL) { if (destType == DATA_URL) {
try { try {
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
String[] cols = { MediaStore.Images.Media.ORIENTATION }; String[] cols = { MediaStore.Images.Media.ORIENTATION };
Cursor cursor = this.ctx.getContentResolver().query(intent.getData(), Cursor cursor = this.ctx.getActivity().getContentResolver().query(intent.getData(),
cols, cols,
null, null, null); null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToPosition(0); cursor.moveToPosition(0);
rotate = cursor.getInt(0); rotate = cursor.getInt(0);
cursor.close(); cursor.close();
} }
if (rotate != 0) { if (rotate != 0) {
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
matrix.setRotate(rotate); matrix.setRotate(rotate);
bitmap = bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} }
bitmap = scaleBitmap(bitmap); bitmap = scaleBitmap(bitmap);
this.processPicture(bitmap); this.processPicture(bitmap);
bitmap.recycle(); bitmap.recycle();
@ -420,7 +423,7 @@ public class CameraLauncher extends Plugin {
this.failPicture("Error retrieving image."); this.failPicture("Error retrieving image.");
} }
} }
// If sending filename back // If sending filename back
else if (destType == FILE_URI) { else if (destType == FILE_URI) {
// Do we need to scale the returned file // Do we need to scale the returned file
@ -428,21 +431,21 @@ public class CameraLauncher extends Plugin {
try { try {
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
bitmap = scaleBitmap(bitmap); bitmap = scaleBitmap(bitmap);
String fileName = DirectoryManager.getTempDirectoryPath(ctx) + "/resize.jpg"; String fileName = DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()) + "/resize.jpg";
OutputStream os = new FileOutputStream(fileName); OutputStream os = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
os.close(); os.close();
// Restore exif data to file // Restore exif data to file
if (this.encodingType == JPEG) { if (this.encodingType == JPEG) {
exif.createOutFile(FileUtils.getRealPathFromURI(uri, ((Activity) ctx))); exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
exif.writeExifData(); exif.writeExifData();
} }
bitmap.recycle(); bitmap.recycle();
bitmap = null; bitmap = null;
// The resized image is cached by the app in order to get around this and not have to delete you // The resized image is cached by the app in order to get around this and not have to delete you
// application cache I'm adding the current system time to the end of the file url. // application cache I'm adding the current system time to the end of the file url.
this.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName + "?" + System.currentTimeMillis())), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName + "?" + System.currentTimeMillis())), this.callbackId);
@ -453,16 +456,16 @@ public class CameraLauncher extends Plugin {
} }
} }
else { else {
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
} }
} }
} }
} }
else if (resultCode == Activity.RESULT_CANCELED) { else if (resultCode == Activity.RESULT_CANCELED) {
this.failPicture("Selection cancelled."); this.failPicture("Selection cancelled.");
} }
else { else {
this.failPicture("Selection did not complete!"); this.failPicture("Selection did not complete!");
} }
} }
} }
@ -473,14 +476,14 @@ public class CameraLauncher extends Plugin {
* @return a cursor * @return a cursor
*/ */
private Cursor queryImgDB() { private Cursor queryImgDB() {
return this.ctx.getContentResolver().query( return this.ctx.getActivity().getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Images.Media._ID }, new String[] { MediaStore.Images.Media._ID },
null, null,
null, null,
null); null);
} }
/** /**
* Used to find out if we are in a situation where the Camera Intent adds to images * Used to find out if we are in a situation where the Camera Intent adds to images
* to the content store. If we are using a FILE_URI and the number of images in the DB * to the content store. If we are using a FILE_URI and the number of images in the DB
@ -492,17 +495,17 @@ public class CameraLauncher extends Plugin {
int diff = 1; int diff = 1;
Cursor cursor = queryImgDB(); Cursor cursor = queryImgDB();
int currentNumOfImages = cursor.getCount(); int currentNumOfImages = cursor.getCount();
if (type == FILE_URI) { if (type == FILE_URI) {
diff = 2; diff = 2;
} }
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL // delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
if ((currentNumOfImages - numPics) == diff) { if ((currentNumOfImages - numPics) == diff) {
cursor.moveToLast(); cursor.moveToLast();
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1; int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id); Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id);
this.ctx.getContentResolver().delete(uri, null, null); this.ctx.getActivity().getContentResolver().delete(uri, null, null);
} }
} }
@ -511,25 +514,24 @@ public class CameraLauncher extends Plugin {
* *
* @param bitmap * @param bitmap
*/ */
public void processPicture(Bitmap bitmap) { public void processPicture(Bitmap bitmap) {
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream(); ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
try { try {
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) { if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
byte[] code = jpeg_data.toByteArray(); byte[] code = jpeg_data.toByteArray();
byte[] output = Base64.encodeBase64(code); byte[] output = Base64.encodeBase64(code);
String js_out = new String(output); String js_out = new String(output);
this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
js_out = null; js_out = null;
output = null; output = null;
code = null; code = null;
} }
} } catch (Exception e) {
catch(Exception e) {
this.failPicture("Error compressing image."); this.failPicture("Error compressing image.");
} }
jpeg_data = null; jpeg_data = null;
} }
/** /**
* Send error message to JavaScript. * Send error message to JavaScript.
* *

View File

@ -22,7 +22,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG; import org.apache.cordova.api.LOG;
import org.apache.cordova.api.Plugin; import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult; import org.apache.cordova.api.PluginResult;
@ -32,7 +31,6 @@ import org.json.JSONObject;
import android.app.Activity; import android.app.Activity;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
@ -40,47 +38,47 @@ import android.media.MediaPlayer;
import android.net.Uri; import android.net.Uri;
import android.util.Log; import android.util.Log;
public class Capture extends Plugin { public class Capture extends Plugin {
private static final String VIDEO_3GPP = "video/3gpp"; private static final String VIDEO_3GPP = "video/3gpp";
private static final String VIDEO_MP4 = "video/mp4"; private static final String VIDEO_MP4 = "video/mp4";
private static final String AUDIO_3GPP = "audio/3gpp"; private static final String AUDIO_3GPP = "audio/3gpp";
private static final String IMAGE_JPEG = "image/jpeg"; private static final String IMAGE_JPEG = "image/jpeg";
private static final int CAPTURE_AUDIO = 0; // Constant for capture audio private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
private static final int CAPTURE_IMAGE = 1; // Constant for capture image private static final int CAPTURE_IMAGE = 1; // Constant for capture image
private static final int CAPTURE_VIDEO = 2; // Constant for capture video private static final int CAPTURE_VIDEO = 2; // Constant for capture video
private static final String LOG_TAG = "Capture"; private static final String LOG_TAG = "Capture";
private static final int CAPTURE_INTERNAL_ERR = 0; private static final int CAPTURE_INTERNAL_ERR = 0;
private static final int CAPTURE_APPLICATION_BUSY = 1; // private static final int CAPTURE_APPLICATION_BUSY = 1;
private static final int CAPTURE_INVALID_ARGUMENT = 2; // private static final int CAPTURE_INVALID_ARGUMENT = 2;
private static final int CAPTURE_NO_MEDIA_FILES = 3; private static final int CAPTURE_NO_MEDIA_FILES = 3;
private static final int CAPTURE_NOT_SUPPORTED = 20; // private static final int CAPTURE_NOT_SUPPORTED = 20;
private String callbackId; // The ID of the callback to be invoked with our result private String callbackId; // The ID of the callback to be invoked with our result
private long limit; // the number of pics/vids/clips to take private long limit; // the number of pics/vids/clips to take
private double duration; // optional duration parameter for video recording private double duration; // optional duration parameter for video recording
private JSONArray results; // The array of results to be returned to the user private JSONArray results; // The array of results to be returned to the user
private Uri imageUri; // Uri of captured image private Uri imageUri; // Uri of captured image
private CordovaInterface cordova;
public void setContext(Context mCtx) //private CordovaInterface cordova;
{
if(CordovaInterface.class.isInstance(mCtx)) // public void setContext(Context mCtx)
cordova = (CordovaInterface) mCtx; // {
else // if (CordovaInterface.class.isInstance(mCtx))
LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity"); // cordova = (CordovaInterface) mCtx;
} // else
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
// }
@Override @Override
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
this.callbackId = callbackId; this.callbackId = callbackId;
this.limit = 1; this.limit = 1;
this.duration = 0.0f; this.duration = 0.0f;
this.results = new JSONArray(); this.results = new JSONArray();
JSONObject options = args.optJSONObject(0); JSONObject options = args.optJSONObject(0);
if (options != null) { if (options != null) {
limit = options.optLong("limit", 1); limit = options.optLong("limit", 1);
@ -102,9 +100,9 @@ public class Capture extends Plugin {
this.captureImage(); this.captureImage();
} }
else if (action.equals("captureVideo")) { else if (action.equals("captureVideo")) {
this.captureVideo(duration); this.captureVideo(duration);
} }
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true); r.setKeepCallback(true);
return r; return r;
@ -133,7 +131,7 @@ public class Capture extends Plugin {
mimeType = FileUtils.getMimeType(filePath); mimeType = FileUtils.getMimeType(filePath);
} }
Log.d(LOG_TAG, "Mime type = " + mimeType); Log.d(LOG_TAG, "Mime type = " + mimeType);
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) { if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
obj = getImageData(filePath, obj); obj = getImageData(filePath, obj);
} }
@ -143,8 +141,7 @@ public class Capture extends Plugin {
else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) { else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
obj = getAudioVideoData(filePath, obj, true); obj = getAudioVideoData(filePath, obj, true);
} }
} } catch (JSONException e) {
catch (JSONException e) {
Log.d(LOG_TAG, "Error: setting media file data object"); Log.d(LOG_TAG, "Error: setting media file data object");
} }
return obj; return obj;
@ -179,15 +176,14 @@ public class Capture extends Plugin {
try { try {
player.setDataSource(filePath); player.setDataSource(filePath);
player.prepare(); player.prepare();
obj.put("duration", player.getDuration()/1000); obj.put("duration", player.getDuration() / 1000);
if (video) { if (video) {
obj.put("height", player.getVideoHeight()); obj.put("height", player.getVideoHeight());
obj.put("width", player.getVideoWidth()); obj.put("width", player.getVideoWidth());
} }
} } catch (IOException e) {
catch (IOException e) {
Log.d(LOG_TAG, "Error: loading video file"); Log.d(LOG_TAG, "Error: loading video file");
} }
return obj; return obj;
} }
@ -197,7 +193,7 @@ public class Capture extends Plugin {
private void captureAudio() { private void captureAudio() {
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION); Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
cordova.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
} }
/** /**
@ -207,11 +203,11 @@ public class Capture extends Plugin {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
File photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Capture.jpg"); File photo = new File(DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()), "Capture.jpg");
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo); this.imageUri = Uri.fromFile(photo);
cordova.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
} }
/** /**
@ -221,10 +217,10 @@ public class Capture extends Plugin {
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE); Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
// Introduced in API 8 // Introduced in API 8
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration); //intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
cordova.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
} }
/** /**
* Called when the video view exits. * Called when the video view exits.
* *
@ -260,11 +256,11 @@ public class Capture extends Plugin {
try { try {
// Create an ExifHelper to save the exif data that is lost during compression // Create an ExifHelper to save the exif data that is lost during compression
ExifHelper exif = new ExifHelper(); ExifHelper exif = new ExifHelper();
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Capture.jpg"); exif.createInFile(DirectoryManager.getTempDirectoryPath(this.ctx.getActivity()) + "/Capture.jpg");
exif.readExifData(); exif.readExifData();
// Read in bitmap of captured image // Read in bitmap of captured image
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri); Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getActivity().getContentResolver(), imageUri);
// Create entry in media store for image // Create entry in media store for image
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it) // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
@ -272,34 +268,34 @@ public class Capture extends Plugin {
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG); values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
Uri uri = null; Uri uri = null;
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); uri = this.ctx.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
LOG.d(LOG_TAG, "Can't write to external media storage."); LOG.d(LOG_TAG, "Can't write to external media storage.");
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values); uri = this.ctx.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException ex) { } catch (UnsupportedOperationException ex) {
LOG.d(LOG_TAG, "Can't write to internal media storage."); LOG.d(LOG_TAG, "Can't write to internal media storage.");
this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found.")); this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found."));
return; return;
} }
} }
// Add compressed version of captured image to returned media store Uri // Add compressed version of captured image to returned media store Uri
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri); OutputStream os = this.ctx.getActivity().getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.close(); os.close();
bitmap.recycle(); bitmap.recycle();
bitmap = null; bitmap = null;
System.gc(); System.gc();
// Restore exif data to file // Restore exif data to file
exif.createOutFile(FileUtils.getRealPathFromURI(uri, ((Activity) this.ctx))); exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
exif.writeExifData(); exif.writeExifData();
// Add image to results // Add image to results
results.put(createMediaFile(uri)); results.put(createMediaFile(uri));
if (results.length() >= limit) { if (results.length() >= limit) {
// Send Uri back to JavaScript for viewing image // Send Uri back to JavaScript for viewing image
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
@ -330,7 +326,7 @@ public class Capture extends Plugin {
else if (resultCode == Activity.RESULT_CANCELED) { else if (resultCode == Activity.RESULT_CANCELED) {
// If we have partial results send them back to the user // If we have partial results send them back to the user
if (results.length() > 0) { if (results.length() > 0) {
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
} }
// user canceled the action // user canceled the action
else { else {
@ -341,7 +337,7 @@ public class Capture extends Plugin {
else { else {
// If we have partial results send them back to the user // If we have partial results send them back to the user
if (results.length() > 0) { if (results.length() > 0) {
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
} }
// something bad happened // something bad happened
else { else {
@ -357,38 +353,38 @@ public class Capture extends Plugin {
* @return a JSONObject that represents a File * @return a JSONObject that represents a File
* @throws IOException * @throws IOException
*/ */
private JSONObject createMediaFile(Uri data){ private JSONObject createMediaFile(Uri data) {
File fp = new File(FileUtils.getRealPathFromURI(data, ((Activity) this.ctx))); File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
try { try {
// File properties // File properties
obj.put("name", fp.getName()); obj.put("name", fp.getName());
obj.put("fullPath", fp.getAbsolutePath()); obj.put("fullPath", fp.getAbsolutePath());
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files // Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it // are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
// is stored in the audio or video content store. // is stored in the audio or video content store.
if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) { if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
if (data.toString().contains("/audio/")) { if (data.toString().contains("/audio/")) {
obj.put("type", AUDIO_3GPP); obj.put("type", AUDIO_3GPP);
} else { } else {
obj.put("type", VIDEO_3GPP); obj.put("type", VIDEO_3GPP);
} }
} else { } else {
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath())); obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
} }
obj.put("lastModifiedDate", fp.lastModified()); obj.put("lastModifiedDate", fp.lastModified());
obj.put("size", fp.length()); obj.put("size", fp.length());
} catch (JSONException e) { } catch (JSONException e) {
// this will never happen // this will never happen
e.printStackTrace(); e.printStackTrace();
} }
return obj; return obj;
} }
private JSONObject createErrorObject(int code, String message) { private JSONObject createErrorObject(int code, String message) {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
try { try {

View File

@ -27,7 +27,6 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
@ -43,18 +42,18 @@ public class CompassListener extends Plugin implements SensorEventListener {
public static int STARTING = 1; public static int STARTING = 1;
public static int RUNNING = 2; public static int RUNNING = 2;
public static int ERROR_FAILED_TO_START = 3; public static int ERROR_FAILED_TO_START = 3;
public long TIMEOUT = 30000; // Timeout in msec to shut off listener public long TIMEOUT = 30000; // Timeout in msec to shut off listener
int status; // status of listener int status; // status of listener
float heading; // most recent heading value float heading; // most recent heading value
long timeStamp; // time of most recent value long timeStamp; // time of most recent value
long lastAccessTime; // time the value was last retrieved long lastAccessTime; // time the value was last retrieved
int accuracy; // accuracy of the sensor int accuracy; // accuracy of the sensor
private SensorManager sensorManager;// Sensor manager private SensorManager sensorManager;// Sensor manager
Sensor mSensor; // Compass sensor returned by sensor manager Sensor mSensor; // Compass sensor returned by sensor manager
/** /**
* Constructor. * Constructor.
*/ */
@ -70,9 +69,9 @@ public class CompassListener extends Plugin implements SensorEventListener {
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(Context ctx) { public void setContext(CordovaInterface ctx) {
super.setContext(ctx); super.setContext(ctx);
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE); this.sensorManager = (SensorManager) ctx.getActivity().getSystemService(Context.SENSOR_SERVICE);
} }
/** /**
@ -85,8 +84,8 @@ public class CompassListener extends Plugin implements SensorEventListener {
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.OK;
String result = ""; String result = "";
try { try {
if (action.equals("start")) { if (action.equals("start")) {
this.start(); this.start();
@ -116,7 +115,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
} }
} }
if (timeout == 0) { if (timeout == 0) {
return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START); return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START);
} }
} }
return new PluginResult(status, getCompassHeading()); return new PluginResult(status, getCompassHeading());
@ -159,7 +158,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
} }
return false; return false;
} }
/** /**
* Called when listener is to be shut down and object is being destroyed. * Called when listener is to be shut down and object is being destroyed.
*/ */
@ -177,13 +176,14 @@ public class CompassListener extends Plugin implements SensorEventListener {
* @return status of listener * @return status of listener
*/ */
public int start() { public int start() {
// If already starting or running, then just return // If already starting or running, then just return
if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) { if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
return this.status; return this.status;
} }
// Get compass sensor from sensor manager // Get compass sensor from sensor manager
@SuppressWarnings("deprecation")
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION); List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
// If found, then register as listener // If found, then register as listener
@ -198,10 +198,10 @@ public class CompassListener extends Plugin implements SensorEventListener {
else { else {
this.setStatus(CompassListener.ERROR_FAILED_TO_START); this.setStatus(CompassListener.ERROR_FAILED_TO_START);
} }
return this.status; return this.status;
} }
/** /**
* Stop listening to compass sensor. * Stop listening to compass sensor.
*/ */
@ -211,8 +211,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
} }
this.setStatus(CompassListener.STOPPED); this.setStatus(CompassListener.STOPPED);
} }
public void onAccuracyChanged(Sensor sensor, int accuracy) { public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@ -237,7 +236,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
this.stop(); this.stop();
} }
} }
/** /**
* Get status of compass sensor. * Get status of compass sensor.
* *
@ -246,7 +245,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
public int getStatus() { public int getStatus() {
return this.status; return this.status;
} }
/** /**
* Get the most recent compass heading. * Get the most recent compass heading.
* *
@ -256,7 +255,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
this.lastAccessTime = System.currentTimeMillis(); this.lastAccessTime = System.currentTimeMillis();
return this.heading; return this.heading;
} }
/** /**
* Set the timeout to turn off compass sensor if getHeading() hasn't been called. * Set the timeout to turn off compass sensor if getHeading() hasn't been called.
* *
@ -265,7 +264,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
public void setTimeout(long timeout) { public void setTimeout(long timeout) {
this.TIMEOUT = timeout; this.TIMEOUT = timeout;
} }
/** /**
* Get the timeout to turn off compass sensor if getHeading() hasn't been called. * Get the timeout to turn off compass sensor if getHeading() hasn't been called.
* *
@ -290,7 +289,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
*/ */
private JSONObject getCompassHeading() { private JSONObject getCompassHeading() {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
try { try {
obj.put("magneticHeading", this.getHeading()); obj.put("magneticHeading", this.getHeading());
obj.put("trueHeading", this.getHeading()); obj.put("trueHeading", this.getHeading());
@ -301,7 +300,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
} catch (JSONException e) { } catch (JSONException e) {
// Should never happen // Should never happen
} }
return obj; return obj;
} }

View File

@ -18,11 +18,12 @@ package org.apache.cordova;
import java.util.HashMap; import java.util.HashMap;
import android.app.Activity; //import android.app.Activity;
import android.content.Context; //import android.content.Context;
import android.util.Log; import android.util.Log;
import android.webkit.WebView; import android.webkit.WebView;
import org.apache.cordova.api.CordovaInterface;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -35,11 +36,11 @@ import org.json.JSONObject;
* Eclair or higher, we want to use {@link ContactAccessorSdk5}. * Eclair or higher, we want to use {@link ContactAccessorSdk5}.
*/ */
public abstract class ContactAccessor { public abstract class ContactAccessor {
protected final String LOG_TAG = "ContactsAccessor"; protected final String LOG_TAG = "ContactsAccessor";
protected Context mApp; protected CordovaInterface mApp;
protected WebView mView; protected WebView mView;
/** /**
* Check to see if the data associated with the key is required to * Check to see if the data associated with the key is required to
* be populated in the Contact object. * be populated in the Contact object.
@ -47,22 +48,22 @@ public abstract class ContactAccessor {
* @param map created by running buildPopulationSet. * @param map created by running buildPopulationSet.
* @return true if the key data is required * @return true if the key data is required
*/ */
protected boolean isRequired(String key, HashMap<String,Boolean> map) { protected boolean isRequired(String key, HashMap<String, Boolean> map) {
Boolean retVal = map.get(key); Boolean retVal = map.get(key);
return (retVal == null) ? false : retVal.booleanValue(); return (retVal == null) ? false : retVal.booleanValue();
} }
/** /**
* Create a hash map of what data needs to be populated in the Contact object * Create a hash map of what data needs to be populated in the Contact object
* @param fields the list of fields to populate * @param fields the list of fields to populate
* @return the hash map of required data * @return the hash map of required data
*/ */
protected HashMap<String,Boolean> buildPopulationSet(JSONArray fields) { protected HashMap<String, Boolean> buildPopulationSet(JSONArray fields) {
HashMap<String,Boolean> map = new HashMap<String,Boolean>(); HashMap<String, Boolean> map = new HashMap<String, Boolean>();
String key; String key;
try { try {
if (fields.length() == 1 && fields.getString(0).equals("*")) { if (fields.length() == 1 && fields.getString(0).equals("*")) {
map.put("displayName", true); map.put("displayName", true);
map.put("name", true); map.put("name", true);
map.put("nickname", true); map.put("nickname", true);
@ -76,90 +77,88 @@ public abstract class ContactAccessor {
map.put("urls", true); map.put("urls", true);
map.put("photos", true); map.put("photos", true);
map.put("categories", true); map.put("categories", true);
}
else {
for (int i=0; i<fields.length(); i++) {
key = fields.getString(i);
if (key.startsWith("displayName")) {
map.put("displayName", true);
}
else if (key.startsWith("name")) {
map.put("displayName", true);
map.put("name", true);
}
else if (key.startsWith("nickname")) {
map.put("nickname", true);
}
else if (key.startsWith("phoneNumbers")) {
map.put("phoneNumbers", true);
}
else if (key.startsWith("emails")) {
map.put("emails", true);
}
else if (key.startsWith("addresses")) {
map.put("addresses", true);
}
else if (key.startsWith("ims")) {
map.put("ims", true);
}
else if (key.startsWith("organizations")) {
map.put("organizations", true);
}
else if (key.startsWith("birthday")) {
map.put("birthday", true);
}
else if (key.startsWith("note")) {
map.put("note", true);
}
else if (key.startsWith("urls")) {
map.put("urls", true);
} }
else {
for (int i = 0; i < fields.length(); i++) {
key = fields.getString(i);
if (key.startsWith("displayName")) {
map.put("displayName", true);
}
else if (key.startsWith("name")) {
map.put("displayName", true);
map.put("name", true);
}
else if (key.startsWith("nickname")) {
map.put("nickname", true);
}
else if (key.startsWith("phoneNumbers")) {
map.put("phoneNumbers", true);
}
else if (key.startsWith("emails")) {
map.put("emails", true);
}
else if (key.startsWith("addresses")) {
map.put("addresses", true);
}
else if (key.startsWith("ims")) {
map.put("ims", true);
}
else if (key.startsWith("organizations")) {
map.put("organizations", true);
}
else if (key.startsWith("birthday")) {
map.put("birthday", true);
}
else if (key.startsWith("note")) {
map.put("note", true);
}
else if (key.startsWith("urls")) {
map.put("urls", true);
}
else if (key.startsWith("photos")) { else if (key.startsWith("photos")) {
map.put("photos", true); map.put("photos", true);
} }
else if (key.startsWith("categories")) { else if (key.startsWith("categories")) {
map.put("categories", true); map.put("categories", true);
} }
} }
}
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
} }
return map;
} }
catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); /**
} * Convenience method to get a string from a JSON object. Saves a
return map; * lot of try/catch writing.
} * If the property is not found in the object null will be returned.
*
/** * @param obj contact object to search
* Convenience method to get a string from a JSON object. Saves a * @param property to be looked up
* lot of try/catch writing. * @return The value of the property
* If the property is not found in the object null will be returned. */
* protected String getJsonString(JSONObject obj, String property) {
* @param obj contact object to search String value = null;
* @param property to be looked up try {
* @return The value of the property if (obj != null) {
*/ value = obj.getString(property);
protected String getJsonString(JSONObject obj, String property) { if (value.equals("null")) {
String value = null; Log.d(LOG_TAG, property + " is string called 'null'");
try { value = null;
if (obj != null) { }
value = obj.getString(property); }
if (value.equals("null")) { } catch (JSONException e) {
Log.d(LOG_TAG, property + " is string called 'null'"); Log.d(LOG_TAG, "Could not get = " + e.getMessage());
value = null;
}
} }
return value;
} }
catch (JSONException e) {
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
}
return value;
}
/** /**
* Handles adding a JSON Contact object into the database. * Handles adding a JSON Contact object into the database.
* @return TODO * @return TODO
*/ */
public abstract String save(JSONObject contact); public abstract String save(JSONObject contact);
/** /**
* Handles searching through SDK-specific contacts API. * Handles searching through SDK-specific contacts API.
@ -175,25 +174,29 @@ public abstract class ContactAccessor {
/** /**
* Handles removing a contact from the database. * Handles removing a contact from the database.
*/ */
public abstract boolean remove(String id); public abstract boolean remove(String id);
/** /**
* A class that represents the where clause to be used in the database query * A class that represents the where clause to be used in the database query
*/ */
class WhereOptions { class WhereOptions {
private String where; private String where;
private String[] whereArgs; private String[] whereArgs;
public void setWhere(String where) {
this.where = where; public void setWhere(String where) {
this.where = where;
}
public String getWhere() {
return where;
}
public void setWhereArgs(String[] whereArgs) {
this.whereArgs = whereArgs;
}
public String[] getWhereArgs() {
return whereArgs;
}
} }
public String getWhere() {
return where;
}
public void setWhereArgs(String[] whereArgs) {
this.whereArgs = whereArgs;
}
public String[] getWhereArgs() {
return whereArgs;
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -17,17 +17,18 @@
under the License. under the License.
*/ */
package org.apache.cordova; package org.apache.cordova;
import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG; import org.apache.cordova.api.LOG;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
//import android.app.Activity;
import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; //import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; //import android.view.View;
import android.webkit.ConsoleMessage; import android.webkit.ConsoleMessage;
import android.webkit.JsPromptResult; import android.webkit.JsPromptResult;
import android.webkit.JsResult; import android.webkit.JsResult;
@ -41,34 +42,41 @@ import android.widget.EditText;
* This class is the WebChromeClient that implements callbacks for our web view. * This class is the WebChromeClient that implements callbacks for our web view.
*/ */
public class CordovaChromeClient extends WebChromeClient { public class CordovaChromeClient extends WebChromeClient {
private String TAG = "CordovaLog"; private String TAG = "CordovaLog";
private long MAX_QUOTA = 100 * 1024 * 1024; private long MAX_QUOTA = 100 * 1024 * 1024;
private Activity ctx; private CordovaInterface ctx;
private CordovaWebView appView; private CordovaWebView appView;
/** /**
* Constructor. * Constructor.
* *
* @param ctx * @param ctx
*/ */
public CordovaChromeClient(Context ctx) { public CordovaChromeClient(CordovaInterface ctx) {
this.ctx = (Activity) ctx; this.ctx = ctx;
//appView = this.ctx.appView;
}
public CordovaChromeClient(Context ctx, CordovaWebView app)
{
this.ctx = (Activity) ctx;
appView = app;
} }
public void setWebView(CordovaWebView view) /**
{ * Constructor.
appView = view; *
* @param ctx
* @param app
*/
public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) {
this.ctx = ctx;
this.appView = app;
} }
/**
* Constructor.
*
* @param view
*/
public void setWebView(CordovaWebView view) {
this.appView = view;
}
/** /**
* Tell the client to display a javascript alert dialog. * Tell the client to display a javascript alert dialog.
* *
@ -79,39 +87,39 @@ public class CordovaChromeClient extends WebChromeClient {
*/ */
@Override @Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx.getActivity());
dlg.setMessage(message); dlg.setMessage(message);
dlg.setTitle("Alert"); dlg.setTitle("Alert");
//Don't let alerts break the back button //Don't let alerts break the back button
dlg.setCancelable(true); dlg.setCancelable(true);
dlg.setPositiveButton(android.R.string.ok, dlg.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() { new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
result.confirm(); result.confirm();
} }
}); });
dlg.setOnCancelListener( dlg.setOnCancelListener(
new DialogInterface.OnCancelListener() { new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
result.confirm(); result.confirm();
} }
}); });
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
//DO NOTHING //DO NOTHING
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) if (keyCode == KeyEvent.KEYCODE_BACK)
{ {
result.confirm(); result.confirm();
return false; return false;
} }
else else
return true; return true;
} }
}); });
dlg.create(); dlg.create();
dlg.show(); dlg.show();
return true; return true;
} }
/** /**
* Tell the client to display a confirm dialog to the user. * Tell the client to display a confirm dialog to the user.
@ -123,40 +131,40 @@ public class CordovaChromeClient extends WebChromeClient {
*/ */
@Override @Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx.getActivity());
dlg.setMessage(message); dlg.setMessage(message);
dlg.setTitle("Confirm"); dlg.setTitle("Confirm");
dlg.setCancelable(true); dlg.setCancelable(true);
dlg.setPositiveButton(android.R.string.ok, dlg.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
result.confirm(); result.confirm();
} }
}); });
dlg.setNegativeButton(android.R.string.cancel, dlg.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
result.cancel(); result.cancel();
} }
}); });
dlg.setOnCancelListener( dlg.setOnCancelListener(
new DialogInterface.OnCancelListener() { new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
result.cancel(); result.cancel();
} }
}); });
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
//DO NOTHING //DO NOTHING
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK) if (keyCode == KeyEvent.KEYCODE_BACK)
{ {
result.cancel(); result.cancel();
return false; return false;
} }
else else
return true; return true;
} }
}); });
dlg.create(); dlg.create();
dlg.show(); dlg.show();
return true; return true;
@ -178,14 +186,14 @@ public class CordovaChromeClient extends WebChromeClient {
*/ */
@Override @Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// Security check to make sure any requests are coming from the page initially // Security check to make sure any requests are coming from the page initially
// loaded in webview and not another loaded in an iframe. // loaded in webview and not another loaded in an iframe.
boolean reqOk = false; boolean reqOk = false;
if (url.startsWith("file://") || url.indexOf(appView.baseUrl) == 0 || appView.isUrlWhiteListed(url)) { if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
reqOk = true; reqOk = true;
} }
// Calling PluginManager.exec() to call a native service using // Calling PluginManager.exec() to call a native service using
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true])); // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) { if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
@ -196,67 +204,72 @@ public class CordovaChromeClient extends WebChromeClient {
String action = array.getString(1); String action = array.getString(1);
String callbackId = array.getString(2); String callbackId = array.getString(2);
boolean async = array.getBoolean(3); boolean async = array.getBoolean(3);
String r = appView.pluginManager.exec(service, action, callbackId, message, async); String r = this.appView.pluginManager.exec(service, action, callbackId, message, async);
result.confirm(r); result.confirm(r);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
// Polling for JavaScript messages // Polling for JavaScript messages
else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) { else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
String r = appView.callbackServer.getJavascript(); String r = this.appView.callbackServer.getJavascript();
result.confirm(r); result.confirm(r);
} }
// Do NO-OP so older code doesn't display dialog
else if (defaultValue.equals("gap_init:")) {
result.confirm("OK");
}
// Calling into CallbackServer // Calling into CallbackServer
else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) { else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) {
String r = ""; String r = "";
if (message.equals("usePolling")) { if (message.equals("usePolling")) {
r = ""+ appView.callbackServer.usePolling(); r = "" + this.appView.callbackServer.usePolling();
} }
else if (message.equals("restartServer")) { else if (message.equals("restartServer")) {
appView.callbackServer.restartServer(); this.appView.callbackServer.restartServer();
} }
else if (message.equals("getPort")) { else if (message.equals("getPort")) {
r = Integer.toString(appView.callbackServer.getPort()); r = Integer.toString(this.appView.callbackServer.getPort());
} }
else if (message.equals("getToken")) { else if (message.equals("getToken")) {
r = appView.callbackServer.getToken(); r = this.appView.callbackServer.getToken();
} }
result.confirm(r); result.confirm(r);
} }
// Show dialog // Show dialog
else { else {
final JsPromptResult res = result; final JsPromptResult res = result;
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx.getActivity());
dlg.setMessage(message); dlg.setMessage(message);
final EditText input = new EditText(this.ctx); final EditText input = new EditText(this.ctx.getActivity());
if (defaultValue != null) { if (defaultValue != null) {
input.setText(defaultValue); input.setText(defaultValue);
} }
dlg.setView(input); dlg.setView(input);
dlg.setCancelable(false); dlg.setCancelable(false);
dlg.setPositiveButton(android.R.string.ok, dlg.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
String usertext = input.getText().toString(); String usertext = input.getText().toString();
res.confirm(usertext); res.confirm(usertext);
} }
}); });
dlg.setNegativeButton(android.R.string.cancel, dlg.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
res.cancel(); res.cancel();
} }
}); });
dlg.create(); dlg.create();
dlg.show(); dlg.show();
} }
return true; return true;
} }
/** /**
* Handle database quota exceeded notification. * Handle database quota exceeded notification.
* *
@ -273,7 +286,7 @@ public class CordovaChromeClient extends WebChromeClient {
{ {
LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
if( estimatedSize < MAX_QUOTA) if (estimatedSize < MAX_QUOTA)
{ {
//increase for 1Mb //increase for 1Mb
long newQuota = estimatedSize; long newQuota = estimatedSize;
@ -289,17 +302,18 @@ public class CordovaChromeClient extends WebChromeClient {
} }
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
@SuppressWarnings("deprecation")
@Override @Override
public void onConsoleMessage(String message, int lineNumber, String sourceID) public void onConsoleMessage(String message, int lineNumber, String sourceID)
{ {
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message); LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
super.onConsoleMessage(message, lineNumber, sourceID); super.onConsoleMessage(message, lineNumber, sourceID);
} }
@Override @Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) public boolean onConsoleMessage(ConsoleMessage consoleMessage)
{ {
if(consoleMessage.message() != null) if (consoleMessage.message() != null)
LOG.d(TAG, consoleMessage.message()); LOG.d(TAG, consoleMessage.message());
return super.onConsoleMessage(consoleMessage); return super.onConsoleMessage(consoleMessage);
} }
@ -315,6 +329,4 @@ public class CordovaChromeClient extends WebChromeClient {
super.onGeolocationPermissionsShowPrompt(origin, callback); super.onGeolocationPermissionsShowPrompt(origin, callback);
callback.invoke(origin, true, false); callback.invoke(origin, true, false);
} }
} }

4
framework/src/org/apache/cordova/CordovaException.java Normal file → Executable file
View File

@ -21,4 +21,8 @@ package org.apache.cordova;
public class CordovaException extends Exception { public class CordovaException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1373339564758328799L;
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,10 +18,13 @@
*/ */
package org.apache.cordova; package org.apache.cordova;
import org.apache.cordova.api.LOG; import java.util.Hashtable;
import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -29,7 +32,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.net.http.SslError; import android.net.http.SslError;
import android.util.Log;
import android.view.View; import android.view.View;
import android.webkit.HttpAuthHandler; import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler; import android.webkit.SslErrorHandler;
@ -40,32 +42,44 @@ import android.webkit.WebViewClient;
* This class is the WebViewClient that implements callbacks for our web view. * This class is the WebViewClient that implements callbacks for our web view.
*/ */
public class CordovaWebViewClient extends WebViewClient { public class CordovaWebViewClient extends WebViewClient {
private static final String TAG = "Cordova"; private static final String TAG = "Cordova";
Activity ctx; CordovaInterface ctx;
CordovaWebView appView; CordovaWebView appView;
private boolean doClearHistory = false; private boolean doClearHistory = false;
/** The authorization tokens. */
private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
/** /**
* Constructor. * Constructor.
* *
* @param ctx * @param ctx
*/ */
public CordovaWebViewClient(Activity ctx) { public CordovaWebViewClient(CordovaInterface ctx) {
this.ctx = ctx; this.ctx = ctx;
} }
public CordovaWebViewClient(Context ctx, CordovaWebView view) /**
{ * Constructor.
this.ctx = (Activity) ctx; *
appView = view; * @param ctx
* @param view
*/
public CordovaWebViewClient(CordovaInterface ctx, CordovaWebView view) {
this.ctx = ctx;
this.appView = view;
} }
public void setWebView(CordovaWebView view) /**
{ * Constructor.
appView = view; *
* @param view
*/
public void setWebView(CordovaWebView view) {
this.appView = view;
} }
/** /**
* Give the host application a chance to take over the control when a new url * Give the host application a chance to take over the control when a new url
* is about to be loaded in the current WebView. * is about to be loaded in the current WebView.
@ -76,19 +90,19 @@ public class CordovaWebViewClient extends WebViewClient {
*/ */
@Override @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { public boolean shouldOverrideUrlLoading(WebView view, String url) {
// First give any plugins the chance to handle the url themselves // First give any plugins the chance to handle the url themselves
if ((appView.pluginManager != null) && appView.pluginManager.onOverrideUrlLoading(url)) { if ((this.appView.pluginManager != null) && this.appView.pluginManager.onOverrideUrlLoading(url)) {
} }
// If dialing phone (tel:5551212) // If dialing phone (tel:5551212)
else if (url.startsWith(WebView.SCHEME_TEL)) { else if (url.startsWith(WebView.SCHEME_TEL)) {
try { try {
Intent intent = new Intent(Intent.ACTION_DIAL); Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error dialing "+url+": "+ e.toString()); LOG.e(TAG, "Error dialing " + url + ": " + e.toString());
} }
} }
@ -97,9 +111,9 @@ public class CordovaWebViewClient extends WebViewClient {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error showing map "+url+": "+ e.toString()); LOG.e(TAG, "Error showing map " + url + ": " + e.toString());
} }
} }
@ -108,9 +122,9 @@ public class CordovaWebViewClient extends WebViewClient {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error sending email "+url+": "+ e.toString()); LOG.e(TAG, "Error sending email " + url + ": " + e.toString());
} }
} }
@ -137,12 +151,12 @@ public class CordovaWebViewClient extends WebViewClient {
} }
} }
} }
intent.setData(Uri.parse("sms:"+address)); intent.setData(Uri.parse("sms:" + address));
intent.putExtra("address", address); intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms"); intent.setType("vnd.android-dir/mms-sms");
ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error sending sms "+url+":"+ e.toString()); LOG.e(TAG, "Error sending sms " + url + ":" + e.toString());
} }
} }
@ -151,12 +165,12 @@ public class CordovaWebViewClient extends WebViewClient {
// If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity. // If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity.
// Our app continues to run. When BACK is pressed, our app is redisplayed. // Our app continues to run. When BACK is pressed, our app is redisplayed.
if (url.startsWith("file://") || url.indexOf(appView.baseUrl) == 0 || appView.isUrlWhiteListed(url)) { if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
//This will fix iFrames //This will fix iFrames
if(appView.useBrowserHistory) if (appView.useBrowserHistory)
return false; return false;
else else
appView.loadUrl(url); this.appView.loadUrl(url);
} }
// If not our application, let default viewer handle // If not our application, let default viewer handle
@ -164,63 +178,68 @@ public class CordovaWebViewClient extends WebViewClient {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW); Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url)); intent.setData(Uri.parse(url));
ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error loading url "+url, e); LOG.e(TAG, "Error loading url " + url, e);
} }
} }
} }
return true; return true;
} }
/** /**
* On received http auth request. * On received http auth request.
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
* *
* @param view * @param view
* the view
* @param handler * @param handler
* the handler
* @param host * @param host
* the host
* @param realm * @param realm
* the realm
*/ */
@Override @Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
String realm) {
// Get the authentication token
// get the authentication token AuthenticationToken token = this.getAuthenticationToken(host, realm);
// Note: The WebView MUST be a CordoaWebView if (token != null) {
AuthenticationToken token = ((CordovaWebView) view).getAuthenticationToken(host,realm);
if(token != null) {
handler.proceed(token.getUserName(), token.getPassword()); handler.proceed(token.getUserName(), token.getPassword());
} }
} }
/**
* Notify the host application that a page has started loading.
* This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
* one time for the main frame. This also means that onPageStarted will not be called when the contents of an
* embedded frame changes, i.e. clicking a link whose target is an iframe.
*
* @param view The webview initiating the callback.
* @param url The url of the page.
*/
@Override @Override
public void onPageStarted(WebView view, String url, Bitmap favicon) { public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Clear history so history.back() doesn't do anything. // Clear history so history.back() doesn't do anything.
// So we can reinit() native side CallbackServer & PluginManager.\ // So we can reinit() native side CallbackServer & PluginManager.
if(!appView.useBrowserHistory) if (!this.appView.useBrowserHistory) {
{ view.clearHistory();
view.clearHistory(); this.doClearHistory = true;
this.doClearHistory = true;
} }
// Create callback server and plugin manager // Create callback server and plugin manager
if (appView.callbackServer == null) { if (this.appView.callbackServer == null) {
appView.callbackServer = new CallbackServer(); this.appView.callbackServer = new CallbackServer();
appView.callbackServer.init(url); this.appView.callbackServer.init(url);
} }
else { else {
appView.callbackServer.reinit(url); this.appView.callbackServer.reinit(url);
} }
// Broadcast message that page has loaded
this.appView.postMessage("onPageStarted", url);
} }
/** /**
* Notify the host application that a page has finished loading. * Notify the host application that a page has finished loading.
* This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
* *
* @param view The webview initiating the callback. * @param view The webview initiating the callback.
* @param url The url of the page. * @param url The url of the page.
@ -228,6 +247,7 @@ public class CordovaWebViewClient extends WebViewClient {
@Override @Override
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url); super.onPageFinished(view, url);
LOG.d(TAG, "onPageFinished(" + url + ")");
/** /**
* Because of a timing issue we need to clear this history in onPageFinished as well as * Because of a timing issue we need to clear this history in onPageFinished as well as
@ -241,26 +261,28 @@ public class CordovaWebViewClient extends WebViewClient {
} }
// Clear timeout flag // Clear timeout flag
appView.loadUrlTimeout++; this.appView.loadUrlTimeout++;
// Try firing the onNativeReady event in JS. If it fails because the JS is // Try firing the onNativeReady event in JS. If it fails because the JS is
// not loaded yet then just set a flag so that the onNativeReady can be fired // not loaded yet then just set a flag so that the onNativeReady can be fired
// from the JS side when the JS gets to that code. // from the JS side when the JS gets to that code.
if (!url.equals("about:blank")) { if (!url.equals("about:blank")) {
appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}"); this.appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}");
appView.postMessage("onNativeReady", null); this.appView.postMessage("onNativeReady", null);
} }
// Broadcast message that page has loaded
this.appView.postMessage("onPageFinished", url);
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly // Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
if (appView.getVisibility() == View.INVISIBLE) { if (this.appView.getVisibility() == View.INVISIBLE) {
Thread t = new Thread(new Runnable() { Thread t = new Thread(new Runnable() {
public void run() { public void run() {
try { try {
Thread.sleep(2000); Thread.sleep(2000);
ctx.runOnUiThread(new Runnable() { ctx.getActivity().runOnUiThread(new Runnable() {
public void run() { public void run() {
appView.setVisibility(View.VISIBLE); appView.postMessage("spinner", "stop");
//ctx.spinnerStop();
} }
}); });
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -270,17 +292,15 @@ public class CordovaWebViewClient extends WebViewClient {
t.start(); t.start();
} }
// Shutdown if blank loaded // Shutdown if blank loaded
if (url.equals("about:blank")) { if (url.equals("about:blank")) {
if (appView.callbackServer != null) { if (this.appView.callbackServer != null) {
appView.callbackServer.destroy(); this.appView.callbackServer.destroy();
} }
//this.ctx.endActivity(); appView.postMessage("exit", null);
this.ctx.finish();
} }
} }
/** /**
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
* The errorCode parameter corresponds to one of the ERROR_* constants. * The errorCode parameter corresponds to one of the ERROR_* constants.
@ -292,22 +312,38 @@ public class CordovaWebViewClient extends WebViewClient {
*/ */
@Override @Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
LOG.d(TAG, "DroidGap: GapViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl); LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
// Clear timeout flag // Clear timeout flag
//this.ctx.loadUrlTimeout++; this.appView.loadUrlTimeout++;
// Stop "app loading" spinner if showing
//this.ctx.spinnerStop();
// Handle error // Handle error
//this.ctx.onReceivedError(errorCode, description, failingUrl); JSONObject data = new JSONObject();
try {
data.put("errorCode", errorCode);
data.put("description", description);
data.put("url", failingUrl);
} catch (JSONException e) {
e.printStackTrace();
}
this.appView.postMessage("onReceivedError", data);
} }
/**
* Notify the host application that an SSL error occurred while loading a resource.
* The host application must call either handler.cancel() or handler.proceed().
* Note that the decision may be retained for use in response to future SSL errors.
* The default behavior is to cancel the load.
*
* @param view The WebView that is initiating the callback.
* @param handler An SslErrorHandler object that will handle the user's response.
* @param error The SSL error object.
*/
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
final String packageName = this.ctx.getPackageName(); final String packageName = this.ctx.getActivity().getPackageName();
final PackageManager pm = this.ctx.getPackageManager(); final PackageManager pm = this.ctx.getActivity().getPackageManager();
ApplicationInfo appInfo; ApplicationInfo appInfo;
try { try {
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
@ -317,7 +353,7 @@ public class CordovaWebViewClient extends WebViewClient {
return; return;
} else { } else {
// debug = false // debug = false
super.onReceivedSslError(view, handler, error); super.onReceivedSslError(view, handler, error);
} }
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
// When it doubt, lock it out! // When it doubt, lock it out!
@ -325,14 +361,94 @@ public class CordovaWebViewClient extends WebViewClient {
} }
} }
/**
* Notify the host application to update its visited links database.
*
* @param view The WebView that is initiating the callback.
* @param url The url being visited.
* @param isReload True if this url is being reloaded.
*/
@Override @Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
/* /*
* If you do a document.location.href the url does not get pushed on the stack * If you do a document.location.href the url does not get pushed on the stack
* so we do a check here to see if the url should be pushed. * so we do a check here to see if the url should be pushed.
*/ */
if (!appView.peekAtUrlStack().equals(url)) { if (!this.appView.peekAtUrlStack().equals(url)) {
appView.pushUrl(url); this.appView.pushUrl(url);
} }
} }
/**
* Sets the authentication token.
*
* @param authenticationToken
* @param host
* @param realm
*/
public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
if (host == null) {
host = "";
}
if (realm == null) {
realm = "";
}
this.authenticationTokens.put(host.concat(realm), authenticationToken);
}
/**
* Removes the authentication token.
*
* @param host
* @param realm
*
* @return the authentication token or null if did not exist
*/
public AuthenticationToken removeAuthenticationToken(String host, String realm) {
return this.authenticationTokens.remove(host.concat(realm));
}
/**
* Gets the authentication token.
*
* In order it tries:
* 1- host + realm
* 2- host
* 3- realm
* 4- no host, no realm
*
* @param host
* @param realm
*
* @return the authentication token
*/
public AuthenticationToken getAuthenticationToken(String host, String realm) {
AuthenticationToken token = null;
token = this.authenticationTokens.get(host.concat(realm));
if (token == null) {
// try with just the host
token = this.authenticationTokens.get(host);
// Try the realm
if (token == null) {
token = this.authenticationTokens.get(realm);
}
// if no host found, just query for default
if (token == null) {
token = this.authenticationTokens.get("");
}
}
return token;
}
/**
* Clear all authentication tokens.
*/
public void clearAuthenticationTokens() {
this.authenticationTokens.clear();
}
} }

View File

@ -41,7 +41,7 @@ public class Device extends Plugin {
public static String cordovaVersion = "1.7.0"; // Cordova version public static String cordovaVersion = "1.7.0"; // Cordova version
public static String platform = "Android"; // Device OS public static String platform = "Android"; // Device OS
public static String uuid; // Device UUID public static String uuid; // Device UUID
BroadcastReceiver telephonyReceiver = null; BroadcastReceiver telephonyReceiver = null;
/** /**
@ -49,14 +49,14 @@ public class Device extends Plugin {
*/ */
public Device() { public Device() {
} }
/** /**
* Sets the context of the Command. This can then be used to do things like * Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity. * get file paths associated with the Activity.
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(Context ctx) { public void setContext(CordovaInterface ctx) {
super.setContext(ctx); super.setContext(ctx);
Device.uuid = getUuid(); Device.uuid = getUuid();
this.initTelephonyReceiver(); this.initTelephonyReceiver();
@ -72,8 +72,8 @@ public class Device extends Plugin {
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.OK;
String result = ""; String result = "";
try { try {
if (action.equals("getDeviceInfo")) { if (action.equals("getDeviceInfo")) {
JSONObject r = new JSONObject(); JSONObject r = new JSONObject();
@ -105,32 +105,32 @@ public class Device extends Plugin {
} }
return false; return false;
} }
/** /**
* Unregister receiver. * Unregister receiver.
*/ */
public void onDestroy() { public void onDestroy() {
this.ctx.unregisterReceiver(this.telephonyReceiver); this.ctx.getActivity().unregisterReceiver(this.telephonyReceiver);
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Listen for telephony events: RINGING, OFFHOOK and IDLE * Listen for telephony events: RINGING, OFFHOOK and IDLE
* Send these events to all plugins using * Send these events to all plugins using
* DroidGap.onMessage("telephone", "ringing" | "offhook" | "idle") * DroidGap.onMessage("telephone", "ringing" | "offhook" | "idle")
*/ */
private void initTelephonyReceiver() { private void initTelephonyReceiver() {
IntentFilter intentFilter = new IntentFilter() ; IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
final Context myctx = this.ctx; //final CordovaInterface myctx = this.ctx;
this.telephonyReceiver = new BroadcastReceiver() { this.telephonyReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// If state has changed // If state has changed
if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) { if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
@ -151,9 +151,9 @@ public class Device extends Plugin {
} }
} }
}; };
// Register the receiver // Register the receiver
this.ctx.registerReceiver(this.telephonyReceiver, intentFilter); this.ctx.getActivity().registerReceiver(this.telephonyReceiver, intentFilter);
} }
/** /**
@ -164,14 +164,14 @@ public class Device extends Plugin {
public String getPlatform() { public String getPlatform() {
return Device.platform; return Device.platform;
} }
/** /**
* Get the device's Universally Unique Identifier (UUID). * Get the device's Universally Unique Identifier (UUID).
* *
* @return * @return
*/ */
public String getUuid() { public String getUuid() {
String uuid = Settings.Secure.getString(this.ctx.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); String uuid = Settings.Secure.getString(this.ctx.getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
return uuid; return uuid;
} }
@ -182,18 +182,18 @@ public class Device extends Plugin {
*/ */
public String getCordovaVersion() { public String getCordovaVersion() {
return Device.cordovaVersion; return Device.cordovaVersion;
} }
public String getModel() { public String getModel() {
String model = android.os.Build.MODEL; String model = android.os.Build.MODEL;
return model; return model;
} }
public String getProductName() { public String getProductName() {
String productname = android.os.Build.PRODUCT; String productname = android.os.Build.PRODUCT;
return productname; return productname;
} }
/** /**
* Get the OS version. * Get the OS version.
* *
@ -203,17 +203,16 @@ public class Device extends Plugin {
String osversion = android.os.Build.VERSION.RELEASE; String osversion = android.os.Build.VERSION.RELEASE;
return osversion; return osversion;
} }
public String getSDKVersion() { public String getSDKVersion() {
@SuppressWarnings("deprecation")
String sdkversion = android.os.Build.VERSION.SDK; String sdkversion = android.os.Build.VERSION.SDK;
return sdkversion; return sdkversion;
} }
public String getTimeZoneID() {
TimeZone tz = TimeZone.getDefault();
return(tz.getID());
}
}
public String getTimeZoneID() {
TimeZone tz = TimeZone.getDefault();
return (tz.getID());
}
}

View File

@ -31,107 +31,108 @@ import android.os.StatFs;
* It is used by the FileUtils class. * It is used by the FileUtils class.
*/ */
public class DirectoryManager { public class DirectoryManager {
private static final String LOG_TAG = "DirectoryManager";
/** @SuppressWarnings("unused")
* Determine if a file or directory exists. private static final String LOG_TAG = "DirectoryManager";
*
* @param name The name of the file to check. /**
* @return T=exists, F=not found * Determine if a file or directory exists.
*/ *
protected static boolean testFileExists(String name) { * @param name The name of the file to check.
boolean status; * @return T=exists, F=not found
*/
// If SD card exists protected static boolean testFileExists(String name) {
if ((testSaveLocationExists()) && (!name.equals(""))) { boolean status;
File path = Environment.getExternalStorageDirectory();
// If SD card exists
if ((testSaveLocationExists()) && (!name.equals(""))) {
File path = Environment.getExternalStorageDirectory();
File newPath = constructFilePaths(path.toString(), name); File newPath = constructFilePaths(path.toString(), name);
status = newPath.exists(); status = newPath.exists();
} }
// If no SD card // If no SD card
else{ else {
status = false; status = false;
} }
return status; return status;
} }
/** /**
* Get the free disk space * Get the free disk space
* *
* @return Size in KB or -1 if not available * @return Size in KB or -1 if not available
*/ */
protected static long getFreeDiskSpace(boolean checkInternal) { protected static long getFreeDiskSpace(boolean checkInternal) {
String status = Environment.getExternalStorageState(); String status = Environment.getExternalStorageState();
long freeSpace = 0; long freeSpace = 0;
// If SD card exists // If SD card exists
if (status.equals(Environment.MEDIA_MOUNTED)) { if (status.equals(Environment.MEDIA_MOUNTED)) {
freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath()); freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath());
} }
else if (checkInternal) { else if (checkInternal) {
freeSpace = freeSpaceCalculation("/"); freeSpace = freeSpaceCalculation("/");
} }
// If no SD card and we haven't been asked to check the internal directory then return -1 // If no SD card and we haven't been asked to check the internal directory then return -1
else { else {
return -1; return -1;
} }
return freeSpace; return freeSpace;
} }
/** /**
* Given a path return the number of free KB * Given a path return the number of free KB
* *
* @param path to the file system * @param path to the file system
* @return free space in KB * @return free space in KB
*/ */
private static long freeSpaceCalculation(String path) { private static long freeSpaceCalculation(String path) {
StatFs stat = new StatFs(path); StatFs stat = new StatFs(path);
long blockSize = stat.getBlockSize(); long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks(); long availableBlocks = stat.getAvailableBlocks();
return availableBlocks*blockSize/1024; return availableBlocks * blockSize / 1024;
} }
/** /**
* Determine if SD card exists. * Determine if SD card exists.
* *
* @return T=exists, F=not found * @return T=exists, F=not found
*/ */
protected static boolean testSaveLocationExists() { protected static boolean testSaveLocationExists() {
String sDCardStatus = Environment.getExternalStorageState(); String sDCardStatus = Environment.getExternalStorageState();
boolean status; boolean status;
// If SD card is mounted // If SD card is mounted
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) { if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
status = true; status = true;
} }
// If no SD card // If no SD card
else { else {
status = false; status = false;
} }
return status; return status;
} }
/** /**
* Create a new file object from two file paths. * Create a new file object from two file paths.
* *
* @param file1 Base file path * @param file1 Base file path
* @param file2 Remaining file path * @param file2 Remaining file path
* @return File object * @return File object
*/ */
private static File constructFilePaths (String file1, String file2) { private static File constructFilePaths(String file1, String file2) {
File newPath; File newPath;
if (file2.startsWith(file1)) { if (file2.startsWith(file1)) {
newPath = new File(file2); newPath = new File(file2);
} }
else { else {
newPath = new File(file1+"/"+file2); newPath = new File(file1 + "/" + file2);
} }
return newPath; return newPath;
} }
/** /**
* Determine if we can use the SD Card to store the temporary file. If not then use * Determine if we can use the SD Card to store the temporary file. If not then use
* the internal cache directory. * the internal cache directory.
@ -140,12 +141,12 @@ public class DirectoryManager {
*/ */
protected static String getTempDirectoryPath(Context ctx) { protected static String getTempDirectoryPath(Context ctx) {
File cache = null; File cache = null;
// SD Card Mounted // SD Card Mounted
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + ctx.getPackageName() + "/cache/"); "/Android/data/" + ctx.getPackageName() + "/cache/");
} }
// Use internal storage // Use internal storage
else { else {
cache = ctx.getCacheDir(); cache = ctx.getCacheDir();

File diff suppressed because it is too large Load Diff

View File

@ -51,13 +51,12 @@ import android.net.Uri;
import android.util.Log; import android.util.Log;
import android.webkit.CookieManager; import android.webkit.CookieManager;
public class FileTransfer extends Plugin { public class FileTransfer extends Plugin {
private static final String LOG_TAG = "FileTransfer"; private static final String LOG_TAG = "FileTransfer";
private static final String LINE_START = "--"; private static final String LINE_START = "--";
private static final String LINE_END = "\r\n"; private static final String LINE_END = "\r\n";
private static final String BOUNDRY = "*****"; private static final String BOUNDRY = "*****";
public static int FILE_NOT_FOUND_ERR = 1; public static int FILE_NOT_FOUND_ERR = 1;
public static int INVALID_URL_ERR = 2; public static int INVALID_URL_ERR = 2;
@ -76,8 +75,7 @@ public class FileTransfer extends Plugin {
try { try {
source = args.getString(0); source = args.getString(0);
target = args.getString(1); target = args.getString(1);
} } catch (JSONException e) {
catch (JSONException e) {
Log.d(LOG_TAG, "Missing source or target"); Log.d(LOG_TAG, "Missing source or target");
return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target"); return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target");
} }
@ -151,11 +149,11 @@ public class FileTransfer extends Plugin {
} }
public void checkClientTrusted(X509Certificate[] chain, public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException { String authType) throws CertificateException {
} }
public void checkServerTrusted(X509Certificate[] chain, public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException { String authType) throws CertificateException {
} }
} }; } };
@ -199,7 +197,7 @@ public class FileTransfer extends Plugin {
*/ */
private String getArgument(JSONArray args, int position, String defaultString) { private String getArgument(JSONArray args, int position, String defaultString) {
String arg = defaultString; String arg = defaultString;
if(args.length() >= position) { if (args.length() >= position) {
arg = args.optString(position); arg = args.optString(position);
if (arg == null || "null".equals(arg)) { if (arg == null || "null".equals(arg)) {
arg = defaultString; arg = defaultString;
@ -219,6 +217,7 @@ public class FileTransfer extends Plugin {
* @param params key:value pairs of user-defined parameters * @param params key:value pairs of user-defined parameters
* @return FileUploadResult containing result of upload request * @return FileUploadResult containing result of upload request
*/ */
@SuppressWarnings("deprecation")
public FileUploadResult upload(String file, String server, final String fileKey, final String fileName, public FileUploadResult upload(String file, String server, final String fileKey, final String fileName,
final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException { final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException {
// Create return object // Create return object
@ -275,26 +274,26 @@ public class FileTransfer extends Plugin {
// Use a post method. // Use a post method.
conn.setRequestMethod("POST"); conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+BOUNDRY); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDRY);
// Handle the other headers // Handle the other headers
try { try {
JSONObject headers = params.getJSONObject("headers"); JSONObject headers = params.getJSONObject("headers");
for (Iterator iter = headers.keys(); iter.hasNext();) for (@SuppressWarnings("rawtypes")
{ Iterator iter = headers.keys(); iter.hasNext();)
String headerKey = iter.next().toString(); {
conn.setRequestProperty(headerKey, headers.getString(headerKey)); String headerKey = iter.next().toString();
} conn.setRequestProperty(headerKey, headers.getString(headerKey));
}
} catch (JSONException e1) { } catch (JSONException e1) {
// No headers to be manipulated! // No headers to be manipulated!
} }
// Set the cookies on the response // Set the cookies on the response
String cookie = CookieManager.getInstance().getCookie(server); String cookie = CookieManager.getInstance().getCookie(server);
if (cookie != null) { if (cookie != null) {
conn.setRequestProperty("Cookie", cookie); conn.setRequestProperty("Cookie", cookie);
} }
/* /*
* Store the non-file portions of the multipart data as a string, so that we can add it * Store the non-file portions of the multipart data as a string, so that we can add it
@ -302,42 +301,42 @@ public class FileTransfer extends Plugin {
*/ */
String extraParams = ""; String extraParams = "";
try { try {
for (Iterator iter = params.keys(); iter.hasNext();) { for (@SuppressWarnings("rawtypes")
Iterator iter = params.keys(); iter.hasNext();) {
Object key = iter.next(); Object key = iter.next();
if(key.toString() != "headers") if (key.toString() != "headers")
{ {
extraParams += LINE_START + BOUNDRY + LINE_END; extraParams += LINE_START + BOUNDRY + LINE_END;
extraParams += "Content-Disposition: form-data; name=\"" + key.toString() + "\";"; extraParams += "Content-Disposition: form-data; name=\"" + key.toString() + "\";";
extraParams += LINE_END + LINE_END; extraParams += LINE_END + LINE_END;
extraParams += params.getString(key.toString()); extraParams += params.getString(key.toString());
extraParams += LINE_END; extraParams += LINE_END;
} }
} }
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
} }
extraParams += LINE_START + BOUNDRY + LINE_END; extraParams += LINE_START + BOUNDRY + LINE_END;
extraParams += "Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\""; extraParams += "Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"";
String midParams = "\"" + LINE_END + "Content-Type: " + mimeType + LINE_END + LINE_END; String midParams = "\"" + LINE_END + "Content-Type: " + mimeType + LINE_END + LINE_END;
String tailParams = LINE_END + LINE_START + BOUNDRY + LINE_START + LINE_END; String tailParams = LINE_END + LINE_START + BOUNDRY + LINE_START + LINE_END;
// Should set this up as an option // Should set this up as an option
if (chunkedMode) { if (chunkedMode) {
conn.setChunkedStreamingMode(maxBufferSize); conn.setChunkedStreamingMode(maxBufferSize);
} }
else else
{ {
int stringLength = extraParams.length() + midParams.length() + tailParams.length() + fileName.getBytes("UTF-8").length; int stringLength = extraParams.length() + midParams.length() + tailParams.length() + fileName.getBytes("UTF-8").length;
Log.d(LOG_TAG, "String Length: " + stringLength); Log.d(LOG_TAG, "String Length: " + stringLength);
int fixedLength = (int) fileInputStream.getChannel().size() + stringLength; int fixedLength = (int) fileInputStream.getChannel().size() + stringLength;
Log.d(LOG_TAG, "Content Length: " + fixedLength); Log.d(LOG_TAG, "Content Length: " + fixedLength);
conn.setFixedLengthStreamingMode(fixedLength); conn.setFixedLengthStreamingMode(fixedLength);
} }
dos = new DataOutputStream( conn.getOutputStream() ); dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(extraParams); dos.writeBytes(extraParams);
//We don't want to chagne encoding, we just want this to write for all Unicode. //We don't want to chagne encoding, we just want this to write for all Unicode.
dos.write(fileName.getBytes("UTF-8")); dos.write(fileName.getBytes("UTF-8"));
@ -373,13 +372,13 @@ public class FileTransfer extends Plugin {
StringBuffer responseString = new StringBuffer(""); StringBuffer responseString = new StringBuffer("");
DataInputStream inStream; DataInputStream inStream;
try { try {
inStream = new DataInputStream ( conn.getInputStream() ); inStream = new DataInputStream(conn.getInputStream());
} catch(FileNotFoundException e) { } catch (FileNotFoundException e) {
throw new IOException("Received error from server"); throw new IOException("Received error from server");
} }
String line; String line;
while (( line = inStream.readLine()) != null) { while ((line = inStream.readLine()) != null) {
responseString.append(line); responseString.append(line);
} }
Log.d(LOG_TAG, "got response from server"); Log.d(LOG_TAG, "got response from server");
@ -394,7 +393,7 @@ public class FileTransfer extends Plugin {
// Revert back to the proper verifier and socket factories // Revert back to the proper verifier and socket factories
if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) { if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) {
((HttpsURLConnection)conn).setHostnameVerifier(defaultHostnameVerifier); ((HttpsURLConnection) conn).setHostnameVerifier(defaultHostnameVerifier);
HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory); HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory);
} }
@ -416,46 +415,46 @@ public class FileTransfer extends Plugin {
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
// connect to server // connect to server
if(webView.isUrlWhiteListed(source)) if (webView.isUrlWhiteListed(source))
{ {
URL url = new URL(source); URL url = new URL(source);
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
//Add cookie support
String cookie = CookieManager.getInstance().getCookie(source);
if(cookie != null)
{
connection.setRequestProperty("cookie", cookie);
}
connection.connect();
Log.d(LOG_TAG, "Download file:" + url); //Add cookie support
String cookie = CookieManager.getInstance().getCookie(source);
if (cookie != null)
{
connection.setRequestProperty("cookie", cookie);
}
InputStream inputStream = connection.getInputStream(); connection.connect();
byte[] buffer = new byte[1024];
int bytesRead = 0;
FileOutputStream outputStream = new FileOutputStream(file); Log.d(LOG_TAG, "Download file:" + url);
// write bytes to file InputStream inputStream = connection.getInputStream();
while ( (bytesRead = inputStream.read(buffer)) > 0 ) { byte[] buffer = new byte[1024];
outputStream.write(buffer,0, bytesRead); int bytesRead = 0;
}
outputStream.close(); FileOutputStream outputStream = new FileOutputStream(file);
Log.d(LOG_TAG, "Saved file: " + target); // write bytes to file
while ((bytesRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, bytesRead);
}
// create FileEntry object outputStream.close();
FileUtils fileUtil = new FileUtils();
return fileUtil.getEntry(file); Log.d(LOG_TAG, "Saved file: " + target);
// create FileEntry object
FileUtils fileUtil = new FileUtils();
return fileUtil.getEntry(file);
} }
else else
{ {
throw new IOException("Error: Unable to connect to domain"); throw new IOException("Error: Unable to connect to domain");
} }
} catch (Exception e) { } catch (Exception e) {
Log.d(LOG_TAG, e.getMessage(), e); Log.d(LOG_TAG, e.getMessage(), e);
@ -473,7 +472,7 @@ public class FileTransfer extends Plugin {
private InputStream getPathFromUri(String path) throws FileNotFoundException { private InputStream getPathFromUri(String path) throws FileNotFoundException {
if (path.startsWith("content:")) { if (path.startsWith("content:")) {
Uri uri = Uri.parse(path); Uri uri = Uri.parse(path);
return ctx.getContentResolver().openInputStream(uri); return ctx.getActivity().getContentResolver().openInputStream(uri);
} }
else if (path.startsWith("file://")) { else if (path.startsWith("file://")) {
int question = path.indexOf("?"); int question = path.indexOf("?");

View File

@ -37,21 +37,22 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.content.Context; //import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log; //import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.app.Activity;
//import android.app.Activity;
/** /**
* This class provides SD card file and directory services to JavaScript. * This class provides SD card file and directory services to JavaScript.
* Only files on the SD card can be accessed. * Only files on the SD card can be accessed.
*/ */
public class FileUtils extends Plugin { public class FileUtils extends Plugin {
@SuppressWarnings("unused")
private static final String LOG_TAG = "FileUtils"; private static final String LOG_TAG = "FileUtils";
private static final String _DATA = "_data"; // The column name where the file path is stored private static final String _DATA = "_data"; // The column name where the file path is stored
@ -132,7 +133,7 @@ public class FileUtils extends Plugin {
else if (action.equals("requestFileSystem")) { else if (action.equals("requestFileSystem")) {
long size = args.optLong(1); long size = args.optLong(1);
if (size != 0) { if (size != 0) {
if (size > (DirectoryManager.getFreeDiskSpace(true)*1024)) { if (size > (DirectoryManager.getFreeDiskSpace(true) * 1024)) {
return new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR); return new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR);
} }
} }
@ -224,8 +225,8 @@ public class FileUtils extends Plugin {
private void notifyDelete(String filePath) { private void notifyDelete(String filePath) {
String newFilePath = stripFileProtocol(filePath); String newFilePath = stripFileProtocol(filePath);
int result = this.ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, int result = this.ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
MediaStore.Images.Media.DATA + " = ?", MediaStore.Images.Media.DATA + " = ?",
new String[] {newFilePath}); new String[] { filePath });
} }
/** /**
@ -238,6 +239,7 @@ public class FileUtils extends Plugin {
* @throws IOException if the user can't read the file * @throws IOException if the user can't read the file
* @throws JSONException * @throws JSONException
*/ */
@SuppressWarnings("deprecation")
private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException { private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
String decoded = URLDecoder.decode(url, "UTF-8"); String decoded = URLDecoder.decode(url, "UTF-8");
@ -245,7 +247,7 @@ public class FileUtils extends Plugin {
// Handle the special case where you get an Android content:// uri. // Handle the special case where you get an Android content:// uri.
if (decoded.startsWith("content:")) { if (decoded.startsWith("content:")) {
Cursor cursor = ((Activity) this.ctx).managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null); Cursor cursor = this.ctx.getActivity().managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
// Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data" // Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst(); cursor.moveToFirst();
@ -296,7 +298,7 @@ public class FileUtils extends Plugin {
if (fp.isDirectory()) { if (fp.isDirectory()) {
File[] files = fp.listFiles(); File[] files = fp.listFiles();
for (int i=0; i<files.length; i++) { for (int i = 0; i < files.length; i++) {
entries.put(getEntry(files[i])); entries.put(getEntry(files[i]));
} }
} }
@ -322,7 +324,6 @@ public class FileUtils extends Plugin {
fileName = stripFileProtocol(fileName); fileName = stripFileProtocol(fileName);
newParent = stripFileProtocol(newParent); newParent = stripFileProtocol(newParent);
// Check for invalid file name // Check for invalid file name
if (newName != null && newName.contains(":")) { if (newName != null && newName.contains(":")) {
throw new EncodingException("Bad file name"); throw new EncodingException("Bad file name");
@ -379,7 +380,7 @@ public class FileUtils extends Plugin {
File destFile = null; File destFile = null;
// I know this looks weird but it is to work around a JSON bug. // I know this looks weird but it is to work around a JSON bug.
if ("null".equals(newName) || "".equals(newName) ) { if ("null".equals(newName) || "".equals(newName)) {
newName = null; newName = null;
} }
@ -401,7 +402,7 @@ public class FileUtils extends Plugin {
* @throws InvalidModificationException * @throws InvalidModificationException
* @throws JSONException * @throws JSONException
*/ */
private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException { private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
// Renaming a file to an existing directory should fail // Renaming a file to an existing directory should fail
if (destFile.exists() && destFile.isDirectory()) { if (destFile.exists() && destFile.isDirectory()) {
throw new InvalidModificationException("Can't rename a file to a directory"); throw new InvalidModificationException("Can't rename a file to a directory");
@ -479,7 +480,7 @@ public class FileUtils extends Plugin {
// This weird test is to determine if we are copying or moving a directory into itself. // 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 is okay but
// Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR // Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR
if (dest.startsWith(src) && dest.indexOf(File.separator, src.length()-1) != -1) { if (dest.startsWith(src) && dest.indexOf(File.separator, src.length() - 1) != -1) {
return true; return true;
} }
@ -728,9 +729,9 @@ public class FileUtils extends Plugin {
private boolean atRootDirectory(String filePath) { private boolean atRootDirectory(String filePath) {
filePath = stripFileProtocol(filePath); filePath = stripFileProtocol(filePath);
if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + ctx.getPackageName() + "/cache") || if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + ctx.getActivity().getPackageName() + "/cache") ||
filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) || filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
filePath.equals("/data/data/" + ctx.getPackageName())) { filePath.equals("/data/data/" + ctx.getActivity().getPackageName())) {
return true; return true;
} }
return false; return false;
@ -748,7 +749,7 @@ public class FileUtils extends Plugin {
} }
return filePath; return filePath;
} }
/** /**
* Create a File object from the passed in path * Create a File object from the passed in path
* *
@ -794,7 +795,7 @@ public class FileUtils extends Plugin {
throw new FileNotFoundException("File: " + filePath + " does not exist."); throw new FileNotFoundException("File: " + filePath + " does not exist.");
} }
JSONObject metadata = new JSONObject(); JSONObject metadata = new JSONObject();
metadata.put("size", file.length()); metadata.put("size", file.length());
metadata.put("type", getMimeType(filePath)); metadata.put("type", getMimeType(filePath));
metadata.put("name", file.getName()); metadata.put("name", file.getName());
@ -819,16 +820,16 @@ public class FileUtils extends Plugin {
fs.put("name", "temporary"); fs.put("name", "temporary");
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + ctx.getPackageName() + "/cache/"); "/Android/data/" + ctx.getActivity().getPackageName() + "/cache/");
// Create the cache dir if it doesn't exist. // Create the cache dir if it doesn't exist.
fp.mkdirs(); fp.mkdirs();
fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() + fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + ctx.getPackageName() + "/cache/")); "/Android/data/" + ctx.getActivity().getPackageName() + "/cache/"));
} else { } else {
fp = new File("/data/data/" + ctx.getPackageName() + "/cache/"); fp = new File("/data/data/" + ctx.getActivity().getPackageName() + "/cache/");
// Create the cache dir if it doesn't exist. // Create the cache dir if it doesn't exist.
fp.mkdirs(); fp.mkdirs();
fs.put("root", getEntry("/data/data/" + ctx.getPackageName() + "/cache/")); fs.put("root", getEntry("/data/data/" + ctx.getActivity().getPackageName() + "/cache/"));
} }
} }
else if (type == PERSISTENT) { else if (type == PERSISTENT) {
@ -836,13 +837,13 @@ public class FileUtils extends Plugin {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
fs.put("root", getEntry(Environment.getExternalStorageDirectory())); fs.put("root", getEntry(Environment.getExternalStorageDirectory()));
} else { } else {
fs.put("root", getEntry("/data/data/" + ctx.getPackageName())); fs.put("root", getEntry("/data/data/" + ctx.getActivity().getPackageName()));
} }
} }
else { else {
throw new IOException("No filesystem of type requested"); throw new IOException("No filesystem of type requested");
} }
return fs; return fs;
} }
@ -943,7 +944,7 @@ public class FileUtils extends Plugin {
String contentType = null; String contentType = null;
if (filename.startsWith("content:")) { if (filename.startsWith("content:")) {
Uri fileUri = Uri.parse(filename); Uri fileUri = Uri.parse(filename);
contentType = this.ctx.getContentResolver().getType(fileUri); contentType = this.ctx.getActivity().getContentResolver().getType(fileUri);
} }
else { else {
contentType = getMimeType(filename); contentType = getMimeType(filename);
@ -962,7 +963,7 @@ public class FileUtils extends Plugin {
*/ */
public static String getMimeType(String filename) { public static String getMimeType(String filename) {
MimeTypeMap map = MimeTypeMap.getSingleton(); MimeTypeMap map = MimeTypeMap.getSingleton();
return map.getMimeTypeFromExtension(map.getFileExtensionFromUrl(filename)); return map.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(filename));
} }
/** /**
@ -976,14 +977,14 @@ public class FileUtils extends Plugin {
/**/ /**/
public long write(String filename, String data, int offset) throws FileNotFoundException, IOException { public long write(String filename, String data, int offset) throws FileNotFoundException, IOException {
filename = stripFileProtocol(filename); filename = stripFileProtocol(filename);
boolean append = false; boolean append = false;
if (offset > 0) { if (offset > 0) {
this.truncateFile(filename, offset); this.truncateFile(filename, offset);
append = true; append = true;
} }
byte [] rawData = data.getBytes(); byte[] rawData = data.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(rawData); ByteArrayInputStream in = new ByteArrayInputStream(rawData);
FileOutputStream out = new FileOutputStream(filename, append); FileOutputStream out = new FileOutputStream(filename, append);
byte buff[] = new byte[rawData.length]; byte buff[] = new byte[rawData.length];
@ -1008,9 +1009,9 @@ public class FileUtils extends Plugin {
RandomAccessFile raf = new RandomAccessFile(filename, "rw"); RandomAccessFile raf = new RandomAccessFile(filename, "rw");
if (raf.length() >= size) { if (raf.length() >= size) {
FileChannel channel = raf.getChannel(); FileChannel channel = raf.getChannel();
channel.truncate(size); channel.truncate(size);
return size; return size;
} }
return raf.length(); return raf.length();
@ -1026,7 +1027,7 @@ public class FileUtils extends Plugin {
private InputStream getPathFromUri(String path) throws FileNotFoundException { private InputStream getPathFromUri(String path) throws FileNotFoundException {
if (path.startsWith("content")) { if (path.startsWith("content")) {
Uri uri = Uri.parse(path); Uri uri = Uri.parse(path);
return ctx.getContentResolver().openInputStream(uri); return ctx.getActivity().getContentResolver().openInputStream(uri);
} }
else { else {
path = stripFileProtocol(path); path = stripFileProtocol(path);
@ -1041,9 +1042,10 @@ public class FileUtils extends Plugin {
* @param ctx) the current applicaiton context * @param ctx) the current applicaiton context
* @return the full path to the file * @return the full path to the file
*/ */
protected static String getRealPathFromURI(Uri contentUri, Activity ctx) { @SuppressWarnings("deprecation")
protected static String getRealPathFromURI(Uri contentUri, CordovaInterface ctx) {
String[] proj = { _DATA }; String[] proj = { _DATA };
Cursor cursor = ctx.managedQuery(contentUri, proj, null, null, null); Cursor cursor = ctx.getActivity().managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(_DATA); int column_index = cursor.getColumnIndexOrThrow(_DATA);
cursor.moveToFirst(); cursor.moveToFirst();
return cursor.getString(column_index); return cursor.getString(column_index);

View File

@ -38,7 +38,7 @@ public class GeoBroker extends Plugin {
private GPSListener gpsListener; private GPSListener gpsListener;
private NetworkListener networkListener; private NetworkListener networkListener;
private LocationManager locationManager; private LocationManager locationManager;
/** /**
* Constructor. * Constructor.
*/ */
@ -54,65 +54,65 @@ public class GeoBroker extends Plugin {
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
if (this.locationManager == null) { if (this.locationManager == null) {
this.locationManager = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE); this.locationManager = (LocationManager) this.ctx.getActivity().getSystemService(Context.LOCATION_SERVICE);
this.networkListener = new NetworkListener(this.locationManager, this); this.networkListener = new NetworkListener(this.locationManager, this);
this.gpsListener = new GPSListener(this.locationManager, this); this.gpsListener = new GPSListener(this.locationManager, this);
} }
PluginResult.Status status = PluginResult.Status.NO_RESULT; PluginResult.Status status = PluginResult.Status.NO_RESULT;
String message = ""; String message = "";
PluginResult result = new PluginResult(status, message); PluginResult result = new PluginResult(status, message);
result.setKeepCallback(true); result.setKeepCallback(true);
try { try {
if (action.equals("getLocation")) { if (action.equals("getLocation")) {
boolean enableHighAccuracy = args.getBoolean(0); boolean enableHighAccuracy = args.getBoolean(0);
int maximumAge = args.getInt(1); int maximumAge = args.getInt(1);
Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER)); Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER));
// Check if we can use lastKnownLocation to get a quick reading and use less battery // Check if we can use lastKnownLocation to get a quick reading and use less battery
if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) { if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) {
result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last)); result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
} else { } else {
this.getCurrentLocation(callbackId, enableHighAccuracy); this.getCurrentLocation(callbackId, enableHighAccuracy);
} }
} }
else if (action.equals("addWatch")) { else if (action.equals("addWatch")) {
String id = args.getString(0); String id = args.getString(0);
boolean enableHighAccuracy = args.getBoolean(1); boolean enableHighAccuracy = args.getBoolean(1);
this.addWatch(id, callbackId, enableHighAccuracy); this.addWatch(id, callbackId, enableHighAccuracy);
} }
else if (action.equals("clearWatch")) { else if (action.equals("clearWatch")) {
String id = args.getString(0); String id = args.getString(0);
this.clearWatch(id); this.clearWatch(id);
} }
} catch (JSONException e) { } catch (JSONException e) {
result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()); result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
} }
return result; return result;
} }
private void clearWatch(String id) { private void clearWatch(String id) {
this.gpsListener.clearWatch(id); this.gpsListener.clearWatch(id);
this.networkListener.clearWatch(id); this.networkListener.clearWatch(id);
}
private void getCurrentLocation(String callbackId, boolean enableHighAccuracy) {
if (enableHighAccuracy) {
this.gpsListener.addCallback(callbackId);
} else {
this.networkListener.addCallback(callbackId);
}
}
private void addWatch(String timerId, String callbackId, boolean enableHighAccuracy) {
if (enableHighAccuracy) {
this.gpsListener.addWatch(timerId, callbackId);
} else {
this.networkListener.addWatch(timerId, callbackId);
}
} }
/** private void getCurrentLocation(String callbackId, boolean enableHighAccuracy) {
if (enableHighAccuracy) {
this.gpsListener.addCallback(callbackId);
} else {
this.networkListener.addCallback(callbackId);
}
}
private void addWatch(String timerId, String callbackId, boolean enableHighAccuracy) {
if (enableHighAccuracy) {
this.gpsListener.addWatch(timerId, callbackId);
} else {
this.networkListener.addWatch(timerId, callbackId);
}
}
/**
* Identifies if action to be executed returns a value and should be run synchronously. * Identifies if action to be executed returns a value and should be run synchronously.
* *
* @param action The action to execute * @param action The action to execute
@ -122,65 +122,66 @@ public class GeoBroker extends Plugin {
// Starting listeners is easier to run on main thread, so don't run async. // Starting listeners is easier to run on main thread, so don't run async.
return true; return true;
} }
/** /**
* Called when the activity is to be shut down. * Called when the activity is to be shut down.
* Stop listener. * Stop listener.
*/ */
public void onDestroy() { public void onDestroy() {
this.networkListener.destroy(); this.networkListener.destroy();
this.gpsListener.destroy(); this.gpsListener.destroy();
this.networkListener = null; this.networkListener = null;
this.gpsListener = null; this.gpsListener = null;
} }
public JSONObject returnLocationJSON(Location loc) { public JSONObject returnLocationJSON(Location loc) {
JSONObject o = new JSONObject(); JSONObject o = new JSONObject();
try { try {
o.put("latitude", loc.getLatitude()); o.put("latitude", loc.getLatitude());
o.put("longitude", loc.getLongitude()); o.put("longitude", loc.getLongitude());
o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null)); o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
o.put("accuracy", loc.getAccuracy()); o.put("accuracy", loc.getAccuracy());
o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null)); o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
o.put("speed", loc.getSpeed()); o.put("speed", loc.getSpeed());
o.put("timestamp", loc.getTime()); o.put("timestamp", loc.getTime());
} catch (JSONException e) { } catch (JSONException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
return o;
return o; }
}
public void win(Location loc, String callbackId) { public void win(Location loc, String callbackId) {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc)); PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
this.success(result, callbackId); this.success(result, callbackId);
} }
/**
* Location failed. Send error back to JavaScript. /**
* * Location failed. Send error back to JavaScript.
* @param code The error code *
* @param msg The error message * @param code The error code
* @throws JSONException * @param msg The error message
*/ * @throws JSONException
public void fail(int code, String msg, String callbackId) { */
JSONObject obj = new JSONObject(); public void fail(int code, String msg, String callbackId) {
String backup = null; JSONObject obj = new JSONObject();
try { String backup = null;
obj.put("code", code); try {
obj.put("message", msg); obj.put("code", code);
} catch (JSONException e) { obj.put("message", msg);
obj = null; } catch (JSONException e) {
backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}"; obj = null;
} backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}";
PluginResult result; }
if (obj != null) { PluginResult result;
result = new PluginResult(PluginResult.Status.ERROR, obj); if (obj != null) {
} else { result = new PluginResult(PluginResult.Status.ERROR, obj);
result = new PluginResult(PluginResult.Status.ERROR, backup); } else {
} result = new PluginResult(PluginResult.Status.ERROR, backup);
}
this.error(result, callbackId);
} this.error(result, callbackId);
}
} }

View File

@ -29,52 +29,61 @@ import org.apache.http.impl.client.DefaultHttpClient;
public class HttpHandler { public class HttpHandler {
protected Boolean get(String url, String file) protected Boolean get(String url, String file)
{ {
HttpEntity entity = getHttpEntity(url); HttpEntity entity = getHttpEntity(url);
try { try {
writeToDisk(entity, file); writeToDisk(entity, file);
} catch (Exception e) { e.printStackTrace(); return false; } } catch (Exception e) {
try { e.printStackTrace();
entity.consumeContent(); return false;
} catch (Exception e) { e.printStackTrace(); return false; } }
return true; try {
} entity.consumeContent();
} catch (Exception e) {
private HttpEntity getHttpEntity(String url) e.printStackTrace();
/** return false;
* get the http entity at a given url }
*/ return true;
{ }
HttpEntity entity=null;
try { private HttpEntity getHttpEntity(String url)
DefaultHttpClient httpclient = new DefaultHttpClient(); /**
HttpGet httpget = new HttpGet(url); * get the http entity at a given url
HttpResponse response = httpclient.execute(httpget); */
entity = response.getEntity(); {
} catch (Exception e) { e.printStackTrace(); return null; } HttpEntity entity = null;
return entity; try {
} DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException HttpResponse response = httpclient.execute(httpget);
/** entity = response.getEntity();
* writes a HTTP entity to the specified filename and location on disk } catch (Exception e) {
*/ e.printStackTrace();
{ return null;
int i=0; }
String FilePath="/sdcard/" + file; return entity;
InputStream in = entity.getContent(); }
byte buff[] = new byte[1024];
FileOutputStream out= private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException
new FileOutputStream(FilePath); /**
do { * writes a HTTP entity to the specified filename and location on disk
int numread = in.read(buff); */
if (numread <= 0) {
break; //int i = 0;
out.write(buff, 0, numread); String FilePath = "/sdcard/" + file;
i++; InputStream in = entity.getContent();
} while (true); byte buff[] = new byte[1024];
out.flush(); FileOutputStream out =
out.close(); new FileOutputStream(FilePath);
} do {
int numread = in.read(buff);
if (numread <= 0)
break;
out.write(buff, 0, numread);
//i++;
} while (true);
out.flush();
out.close();
}
} }

View File

@ -17,10 +17,11 @@
under the License. under the License.
*/ */
package org.apache.cordova; package org.apache.cordova;
import org.apache.cordova.api.LOG; import org.apache.cordova.api.LOG;
import android.content.Context; import android.content.Context;
import android.view.View.MeasureSpec; //import android.view.View.MeasureSpec;
import android.widget.LinearLayout; import android.widget.LinearLayout;
/** /**
@ -29,15 +30,15 @@ import android.widget.LinearLayout;
public class LinearLayoutSoftKeyboardDetect extends LinearLayout { public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
private static final String TAG = "SoftKeyboardDetect"; private static final String TAG = "SoftKeyboardDetect";
private int oldHeight = 0; // Need to save the old height as not to send redundant events private int oldHeight = 0; // Need to save the old height as not to send redundant events
private int oldWidth = 0; // Need to save old width for orientation change private int oldWidth = 0; // Need to save old width for orientation change
private int screenWidth = 0; private int screenWidth = 0;
private int screenHeight = 0; private int screenHeight = 0;
private DroidGap app = null; private DroidGap app = null;
public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) { public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
super(context); super(context);
screenWidth = width; screenWidth = width;
screenHeight = height; screenHeight = height;
app = (DroidGap) context; app = (DroidGap) context;
@ -55,8 +56,8 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
* @param heightMeasureSpec * @param heightMeasureSpec
*/ */
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
LOG.v(TAG, "We are in our onMeasure method"); LOG.v(TAG, "We are in our onMeasure method");
// Get the current height of the visible part of the screen. // Get the current height of the visible part of the screen.
@ -66,7 +67,7 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
height = MeasureSpec.getSize(heightMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec);
LOG.v(TAG, "Old Height = %d", oldHeight); LOG.v(TAG, "Old Height = %d", oldHeight);
LOG.v(TAG, "Height = %d", height); LOG.v(TAG, "Height = %d", height);
LOG.v(TAG, "Old Width = %d", oldWidth); LOG.v(TAG, "Old Width = %d", oldWidth);
LOG.v(TAG, "Width = %d", width); LOG.v(TAG, "Width = %d", width);
@ -76,7 +77,7 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
LOG.d(TAG, "Ignore this event"); LOG.d(TAG, "Ignore this event");
} }
// Account for orientation change and ignore this event/Fire orientation change // Account for orientation change and ignore this event/Fire orientation change
else if(screenHeight == width) else if (screenHeight == width)
{ {
int tmp_var = screenHeight; int tmp_var = screenHeight;
screenHeight = screenWidth; screenHeight = screenWidth;
@ -86,14 +87,14 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
// If the height as gotten bigger then we will assume the soft keyboard has // If the height as gotten bigger then we will assume the soft keyboard has
// gone away. // gone away.
else if (height > oldHeight) { else if (height > oldHeight) {
if(app != null) if (app != null)
app.sendJavascript("cordova.fireDocumentEvent('hidekeyboard');"); app.appView.sendJavascript("cordova.fireDocumentEvent('hidekeyboard');");
} }
// If the height as gotten smaller then we will assume the soft keyboard has // If the height as gotten smaller then we will assume the soft keyboard has
// been displayed. // been displayed.
else if (height < oldHeight) { else if (height < oldHeight) {
if(app != null) if (app != null)
app.sendJavascript("cordova.fireDocumentEvent('showkeyboard');"); app.appView.sendJavascript("cordova.fireDocumentEvent('showkeyboard');");
} }
// Update the old height for the next event // Update the old height for the next event

View File

@ -26,7 +26,7 @@ import android.location.LocationManager;
* *
*/ */
public class NetworkListener extends CordovaLocationListener { public class NetworkListener extends CordovaLocationListener {
public NetworkListener(LocationManager locationManager, GeoBroker m) { public NetworkListener(LocationManager locationManager, GeoBroker m) {
super(locationManager, m, "[Cordova NetworkListener]"); super(locationManager, m, "[Cordova NetworkListener]");
} }
} }

View File

@ -23,7 +23,6 @@ import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult; import org.apache.cordova.api.PluginResult;
import org.json.JSONArray; import org.json.JSONArray;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -33,7 +32,7 @@ import android.net.NetworkInfo;
import android.util.Log; import android.util.Log;
public class NetworkManager extends Plugin { public class NetworkManager extends Plugin {
public static int NOT_REACHABLE = 0; public static int NOT_REACHABLE = 0;
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1; public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
public static int REACHABLE_VIA_WIFI_NETWORK = 2; public static int REACHABLE_VIA_WIFI_NETWORK = 2;
@ -66,18 +65,18 @@ public class NetworkManager extends Plugin {
public static final String TYPE_3G = "3g"; public static final String TYPE_3G = "3g";
public static final String TYPE_4G = "4g"; public static final String TYPE_4G = "4g";
public static final String TYPE_NONE = "none"; public static final String TYPE_NONE = "none";
private static final String LOG_TAG = "NetworkManager"; private static final String LOG_TAG = "NetworkManager";
private String connectionCallbackId; private String connectionCallbackId;
ConnectivityManager sockMan; ConnectivityManager sockMan;
BroadcastReceiver receiver; BroadcastReceiver receiver;
/** /**
* Constructor. * Constructor.
*/ */
public NetworkManager() { public NetworkManager() {
this.receiver = null; this.receiver = null;
} }
@ -87,26 +86,27 @@ public class NetworkManager extends Plugin {
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(Context ctx) { public void setContext(CordovaInterface ctx) {
super.setContext(ctx); super.setContext(ctx);
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); this.sockMan = (ConnectivityManager) ctx.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
this.connectionCallbackId = null; this.connectionCallbackId = null;
// We need to listen to connectivity events to update navigator.connection // We need to listen to connectivity events to update navigator.connection
IntentFilter intentFilter = new IntentFilter() ; IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
if (this.receiver == null) { if (this.receiver == null) {
this.receiver = new BroadcastReceiver() { this.receiver = new BroadcastReceiver() {
@SuppressWarnings("deprecation")
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)); updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
} }
}; };
ctx.registerReceiver(this.receiver, intentFilter); ctx.getActivity().registerReceiver(this.receiver, intentFilter);
} }
} }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
@ -118,7 +118,7 @@ public class NetworkManager extends Plugin {
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.INVALID_ACTION; PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
String result = "Unsupported Operation: " + action; String result = "Unsupported Operation: " + action;
if (action.equals("getConnectionInfo")) { if (action.equals("getConnectionInfo")) {
this.connectionCallbackId = callbackId; this.connectionCallbackId = callbackId;
NetworkInfo info = sockMan.getActiveNetworkInfo(); NetworkInfo info = sockMan.getActiveNetworkInfo();
@ -126,7 +126,7 @@ public class NetworkManager extends Plugin {
pluginResult.setKeepCallback(true); pluginResult.setKeepCallback(true);
return pluginResult; return pluginResult;
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} }
@ -139,14 +139,14 @@ public class NetworkManager extends Plugin {
public boolean isSynch(String action) { public boolean isSynch(String action) {
return true; return true;
} }
/** /**
* Stop network receiver. * Stop network receiver.
*/ */
public void onDestroy() { public void onDestroy() {
if (this.receiver != null) { if (this.receiver != null) {
try { try {
this.ctx.unregisterReceiver(this.receiver); this.ctx.getActivity().unregisterReceiver(this.receiver);
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e); Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
} }
@ -157,14 +157,13 @@ public class NetworkManager extends Plugin {
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Updates the JavaScript side whenever the connection changes * Updates the JavaScript side whenever the connection changes
* *
* @param info the current active network info * @param info the current active network info
* @return * @return
*/ */
private void updateConnectionInfo(NetworkInfo info) { private void updateConnectionInfo(NetworkInfo info) {
// send update to javascript "navigator.network.connection" // send update to javascript "navigator.network.connection"
sendUpdate(this.getConnectionInfo(info)); sendUpdate(this.getConnectionInfo(info));
} }
@ -188,7 +187,7 @@ public class NetworkManager extends Plugin {
} }
return type; return type;
} }
/** /**
* Create a new plugin result and send it back to JavaScript * Create a new plugin result and send it back to JavaScript
* *
@ -198,11 +197,11 @@ public class NetworkManager extends Plugin {
PluginResult result = new PluginResult(PluginResult.Status.OK, type); PluginResult result = new PluginResult(PluginResult.Status.OK, type);
result.setKeepCallback(true); result.setKeepCallback(true);
this.success(result, this.connectionCallbackId); this.success(result, this.connectionCallbackId);
// Send to all plugins // Send to all plugins
webView.postMessage("networkconnection", type); webView.postMessage("networkconnection", type);
} }
/** /**
* Determine the type of connection * Determine the type of connection
* *
@ -218,13 +217,13 @@ public class NetworkManager extends Plugin {
} }
else if (type.toLowerCase().equals(MOBILE)) { else if (type.toLowerCase().equals(MOBILE)) {
type = info.getSubtypeName(); type = info.getSubtypeName();
if (type.toLowerCase().equals(GSM) || if (type.toLowerCase().equals(GSM) ||
type.toLowerCase().equals(GPRS) || type.toLowerCase().equals(GPRS) ||
type.toLowerCase().equals(EDGE)) { type.toLowerCase().equals(EDGE)) {
return TYPE_2G; return TYPE_2G;
} }
else if (type.toLowerCase().startsWith(CDMA) || else if (type.toLowerCase().startsWith(CDMA) ||
type.toLowerCase().equals(UMTS) || type.toLowerCase().equals(UMTS) ||
type.toLowerCase().equals(ONEXRTT) || type.toLowerCase().equals(ONEXRTT) ||
type.toLowerCase().equals(EHRPD) || type.toLowerCase().equals(EHRPD) ||
type.toLowerCase().equals(HSUPA) || type.toLowerCase().equals(HSUPA) ||
@ -232,13 +231,13 @@ public class NetworkManager extends Plugin {
type.toLowerCase().equals(HSPA)) { type.toLowerCase().equals(HSPA)) {
return TYPE_3G; return TYPE_3G;
} }
else if (type.toLowerCase().equals(LTE) || else if (type.toLowerCase().equals(LTE) ||
type.toLowerCase().equals(UMB) || type.toLowerCase().equals(UMB) ||
type.toLowerCase().equals(HSPA_PLUS)) { type.toLowerCase().equals(HSPA_PLUS)) {
return TYPE_4G; return TYPE_4G;
} }
} }
} }
else { else {
return TYPE_NONE; return TYPE_NONE;
} }

View File

@ -31,337 +31,336 @@ import android.media.Ringtone;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Vibrator; import android.os.Vibrator;
import android.app.Activity;
/** /**
* This class provides access to notifications on the device. * This class provides access to notifications on the device.
*/ */
public class Notification extends Plugin { public class Notification extends Plugin {
public int confirmResult = -1;
public ProgressDialog spinnerDialog = null;
public ProgressDialog progressDialog = null;
/**
* Constructor.
*/
public Notification() {
}
/** public int confirmResult = -1;
* Executes the request and returns PluginResult. public ProgressDialog spinnerDialog = null;
* public ProgressDialog progressDialog = null;
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("beep")) {
this.beep(args.getLong(0));
}
else if (action.equals("vibrate")) {
this.vibrate(args.getLong(0));
}
else if (action.equals("alert")) {
this.alert(args.getString(0),args.getString(1),args.getString(2), callbackId);
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
else if (action.equals("confirm")) {
this.confirm(args.getString(0),args.getString(1),args.getString(2), callbackId);
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
else if (action.equals("activityStart")) {
this.activityStart(args.getString(0),args.getString(1));
}
else if (action.equals("activityStop")) {
this.activityStop();
}
else if (action.equals("progressStart")) {
this.progressStart(args.getString(0),args.getString(1));
}
else if (action.equals("progressValue")) {
this.progressValue(args.getInt(0));
}
else if (action.equals("progressStop")) {
this.progressStop();
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Constructor.
* */
* @param action The action to execute public Notification() {
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("alert")) {
return true;
} }
else if (action.equals("confirm")) {
return true; /**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("beep")) {
this.beep(args.getLong(0));
}
else if (action.equals("vibrate")) {
this.vibrate(args.getLong(0));
}
else if (action.equals("alert")) {
this.alert(args.getString(0), args.getString(1), args.getString(2), callbackId);
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
else if (action.equals("confirm")) {
this.confirm(args.getString(0), args.getString(1), args.getString(2), callbackId);
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
else if (action.equals("activityStart")) {
this.activityStart(args.getString(0), args.getString(1));
}
else if (action.equals("activityStop")) {
this.activityStop();
}
else if (action.equals("progressStart")) {
this.progressStart(args.getString(0), args.getString(1));
}
else if (action.equals("progressValue")) {
this.progressValue(args.getInt(0));
}
else if (action.equals("progressStop")) {
this.progressStop();
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
} }
else if (action.equals("activityStart")) {
return true; /**
* Identifies if action to be executed returns a value and should be run synchronously.
*
* @param action The action to execute
* @return T=returns value
*/
public boolean isSynch(String action) {
if (action.equals("alert")) {
return true;
}
else if (action.equals("confirm")) {
return true;
}
else if (action.equals("activityStart")) {
return true;
}
else if (action.equals("activityStop")) {
return true;
}
else if (action.equals("progressStart")) {
return true;
}
else if (action.equals("progressValue")) {
return true;
}
else if (action.equals("progressStop")) {
return true;
}
else {
return false;
}
} }
else if (action.equals("activityStop")) {
return true;
}
else if (action.equals("progressStart")) {
return true;
}
else if (action.equals("progressValue")) {
return true;
}
else if (action.equals("progressStop")) {
return true;
}
else {
return false;
}
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Beep plays the default notification ringtone. * Beep plays the default notification ringtone.
* *
* @param count Number of times to play notification * @param count Number of times to play notification
*/ */
public void beep(long count) { public void beep(long count) {
Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone notification = RingtoneManager.getRingtone(this.ctx, ringtone); Ringtone notification = RingtoneManager.getRingtone(this.ctx.getActivity().getBaseContext(), ringtone);
// If phone is not set to silent mode // If phone is not set to silent mode
if (notification != null) { if (notification != null) {
for (long i = 0; i < count; ++i) { for (long i = 0; i < count; ++i) {
notification.play(); notification.play();
long timeout = 5000; long timeout = 5000;
while (notification.isPlaying() && (timeout > 0)) { while (notification.isPlaying() && (timeout > 0)) {
timeout = timeout - 100; timeout = timeout - 100;
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
}
}
} }
}
} }
}
/**
/** * Vibrates the device for the specified amount of time.
* Vibrates the device for the specified amount of time. *
* * @param time Time to vibrate in ms.
* @param time Time to vibrate in ms. */
*/ public void vibrate(long time) {
public void vibrate(long time){
// Start the vibration, 0 defaults to half a second. // Start the vibration, 0 defaults to half a second.
if (time == 0) { if (time == 0) {
time = 500; time = 500;
} }
Vibrator vibrator = (Vibrator) this.ctx.getSystemService(Context.VIBRATOR_SERVICE); Vibrator vibrator = (Vibrator) this.ctx.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(time); vibrator.vibrate(time);
}
/**
* Builds and shows a native Android alert with given Strings
* @param message The message the alert should display
* @param title The title of the alert
* @param buttonLabel The label of the button
* @param callbackId The callback id
*/
public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
final Context ctx = this.ctx;
final Notification notification = this;
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(buttonLabel,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
}
});
dlg.create();
dlg.show();
};
};
((Activity) this.ctx).runOnUiThread(runnable);
}
/**
* Builds and shows a native Android confirm dialog with given title, message, buttons.
* This dialog only shows up to 3 buttons. Any labels after that will be ignored.
* The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
*
* @param message The message the dialog should display
* @param title The title of the dialog
* @param buttonLabels A comma separated list of button labels (Up to 3 buttons)
* @param callbackId The callback id
*/
public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
final Context ctx = this.ctx;
final Notification notification = this;
final String[] fButtons = buttonLabels.split(",");
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
// First button
if (fButtons.length > 0) {
dlg.setNegativeButton(fButtons[0],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
}
});
}
// Second button
if (fButtons.length > 1) {
dlg.setNeutralButton(fButtons[1],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
}
});
}
// Third button
if (fButtons.length > 2) {
dlg.setPositiveButton(fButtons[2],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
}
}
);
}
dlg.create();
dlg.show();
};
};
((Activity) this.ctx).runOnUiThread(runnable);
}
/**
* Show the spinner.
*
* @param title Title of the dialog
* @param message The message of the dialog
*/
public synchronized void activityStart(final String title, final String message) {
if (this.spinnerDialog != null) {
this.spinnerDialog.dismiss();
this.spinnerDialog = null;
} }
final Notification notification = this;
final Activity ctx = (Activity) this.ctx;
Runnable runnable = new Runnable() {
public void run() {
notification.spinnerDialog = ProgressDialog.show(ctx, title , message, true, true,
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
notification.spinnerDialog = null;
}
});
}
};
ctx.runOnUiThread(runnable);
}
/**
* Stop spinner.
*/
public synchronized void activityStop() {
if (this.spinnerDialog != null) {
this.spinnerDialog.dismiss();
this.spinnerDialog = null;
}
}
/** /**
* Show the progress dialog. * Builds and shows a native Android alert with given Strings
* * @param message The message the alert should display
* @param title Title of the dialog * @param title The title of the alert
* @param message The message of the dialog * @param buttonLabel The label of the button
*/ * @param callbackId The callback id
public synchronized void progressStart(final String title, final String message) { */
if (this.progressDialog != null) { public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
this.progressDialog.dismiss();
this.progressDialog = null; final CordovaInterface ctx = this.ctx;
final Notification notification = this;
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx.getActivity());
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(buttonLabel,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
}
});
dlg.create();
dlg.show();
};
};
this.ctx.getActivity().runOnUiThread(runnable);
} }
final Notification notification = this;
final Activity ctx = (Activity) this.ctx; /**
Runnable runnable = new Runnable() { * Builds and shows a native Android confirm dialog with given title, message, buttons.
public void run() { * This dialog only shows up to 3 buttons. Any labels after that will be ignored.
notification.progressDialog = new ProgressDialog(ctx); * The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); *
notification.progressDialog.setTitle(title); * @param message The message the dialog should display
notification.progressDialog.setMessage(message); * @param title The title of the dialog
notification.progressDialog.setCancelable(true); * @param buttonLabels A comma separated list of button labels (Up to 3 buttons)
notification.progressDialog.setMax(100); * @param callbackId The callback id
notification.progressDialog.setProgress(0); */
notification.progressDialog.setOnCancelListener( public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) { final CordovaInterface ctx = this.ctx;
notification.progressDialog = null; final Notification notification = this;
final String[] fButtons = buttonLabels.split(",");
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx.getActivity());
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
// First button
if (fButtons.length > 0) {
dlg.setNegativeButton(fButtons[0],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
}
});
}
// Second button
if (fButtons.length > 1) {
dlg.setNeutralButton(fButtons[1],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
}
});
}
// Third button
if (fButtons.length > 2) {
dlg.setPositiveButton(fButtons[2],
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
}
}
);
}
dlg.create();
dlg.show();
};
};
this.ctx.getActivity().runOnUiThread(runnable);
}
/**
* Show the spinner.
*
* @param title Title of the dialog
* @param message The message of the dialog
*/
public synchronized void activityStart(final String title, final String message) {
if (this.spinnerDialog != null) {
this.spinnerDialog.dismiss();
this.spinnerDialog = null;
}
final Notification notification = this;
final CordovaInterface ctx = this.ctx;
Runnable runnable = new Runnable() {
public void run() {
notification.spinnerDialog = ProgressDialog.show(ctx.getActivity(), title, message, true, true,
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
notification.spinnerDialog = null;
}
});
} }
}); };
notification.progressDialog.show(); this.ctx.getActivity().runOnUiThread(runnable);
} }
};
ctx.runOnUiThread(runnable); /**
} * Stop spinner.
*/
/** public synchronized void activityStop() {
* Set value of progress bar. if (this.spinnerDialog != null) {
* this.spinnerDialog.dismiss();
* @param value 0-100 this.spinnerDialog = null;
*/ }
public synchronized void progressValue(int value) { }
if (this.progressDialog != null) {
this.progressDialog.setProgress(value); /**
} * Show the progress dialog.
} *
* @param title Title of the dialog
/** * @param message The message of the dialog
* Stop progress dialog. */
*/ public synchronized void progressStart(final String title, final String message) {
public synchronized void progressStop() { if (this.progressDialog != null) {
if (this.progressDialog != null) { this.progressDialog.dismiss();
this.progressDialog.dismiss(); this.progressDialog = null;
this.progressDialog = null; }
final Notification notification = this;
final CordovaInterface ctx = this.ctx;
Runnable runnable = new Runnable() {
public void run() {
notification.progressDialog = new ProgressDialog(ctx.getActivity());
notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
notification.progressDialog.setTitle(title);
notification.progressDialog.setMessage(message);
notification.progressDialog.setCancelable(true);
notification.progressDialog.setMax(100);
notification.progressDialog.setProgress(0);
notification.progressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
notification.progressDialog = null;
}
});
notification.progressDialog.show();
}
};
this.ctx.getActivity().runOnUiThread(runnable);
}
/**
* Set value of progress bar.
*
* @param value 0-100
*/
public synchronized void progressValue(int value) {
if (this.progressDialog != null) {
this.progressDialog.setProgress(value);
}
}
/**
* Stop progress dialog.
*/
public synchronized void progressStop() {
if (this.progressDialog != null) {
this.progressDialog.dismiss();
this.progressDialog = null;
}
} }
}
} }

View File

@ -31,7 +31,8 @@ public class SplashScreen extends Plugin {
String result = ""; String result = "";
if (action.equals("hide")) { if (action.equals("hide")) {
((DroidGap)this.ctx).removeSplashScreen(); //((DroidGap)this.ctx).removeSplashScreen();
this.webView.postMessage("splashscreen", "hide");
} }
else { else {
status = PluginResult.Status.INVALID_ACTION; status = PluginResult.Status.INVALID_ACTION;

View File

@ -18,18 +18,18 @@
*/ */
package org.apache.cordova; package org.apache.cordova;
import java.lang.reflect.Field; //import java.lang.reflect.Field;
import android.app.Activity; //import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
public class StandAlone extends DroidGap { public class StandAlone extends DroidGap {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html"); super.loadUrl("file:///android_asset/www/index.html");
} }
} }

View File

@ -37,203 +37,202 @@ import android.database.sqlite.*;
*/ */
public class Storage extends Plugin { public class Storage extends Plugin {
// Data Definition Language // Data Definition Language
private static final String ALTER = "alter"; private static final String ALTER = "alter";
private static final String CREATE = "create"; private static final String CREATE = "create";
private static final String DROP = "drop"; private static final String DROP = "drop";
private static final String TRUNCATE = "truncate"; private static final String TRUNCATE = "truncate";
SQLiteDatabase myDb = null; // Database object
String path = null; // Database path
String dbName = null; // Database name
/** SQLiteDatabase myDb = null; // Database object
* Constructor. String path = null; // Database path
*/ String dbName = null; // Database name
public Storage() {
}
/** /**
* Executes the request and returns PluginResult. * Constructor.
* */
* @param action public Storage() {
* The action to execute. }
* @param args
* JSONArry of arguments for the plugin.
* @param callbackId
* The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try { /**
if (action.equals("openDatabase")) { * Executes the request and returns PluginResult.
this.openDatabase(args.getString(0), args.getString(1), *
args.getString(2), args.getLong(3)); * @param action
} else if (action.equals("executeSql")) { * The action to execute.
String[] s = null; * @param args
if (args.isNull(1)) { * JSONArry of arguments for the plugin.
s = new String[0]; * @param callbackId
} else { * The callback id used when calling back into JavaScript.
JSONArray a = args.getJSONArray(1); * @return A PluginResult object with a status and message.
int len = a.length(); */
s = new String[len]; public PluginResult execute(String action, JSONArray args, String callbackId) {
for (int i = 0; i < len; i++) { PluginResult.Status status = PluginResult.Status.OK;
s[i] = a.getString(i); String result = "";
}
}
this.executeSql(args.getString(0), s, args.getString(2));
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/** try {
* Identifies if action to be executed returns a value and should be run if (action.equals("openDatabase")) {
* synchronously. this.openDatabase(args.getString(0), args.getString(1),
* args.getString(2), args.getLong(3));
* @param action } else if (action.equals("executeSql")) {
* The action to execute String[] s = null;
* @return T=returns value if (args.isNull(1)) {
*/ s = new String[0];
public boolean isSynch(String action) { } else {
return true; JSONArray a = args.getJSONArray(1);
} int len = a.length();
s = new String[len];
for (int i = 0; i < len; i++) {
s[i] = a.getString(i);
}
}
this.executeSql(args.getString(0), s, args.getString(2));
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
/** /**
* Clean up and close database. * Identifies if action to be executed returns a value and should be run
*/ * synchronously.
@Override *
public void onDestroy() { * @param action
if (this.myDb != null) { * The action to execute
this.myDb.close(); * @return T=returns value
this.myDb = null; */
} public boolean isSynch(String action) {
} return true;
}
// -------------------------------------------------------------------------- /**
// LOCAL METHODS * Clean up and close database.
// -------------------------------------------------------------------------- */
@Override
public void onDestroy() {
if (this.myDb != null) {
this.myDb.close();
this.myDb = null;
}
}
/** // --------------------------------------------------------------------------
* Open database. // LOCAL METHODS
* // --------------------------------------------------------------------------
* @param db
* The name of the database
* @param version
* The version
* @param display_name
* The display name
* @param size
* The size in bytes
*/
public void openDatabase(String db, String version, String display_name,
long size) {
// If database is open, then close it /**
if (this.myDb != null) { * Open database.
this.myDb.close(); *
} * @param db
* The name of the database
* @param version
* The version
* @param display_name
* The display name
* @param size
* The size in bytes
*/
public void openDatabase(String db, String version, String display_name,
long size) {
// If no database path, generate from application package // If database is open, then close it
if (this.path == null) { if (this.myDb != null) {
this.path = this.ctx.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); this.myDb.close();
} }
this.dbName = this.path + File.pathSeparator + db + ".db"; // If no database path, generate from application package
this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null); if (this.path == null) {
} this.path = this.ctx.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
}
/** this.dbName = this.path + File.pathSeparator + db + ".db";
* Execute SQL statement. this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
* }
* @param query
* The SQL query
* @param params
* Parameters for the query
* @param tx_id
* Transaction id
*/
public void executeSql(String query, String[] params, String tx_id) {
try {
if (isDDL(query)) {
this.myDb.execSQL(query);
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
}
else {
Cursor myCursor = this.myDb.rawQuery(query, params);
this.processResults(myCursor, tx_id);
myCursor.close();
}
}
catch (SQLiteException ex) {
ex.printStackTrace();
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
// Send error message back to JavaScript
this.sendJavascript("cordova.require('cordova/plugin/android/storage').fail('" + ex.getMessage() + "','" + tx_id + "');");
}
}
/** /**
* Checks to see the the query is a Data Definintion command * Execute SQL statement.
* *
* @param query to be executed * @param query
* @return true if it is a DDL command, false otherwise * The SQL query
*/ * @param params
private boolean isDDL(String query) { * Parameters for the query
String cmd = query.toLowerCase(); * @param tx_id
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) { * Transaction id
return true; */
} public void executeSql(String query, String[] params, String tx_id) {
return false; try {
} if (isDDL(query)) {
this.myDb.execSQL(query);
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
}
else {
Cursor myCursor = this.myDb.rawQuery(query, params);
this.processResults(myCursor, tx_id);
myCursor.close();
}
} catch (SQLiteException ex) {
ex.printStackTrace();
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
/** // Send error message back to JavaScript
* Process query results. this.sendJavascript("cordova.require('cordova/plugin/android/storage').fail('" + ex.getMessage() + "','" + tx_id + "');");
* }
* @param cur }
* Cursor into query results
* @param tx_id
* Transaction id
*/
public void processResults(Cursor cur, String tx_id) {
String result = "[]"; /**
// If query result has rows * Checks to see the the query is a Data Definintion command
*
* @param query to be executed
* @return true if it is a DDL command, false otherwise
*/
private boolean isDDL(String query) {
String cmd = query.toLowerCase();
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
return true;
}
return false;
}
if (cur.moveToFirst()) { /**
JSONArray fullresult = new JSONArray(); * Process query results.
String key = ""; *
String value = ""; * @param cur
int colCount = cur.getColumnCount(); * Cursor into query results
* @param tx_id
* Transaction id
*/
public void processResults(Cursor cur, String tx_id) {
// Build up JSON result object for each row String result = "[]";
do { // If query result has rows
JSONObject row = new JSONObject();
try {
for (int i = 0; i < colCount; ++i) {
key = cur.getColumnName(i);
value = cur.getString(i);
row.put(key, value);
}
fullresult.put(row);
} catch (JSONException e) { if (cur.moveToFirst()) {
e.printStackTrace(); JSONArray fullresult = new JSONArray();
} String key = "";
String value = "";
int colCount = cur.getColumnCount();
} while (cur.moveToNext()); // Build up JSON result object for each row
do {
JSONObject row = new JSONObject();
try {
for (int i = 0; i < colCount; ++i) {
key = cur.getColumnName(i);
value = cur.getString(i);
row.put(key, value);
}
fullresult.put(row);
result = fullresult.toString(); } catch (JSONException e) {
} e.printStackTrace();
}
// Let JavaScript know that there are no more rows } while (cur.moveToNext());
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
} result = fullresult.toString();
}
// Let JavaScript know that there are no more rows
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
}
} }

View File

@ -25,7 +25,6 @@ import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult; import org.apache.cordova.api.PluginResult;
import org.json.JSONArray; import org.json.JSONArray;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
@ -33,80 +32,81 @@ import android.hardware.SensorManager;
import android.content.Context; import android.content.Context;
public class TempListener extends Plugin implements SensorEventListener { public class TempListener extends Plugin implements SensorEventListener {
Sensor mSensor;
private SensorManager sensorManager;
/**
* Constructor.
*/
public TempListener() {
}
/** Sensor mSensor;
* Sets the context of the Command. This can then be used to do things like private SensorManager sensorManager;
* get file paths associated with the Activity.
* /**
* @param ctx The context of the main Activity. * Constructor.
*/ */
public void setContext(Context ctx) { public TempListener() {
super.setContext(ctx); }
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
} /**
* Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity.
*
* @param ctx The context of the main Activity.
*/
public void setContext(CordovaInterface ctx) {
super.setContext(ctx);
this.sensorManager = (SensorManager) ctx.getActivity().getSystemService(Context.SENSOR_SERVICE);
}
/**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
if (action.equals("start")) {
this.start();
}
else if (action.equals("stop")) {
this.stop();
}
return new PluginResult(status, result);
}
/**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
if (action.equals("start")) {
this.start();
}
else if (action.equals("stop")) {
this.stop();
}
return new PluginResult(status, result);
}
/** /**
* Called by AccelBroker when listener is to be shut down. * Called by AccelBroker when listener is to be shut down.
* Stop listener. * Stop listener.
*/ */
public void onDestroy() { public void onDestroy() {
this.stop(); this.stop();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
public void start() { public void start() {
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE); @SuppressWarnings("deprecation")
if (list.size() > 0) { List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
this.mSensor = list.get(0); if (list.size() > 0) {
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL); this.mSensor = list.get(0);
} this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
} }
}
public void stop() {
this.sensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) { public void stop() {
// We want to know what temp this is. this.sensorManager.unregisterListener(this);
float temp = event.values[0]; }
this.sendJavascript("gotTemp(" + temp + ");");
} public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
// We want to know what temp this is.
float temp = event.values[0];
this.sendJavascript("gotTemp(" + temp + ");");
}
} }

View File

@ -18,23 +18,8 @@
*/ */
package org.apache.cordova.api; package org.apache.cordova.api;
import java.util.HashMap;
import android.app.Activity; import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.hardware.SensorManager;
import android.net.Uri;
import android.view.Menu;
import android.view.MenuItem;
/** /**
* The Cordova activity abstract class that is extended by DroidGap. * The Cordova activity abstract class that is extended by DroidGap.
@ -42,7 +27,6 @@ import android.view.MenuItem;
*/ */
public interface CordovaInterface { public interface CordovaInterface {
/** /**
* Launch an activity for which you would like a result when it finished. When this activity exits, * Launch an activity for which you would like a result when it finished. When this activity exits,
* your onActivityResult() method will be called. * your onActivityResult() method will be called.
@ -52,147 +36,45 @@ public interface CordovaInterface {
* @param requestCode The request code that is passed to callback to identify the activity * @param requestCode The request code that is passed to callback to identify the activity
*/ */
abstract public void startActivityForResult(IPlugin command, Intent intent, int requestCode); abstract public void startActivityForResult(IPlugin command, Intent intent, int requestCode);
/** /**
* Set the plugin to be called when a sub-activity exits. * Set the plugin to be called when a sub-activity exits.
* *
* @param plugin The plugin on which onActivityResult is to be called * @param plugin The plugin on which onActivityResult is to be called
*/ */
abstract public void setActivityResultCallback(IPlugin plugin); abstract public void setActivityResultCallback(IPlugin plugin);
/** /**
* Causes the Activity to override the back button behaviour * Causes the Activity to override the back button behavior.
*
* @param override * @param override
*/ */
public abstract void bindBackButton(boolean override); public abstract void bindBackButton(boolean override);
/** /**
* A hook required to check if the Back Button is bound * A hook required to check if the Back Button is bound.
*
* @return * @return
*/ */
public abstract boolean isBackButtonBound(); public abstract boolean isBackButtonBound();
/*
* Hook in DroidGap for menu plugins
* (This is in the Android SDK, do we need this on the Interface?)
*/
public abstract boolean onCreateOptionsMenu(Menu menu);
public abstract boolean onPrepareOptionsMenu(Menu menu);
public abstract boolean onOptionsItemSelected(MenuItem item);
/** /**
* @deprecated * Get the Android activity.
* Add services to res/xml/plugins.xml instead.
* *
* Add a class that implements a service. * @return
*
* @param serviceType
* @param className
*/ */
@Deprecated public abstract Activity getActivity();
abstract public void addService(String serviceType, String className);
/**
* @deprecated
* Send JavaScript statement back to JavaScript.
*
* @param message
*/
@Deprecated
abstract public void sendJavascript(String statement);
/**
* @deprecated
* Launch an activity for which you would not like a result when it finished.
*
* @param intent The intent to start
*/
@Deprecated
abstract public void startActivity(Intent intent);
/**
* @deprecated
* Load the specified URL in the Cordova webview.
*
* @param url The URL to load.
*/
@Deprecated
abstract public void loadUrl(String url);
/**
* @deprecated
* Send a message to all plugins.
*
* @param id The message id
* @param data The message data
*/
@Deprecated
abstract public void postMessage(String id, Object data);
@Deprecated
public abstract Resources getResources();
@Deprecated
public abstract String getPackageName();
@Deprecated
public abstract Object getSystemService(String service);
@Deprecated
public abstract Context getContext();
@Deprecated
public abstract Context getBaseContext();
@Deprecated
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter intentFilter);
@Deprecated
public abstract ContentResolver getContentResolver();
@Deprecated
public abstract void unregisterReceiver(BroadcastReceiver receiver);
@Deprecated
public abstract Cursor managedQuery(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder);
@Deprecated
public abstract void runOnUiThread(Runnable runnable);
@Deprecated
public abstract AssetManager getAssets();
@Deprecated
public abstract void clearCache();
@Deprecated
public abstract void clearHistory();
@Deprecated
public abstract boolean backHistory();
//public abstract void addWhiteListEntry(String origin, boolean subdomains);
@Deprecated @Deprecated
public abstract void cancelLoadUrl(); public abstract void cancelLoadUrl();
@Deprecated /**
public abstract void showWebPage(String url, boolean openExternal, * Called when a message is sent to plugin.
boolean clearHistory, HashMap<String, Object> params); *
* @param id The message id
* @param data The message data
* @return Object or null
*/
public Object onMessage(String id, Object data);
@Deprecated
public abstract Context getApplicationContext();
@Deprecated
public abstract boolean isUrlWhiteListed(String source);
} }

View File

@ -21,9 +21,8 @@ package org.apache.cordova.api;
import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebView;
import org.json.JSONArray; import org.json.JSONArray;
import android.content.Context; //import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.webkit.WebView;
/** /**
* Plugin interface must be implemented by any plugin classes. * Plugin interface must be implemented by any plugin classes.
@ -31,40 +30,40 @@ import android.webkit.WebView;
* The execute method is called by the PluginManager. * The execute method is called by the PluginManager.
*/ */
public interface IPlugin { public interface IPlugin {
/**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
PluginResult execute(String action, JSONArray args, String callbackId);
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Executes the request and returns PluginResult.
* *
* @param action The action to execute * @param action The action to execute.
* @return T=returns value * @param args JSONArry of arguments for the plugin.
*/ * @param callbackId The callback id used when calling back into JavaScript.
public boolean isSynch(String action); * @return A PluginResult object with a status and message.
*/
PluginResult execute(String action, JSONArray args, String callbackId);
/** /**
* Sets the context of the Plugin. This can then be used to do things like * Identifies if action to be executed returns a value and should be run synchronously.
* get file paths associated with the Activity. *
* * @param action The action to execute
* @param ctx The context of the main Activity. * @return T=returns value
*/ */
void setContext(Context ctx); public boolean isSynch(String action);
/** /**
* Sets the main View of the application, this is the WebView within which * Sets the context of the Plugin. This can then be used to do things like
* a Cordova app runs. * get file paths associated with the Activity.
* *
* @param webView The Cordova WebView * @param ctx The context of the main Activity.
*/ */
void setView(CordovaWebView webView); void setContext(CordovaInterface ctx);
/**
* Sets the main View of the application, this is the WebView within which
* a Cordova app runs.
*
* @param webView The Cordova WebView
*/
void setView(CordovaWebView webView);
/** /**
* Called when the system is about to start resuming a previous activity. * Called when the system is about to start resuming a previous activity.
@ -79,7 +78,7 @@ public interface IPlugin {
* @param multitasking Flag indicating if multitasking is turned on for app * @param multitasking Flag indicating if multitasking is turned on for app
*/ */
void onResume(boolean multitasking); void onResume(boolean multitasking);
/** /**
* Called when the activity receives a new intent. * Called when the activity receives a new intent.
*/ */
@ -89,14 +88,15 @@ public interface IPlugin {
* The final call you receive before your activity is destroyed. * The final call you receive before your activity is destroyed.
*/ */
void onDestroy(); void onDestroy();
/** /**
* Called when a message is sent to plugin. * Called when a message is sent to plugin.
* *
* @param id The message id * @param id The message id
* @param data The message data * @param data The message data
* @return Object to stop propagation or null
*/ */
public void onMessage(String id, Object data); public Object onMessage(String id, Object data);
/** /**
* Called when an activity you launched exits, giving you the requestCode you started it with, * Called when an activity you launched exits, giving you the requestCode you started it with,

View File

@ -21,10 +21,7 @@ package org.apache.cordova.api;
import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebView;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.webkit.WebView;
/** /**
* Plugin interface must be implemented by any plugin classes. * Plugin interface must be implemented by any plugin classes.
@ -33,50 +30,50 @@ import android.webkit.WebView;
*/ */
public abstract class Plugin implements IPlugin { public abstract class Plugin implements IPlugin {
public String id; public String id;
public CordovaWebView webView; // WebView object public CordovaWebView webView; // WebView object
public Context ctx; // CordovaActivity object public CordovaInterface ctx; // CordovaActivity object
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
* @param action The action to execute. * @param action The action to execute.
* @param args JSONArry of arguments for the plugin. * @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public abstract PluginResult execute(String action, JSONArray args, String callbackId); public abstract PluginResult execute(String action, JSONArray args, String callbackId);
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Identifies if action to be executed returns a value and should be run synchronously.
* *
* @param action The action to execute * @param action The action to execute
* @return T=returns value * @return T=returns value
*/ */
public boolean isSynch(String action) { public boolean isSynch(String action) {
return false; return false;
} }
/** /**
* Sets the context of the Plugin. This can then be used to do things like * Sets the context of the Plugin. This can then be used to do things like
* get file paths associated with the Activity. * get file paths associated with the Activity.
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(Context ctx) { public void setContext(CordovaInterface ctx) {
this.ctx = ctx; this.ctx = ctx;
} }
/**
* Sets the main View of the application, this is the WebView within which
* a Cordova app runs.
*
* @param webView The Cordova WebView
*/
public void setView(CordovaWebView webView) {
this.webView = webView;
}
/**
* Sets the main View of the application, this is the WebView within which
* a Cordova app runs.
*
* @param webView The Cordova WebView
*/
public void setView(CordovaWebView webView) {
this.webView = webView;
}
/** /**
* Called when the system is about to start resuming a previous activity. * Called when the system is about to start resuming a previous activity.
* *
@ -92,26 +89,28 @@ public abstract class Plugin implements IPlugin {
*/ */
public void onResume(boolean multitasking) { public void onResume(boolean multitasking) {
} }
/** /**
* Called when the activity receives a new intent. * Called when the activity receives a new intent.
*/ */
public void onNewIntent(Intent intent) { public void onNewIntent(Intent intent) {
} }
/** /**
* The final call you receive before your activity is destroyed. * The final call you receive before your activity is destroyed.
*/ */
public void onDestroy() { public void onDestroy() {
} }
/** /**
* Called when a message is sent to plugin. * Called when a message is sent to plugin.
* *
* @param id The message id * @param id The message id
* @param data The message data * @param data The message data
* @return Object to stop propagation or null
*/ */
public void onMessage(String id, Object data) { public Object onMessage(String id, Object data) {
return null;
} }
/** /**
@ -133,7 +132,7 @@ public abstract class Plugin implements IPlugin {
* @return Return true to prevent the URL from loading. Default is false. * @return Return true to prevent the URL from loading. Default is false.
*/ */
public boolean onOverrideUrlLoading(String url) { public boolean onOverrideUrlLoading(String url) {
return false; return false;
} }
/** /**
@ -143,7 +142,7 @@ public abstract class Plugin implements IPlugin {
* @param statement * @param statement
*/ */
public void sendJavascript(String statement) { public void sendJavascript(String statement) {
webView.sendJavascript(statement); this.webView.sendJavascript(statement);
} }
/** /**
@ -154,10 +153,10 @@ public abstract class Plugin implements IPlugin {
* call success(...) or error(...) * call success(...) or error(...)
* *
* @param pluginResult The result to return. * @param pluginResult The result to return.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void success(PluginResult pluginResult, String callbackId) { public void success(PluginResult pluginResult, String callbackId) {
webView.sendJavascript(pluginResult.toSuccessCallbackString(callbackId)); this.webView.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
} }
/** /**
@ -167,7 +166,7 @@ public abstract class Plugin implements IPlugin {
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void success(JSONObject message, String callbackId) { public void success(JSONObject message, String callbackId) {
webView.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId)); this.webView.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
} }
/** /**
@ -177,17 +176,17 @@ public abstract class Plugin implements IPlugin {
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void success(String message, String callbackId) { public void success(String message, String callbackId) {
webView.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId)); this.webView.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
} }
/** /**
* Call the JavaScript error callback for this plugin. * Call the JavaScript error callback for this plugin.
* *
* @param pluginResult The result to return. * @param pluginResult The result to return.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void error(PluginResult pluginResult, String callbackId) { public void error(PluginResult pluginResult, String callbackId) {
webView.sendJavascript(pluginResult.toErrorCallbackString(callbackId)); this.webView.sendJavascript(pluginResult.toErrorCallbackString(callbackId));
} }
/** /**
@ -197,7 +196,7 @@ public abstract class Plugin implements IPlugin {
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void error(JSONObject message, String callbackId) { public void error(JSONObject message, String callbackId) {
webView.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId)); this.webView.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
} }
/** /**
@ -207,6 +206,6 @@ public abstract class Plugin implements IPlugin {
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
*/ */
public void error(String message, String callbackId) { public void error(String message, String callbackId) {
webView.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId)); this.webView.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
} }
} }

View File

@ -20,8 +20,8 @@ package org.apache.cordova.api;
import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebView;
import android.content.Context; //import android.content.Context;
import android.webkit.WebView; //import android.webkit.WebView;
/** /**
* This class represents a service entry object. * This class represents a service entry object.
@ -69,12 +69,12 @@ public class PluginEntry {
* *
* @return The plugin object * @return The plugin object
*/ */
@SuppressWarnings("unchecked") public IPlugin createPlugin(CordovaWebView webView, CordovaInterface ctx) {
public IPlugin createPlugin(CordovaWebView webView, Context ctx) {
if (this.plugin != null) { if (this.plugin != null) {
return this.plugin; return this.plugin;
} }
try { try {
@SuppressWarnings("rawtypes")
Class c = getClassByName(this.pluginClass); Class c = getClassByName(this.pluginClass);
if (isCordovaPlugin(c)) { if (isCordovaPlugin(c)) {
this.plugin = (IPlugin) c.newInstance(); this.plugin = (IPlugin) c.newInstance();
@ -96,7 +96,7 @@ public class PluginEntry {
* @return * @return
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("rawtypes")
private Class getClassByName(final String clazz) throws ClassNotFoundException { private Class getClassByName(final String clazz) throws ClassNotFoundException {
Class c = null; Class c = null;
if (clazz != null) { if (clazz != null) {
@ -112,7 +112,7 @@ public class PluginEntry {
* @param c The class to check the interfaces of. * @param c The class to check the interfaces of.
* @return Boolean indicating if the class implements org.apache.cordova.api.Plugin * @return Boolean indicating if the class implements org.apache.cordova.api.Plugin
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("rawtypes")
private boolean isCordovaPlugin(Class c) { private boolean isCordovaPlugin(Class c) {
if (c != null) { if (c != null) {
return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c); return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);

View File

@ -28,10 +28,8 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
import android.webkit.WebView;
/** /**
* PluginManager is exposed to JavaScript in the Cordova WebView. * PluginManager is exposed to JavaScript in the Cordova WebView.
@ -45,7 +43,7 @@ public class PluginManager {
// List of service entries // List of service entries
private final HashMap<String, PluginEntry> entries = new HashMap<String, PluginEntry>(); private final HashMap<String, PluginEntry> entries = new HashMap<String, PluginEntry>();
private final Context ctx; private final CordovaInterface ctx;
private final CordovaWebView app; private final CordovaWebView app;
// Flag to track first time through // Flag to track first time through
@ -61,27 +59,12 @@ public class PluginManager {
* @param app * @param app
* @param ctx * @param ctx
*/ */
public PluginManager(CordovaWebView app, Context ctx) { public PluginManager(CordovaWebView app, CordovaInterface ctx) {
this.ctx = ctx; this.ctx = ctx;
this.app = app; this.app = app;
this.firstRun = true; this.firstRun = true;
} }
public PluginManager(WebView mApp, CordovaInterface mCtx) throws Exception {
this.ctx = mCtx.getContext();
if(CordovaWebView.class.isInstance(mApp))
{
this.app = (CordovaWebView) mApp;
}
else
{
//Throw an exception here
throw new Exception();
}
}
/** /**
* Init when loading a new HTML page into webview. * Init when loading a new HTML page into webview.
*/ */
@ -89,9 +72,9 @@ public class PluginManager {
LOG.d(TAG, "init()"); LOG.d(TAG, "init()");
// If first time, then load plugins from plugins.xml file // If first time, then load plugins from plugins.xml file
if (firstRun) { if (this.firstRun) {
this.loadPlugins(); this.loadPlugins();
firstRun = false; this.firstRun = false;
} }
// Stop plugins on current HTML page and discard plugin objects // Stop plugins on current HTML page and discard plugin objects
@ -109,11 +92,11 @@ public class PluginManager {
* Load plugins from res/xml/plugins.xml * Load plugins from res/xml/plugins.xml
*/ */
public void loadPlugins() { public void loadPlugins() {
int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName()); int id = this.ctx.getActivity().getResources().getIdentifier("plugins", "xml", this.ctx.getActivity().getPackageName());
if (id == 0) { if (id == 0) {
pluginConfigurationMissing(); this.pluginConfigurationMissing();
} }
XmlResourceParser xml = ctx.getResources().getXml(id); XmlResourceParser xml = this.ctx.getActivity().getResources().getXml(id);
int eventType = -1; int eventType = -1;
String service = "", pluginClass = ""; String service = "", pluginClass = "";
boolean onload = false; boolean onload = false;
@ -184,14 +167,13 @@ public class PluginManager {
* *
* @return JSON encoded string with a response message and status. * @return JSON encoded string with a response message and status.
*/ */
@SuppressWarnings("unchecked")
public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) { public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) {
PluginResult cr = null; PluginResult cr = null;
boolean runAsync = async; boolean runAsync = async;
try { try {
final JSONArray args = new JSONArray(jsonArgs); final JSONArray args = new JSONArray(jsonArgs);
final IPlugin plugin = this.getPlugin(service); final IPlugin plugin = this.getPlugin(service);
final Context ctx = this.ctx; //final CordovaInterface ctx = this.ctx;
if (plugin != null) { if (plugin != null) {
runAsync = async && !plugin.isSynch(action); runAsync = async && !plugin.isSynch(action);
if (runAsync) { if (runAsync) {
@ -257,7 +239,7 @@ public class PluginManager {
* @return IPlugin or null * @return IPlugin or null
*/ */
private IPlugin getPlugin(String service) { private IPlugin getPlugin(String service) {
PluginEntry entry = entries.get(service); PluginEntry entry = this.entries.get(service);
if (entry == null) { if (entry == null) {
return null; return null;
} }
@ -332,13 +314,22 @@ public class PluginManager {
* *
* @param id The message id * @param id The message id
* @param data The message data * @param data The message data
* @return
*/ */
public void postMessage(String id, Object data) { public Object postMessage(String id, Object data) {
Object obj = this.ctx.onMessage(id, data);
if (obj != null) {
return obj;
}
for (PluginEntry entry : this.entries.values()) { for (PluginEntry entry : this.entries.values()) {
if (entry.plugin != null) { if (entry.plugin != null) {
entry.plugin.onMessage(id, data); obj = entry.plugin.onMessage(id, data);
if (obj != null) {
return obj;
}
} }
} }
return null;
} }
/** /**

View File

@ -21,99 +21,99 @@ package org.apache.cordova.api;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import android.util.Log; //import android.util.Log;
public class PluginResult { public class PluginResult {
private final int status; private final int status;
private final String message; private final String message;
private boolean keepCallback = false; private boolean keepCallback = false;
public PluginResult(Status status) {
this.status = status.ordinal();
this.message = "'" + PluginResult.StatusMessages[this.status] + "'";
}
public PluginResult(Status status, String message) {
this.status = status.ordinal();
this.message = JSONObject.quote(message);
}
public PluginResult(Status status, JSONArray message) { public PluginResult(Status status) {
this.status = status.ordinal(); this.status = status.ordinal();
this.message = message.toString(); this.message = "'" + PluginResult.StatusMessages[this.status] + "'";
} }
public PluginResult(Status status, JSONObject message) { public PluginResult(Status status, String message) {
this.status = status.ordinal(); this.status = status.ordinal();
this.message = message.toString(); this.message = JSONObject.quote(message);
} }
public PluginResult(Status status, int i) { public PluginResult(Status status, JSONArray message) {
this.status = status.ordinal(); this.status = status.ordinal();
this.message = ""+i; this.message = message.toString();
} }
public PluginResult(Status status, float f) { public PluginResult(Status status, JSONObject message) {
this.status = status.ordinal(); this.status = status.ordinal();
this.message = ""+f; this.message = message.toString();
} }
public PluginResult(Status status, boolean b) { public PluginResult(Status status, int i) {
this.status = status.ordinal(); this.status = status.ordinal();
this.message = ""+b; this.message = "" + i;
} }
public void setKeepCallback(boolean b) {
this.keepCallback = b;
}
public int getStatus() {
return status;
}
public String getMessage() { public PluginResult(Status status, float f) {
return message; this.status = status.ordinal();
} this.message = "" + f;
}
public boolean getKeepCallback() {
return this.keepCallback; public PluginResult(Status status, boolean b) {
} this.status = status.ordinal();
this.message = "" + b;
public String getJSONString() { }
return "{status:" + this.status + ",message:" + this.message + ",keepCallback:" + this.keepCallback + "}";
} public void setKeepCallback(boolean b) {
this.keepCallback = b;
public String toSuccessCallbackString(String callbackId) { }
return "cordova.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");";
} public int getStatus() {
return status;
public String toErrorCallbackString(String callbackId) { }
return "cordova.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
} public String getMessage() {
return message;
public static String[] StatusMessages = new String[] { }
"No result",
"OK", public boolean getKeepCallback() {
"Class not found", return this.keepCallback;
"Illegal access", }
"Instantiation error",
"Malformed url", public String getJSONString() {
"IO error", return "{status:" + this.status + ",message:" + this.message + ",keepCallback:" + this.keepCallback + "}";
"Invalid action", }
"JSON error",
"Error" public String toSuccessCallbackString(String callbackId) {
}; return "cordova.callbackSuccess('" + callbackId + "'," + this.getJSONString() + ");";
}
public enum Status {
NO_RESULT, public String toErrorCallbackString(String callbackId) {
OK, return "cordova.callbackError('" + callbackId + "', " + this.getJSONString() + ");";
CLASS_NOT_FOUND_EXCEPTION, }
ILLEGAL_ACCESS_EXCEPTION,
INSTANTIATION_EXCEPTION, public static String[] StatusMessages = new String[] {
MALFORMED_URL_EXCEPTION, "No result",
IO_EXCEPTION, "OK",
INVALID_ACTION, "Class not found",
JSON_EXCEPTION, "Illegal access",
ERROR "Instantiation error",
} "Malformed url",
"IO error",
"Invalid action",
"JSON error",
"Error"
};
public enum Status {
NO_RESULT,
OK,
CLASS_NOT_FOUND_EXCEPTION,
ILLEGAL_ACCESS_EXCEPTION,
INSTANTIATION_EXCEPTION,
MALFORMED_URL_EXCEPTION,
IO_EXCEPTION,
INVALID_ACTION,
JSON_EXCEPTION,
ERROR
}
} }

View File

@ -69,9 +69,9 @@ public class ActivityPlugin extends Plugin {
public void startActivity(String className) { public void startActivity(String className) {
try { try {
Intent intent = new Intent().setClass(this.ctx, Class.forName(className)); Intent intent = new Intent().setClass(this.ctx.getActivity(), Class.forName(className));
LOG.d(TAG, "Starting activity %s", className); LOG.d(TAG, "Starting activity %s", className);
this.ctx.startActivity(intent); this.ctx.getActivity().startActivity(intent);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
LOG.e(TAG, "Error starting activity %s", className); LOG.e(TAG, "Error starting activity %s", className);