diff --git a/framework/AndroidManifest.xml b/framework/AndroidManifest.xml
index c6eeb949..4bae9257 100644
--- a/framework/AndroidManifest.xml
+++ b/framework/AndroidManifest.xml
@@ -25,6 +25,7 @@
+
diff --git a/framework/assets/js/battery.js b/framework/assets/js/battery.js
new file mode 100755
index 00000000..883b2de2
--- /dev/null
+++ b/framework/assets/js/battery.js
@@ -0,0 +1,124 @@
+/*
+ * PhoneGap is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2005-2010, Nitobi Software Inc.
+ * Copyright (c) 2010-2011, IBM Corporation
+ */
+
+if (!PhoneGap.hasResource("battery")) {
+PhoneGap.addResource("battery");
+
+/**
+ * This class contains information about the current battery status.
+ * @constructor
+ */
+var Battery = function() {
+ this._level = null;
+ this._isPlugged = null;
+ this._batteryListener = [];
+ this._lowListener = [];
+ this._criticalListener = [];
+};
+
+/**
+ * Registers as an event producer for battery events.
+ *
+ * @param {Object} eventType
+ * @param {Object} handler
+ * @param {Object} add
+ */
+Battery.prototype.eventHandler = function(eventType, handler, add) {
+ var me = navigator.battery;
+ if (add) {
+ // If there are no current registered event listeners start the battery listener on native side.
+ if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
+ PhoneGap.exec(me._status, me._error, "Battery", "start", []);
+ }
+
+ // Register the event listener in the proper array
+ if (eventType === "batterystatus") {
+ var pos = me._batteryListener.indexOf(handler);
+ if (pos === -1) {
+ me._batteryListener.push(handler);
+ }
+ } else if (eventType === "batterylow") {
+ var pos = me._lowListener.indexOf(handler);
+ if (pos === -1) {
+ me._lowListener.push(handler);
+ }
+ } else if (eventType === "batterycritical") {
+ var pos = me._criticalListener.indexOf(handler);
+ if (pos === -1) {
+ me._criticalListener.push(handler);
+ }
+ }
+ } else {
+ // Remove the event listener from the proper array
+ if (eventType === "batterystatus") {
+ var pos = me._batteryListener.indexOf(handler);
+ if (pos > -1) {
+ me._batteryListener.splice(pos, 1);
+ }
+ } else if (eventType === "batterylow") {
+ var pos = me._lowListener.indexOf(handler);
+ if (pos > -1) {
+ me._lowListener.splice(pos, 1);
+ }
+ } else if (eventType === "batterycritical") {
+ var pos = me._criticalListener.indexOf(handler);
+ if (pos > -1) {
+ me._criticalListener.splice(pos, 1);
+ }
+ }
+
+ // If there are no more registered event listeners stop the battery listener on native side.
+ if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
+ PhoneGap.exec(null, null, "Battery", "stop", []);
+ }
+ }
+};
+
+/**
+ * Callback for battery status
+ *
+ * @param {Object} info keys: level, isPlugged
+ */
+Battery.prototype._status = function(info) {
+ if (info) {
+ var me = this;
+ if (me._level != info.level || me._isPlugged != info.isPlugged) {
+ // Fire batterystatus event
+ PhoneGap.fireWindowEvent("batterystatus", info);
+
+ // Fire low battery event
+ if (info.level == 20 || info.level == 5) {
+ if (info.level == 20) {
+ PhoneGap.fireWindowEvent("batterylow", info);
+ }
+ else {
+ PhoneGap.fireWindowEvent("batterycritical", info);
+ }
+ }
+ }
+ me._level = info.level;
+ me._isPlugged = info.isPlugged;
+ }
+};
+
+/**
+ * Error callback for battery start
+ */
+Battery.prototype._error = function(e) {
+ console.log("Error initializing Battery: " + e);
+};
+
+PhoneGap.addConstructor(function() {
+ if (typeof navigator.battery === "undefined") {
+ navigator.battery = new Battery();
+ PhoneGap.addWindowEventHandler("batterystatus", navigator.battery.eventHandler);
+ PhoneGap.addWindowEventHandler("batterylow", navigator.battery.eventHandler);
+ PhoneGap.addWindowEventHandler("batterycritical", navigator.battery.eventHandler);
+ }
+});
+}
diff --git a/framework/assets/js/media.js b/framework/assets/js/media.js
index de955c66..f530025c 100755
--- a/framework/assets/js/media.js
+++ b/framework/assets/js/media.js
@@ -155,6 +155,13 @@ Media.prototype.release = function() {
PhoneGap.exec(null, null, "Media", "release", [this.id]);
};
+/**
+ * Adjust the volume.
+ */
+Media.prototype.setVolume = function(volume) {
+ PhoneGap.exec(null, null, "Media", "setVolume", [this.id, volume]);
+};
+
/**
* List of media objects.
* PRIVATE
diff --git a/framework/assets/js/network.js b/framework/assets/js/network.js
index b17a3434..f174b6da 100755
--- a/framework/assets/js/network.js
+++ b/framework/assets/js/network.js
@@ -27,7 +27,7 @@ var Connection = function() {
// set a timer if still offline at the end of timer send the offline event
me._timer = setTimeout(function(){
me.type = type;
- PhoneGap.fireEvent('offline');
+ PhoneGap.fireDocumentEvent('offline');
me._timer = null;
}, me.timeout);
} else {
@@ -37,7 +37,7 @@ var Connection = function() {
me._timer = null;
}
me.type = type;
- PhoneGap.fireEvent('online');
+ PhoneGap.fireDocumentEvent('online');
}
// should only fire this once
@@ -47,6 +47,12 @@ var Connection = function() {
}
},
function(e) {
+ // If we can't get the network info we should still tell PhoneGap
+ // to fire the deviceready event.
+ if (me._firstRun) {
+ me._firstRun = false;
+ PhoneGap.onPhoneGapConnectionReady.fire();
+ }
console.log("Error initializing Network Connection: " + e);
});
};
diff --git a/framework/assets/js/phonegap.js.base b/framework/assets/js/phonegap.js.base
index f9ec35d2..f8f64025 100755
--- a/framework/assets/js/phonegap.js.base
+++ b/framework/assets/js/phonegap.js.base
@@ -46,7 +46,9 @@ var PhoneGap = {
ready: true,
commands: [],
timer: null
- }
+ },
+ documentEventHandler: {}, // Collection of custom document event handlers
+ windowEventHandler: {} // Collection of custom window event handlers
};
/**
@@ -365,6 +367,9 @@ PhoneGap.Channel.join(function() {
// Fire onDeviceReady event once all constructors have run and PhoneGap info has been
// received from native side, and any user defined initialization channels.
PhoneGap.Channel.join(function() {
+ // Let native code know we are inited on JS side
+ prompt("", "gap_init:");
+
PhoneGap.onDeviceReady.fire();
// Fire the onresume event, since first one happens before JavaScript is loaded
@@ -381,6 +386,36 @@ document.addEventListener('DOMContentLoaded', function() {
// Intercept calls to document.addEventListener and watch for deviceready
PhoneGap.m_document_addEventListener = document.addEventListener;
+// Intercept calls to window.addEventListener
+PhoneGap.m_window_addEventListener = window.addEventListener;
+
+/**
+ * Add a custom window event handler.
+ *
+ * @param {String} event The event name that callback handles
+ * @param {Function} callback The event handler
+ */
+PhoneGap.addWindowEventHandler = function(event, callback) {
+ PhoneGap.windowEventHandler[event] = callback;
+}
+
+/**
+ * Add a custom document event handler.
+ *
+ * @param {String} event The event name that callback handles
+ * @param {Function} callback The event handler
+ */
+PhoneGap.addDocumentEventHandler = function(event, callback) {
+ PhoneGap.documentEventHandler[event] = callback;
+}
+
+/**
+ * Intercept adding document event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
document.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
if (e === 'deviceready') {
@@ -398,15 +433,52 @@ document.addEventListener = function(evt, handler, capture) {
if (e === 'backbutton') {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [true]);
}
-
+
+ // If subscribing to an event that is handled by a plugin
+ else if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
+ if (PhoneGap.documentEventHandler[e](e, handler, true)) {
+ return; // Stop default behavior
+ }
+ }
+
PhoneGap.m_document_addEventListener.call(document, evt, handler, capture);
}
};
+/**
+ * Intercept adding window event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If subscribing to an event that is handled by a plugin
+ if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
+ if (PhoneGap.windowEventHandler[e](e, handler, true)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_window_addEventListener.call(window, evt, handler, capture);
+};
+
// Intercept calls to document.removeEventListener and watch for events that
// are generated by PhoneGap native code
PhoneGap.m_document_removeEventListener = document.removeEventListener;
+// Intercept calls to window.removeEventListener
+PhoneGap.m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Intercept removing document event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
document.removeEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
@@ -415,18 +487,70 @@ document.removeEventListener = function(evt, handler, capture) {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [false]);
}
+ // If unsubcribing from an event that is handled by a plugin
+ if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
+ if (PhoneGap.documentEventHandler[e](e, handler, false)) {
+ return; // Stop default behavior
+ }
+ }
+
PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
};
/**
- * Method to fire event from native code
+ * Intercept removing window event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
*/
-PhoneGap.fireEvent = function(type) {
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If unsubcribing from an event that is handled by a plugin
+ if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
+ if (PhoneGap.windowEventHandler[e](e, handler, false)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_window_removeEventListener.call(window, evt, handler, capture);
+};
+
+/**
+ * Method to fire document event
+ *
+ * @param {String} type The event type to fire
+ * @param {Object} data Data to send with event
+ */
+PhoneGap.fireDocumentEvent = function(type, data) {
var e = document.createEvent('Events');
e.initEvent(type);
+ if (data) {
+ for (var i in data) {
+ e[i] = data[i];
+ }
+ }
document.dispatchEvent(e);
};
+/**
+ * Method to fire window event
+ *
+ * @param {String} type The event type to fire
+ * @param {Object} data Data to send with event
+ */
+PhoneGap.fireWindowEvent = function(type, data) {
+ var e = document.createEvent('Events');
+ e.initEvent(type);
+ if (data) {
+ for (var i in data) {
+ e[i] = data[i];
+ }
+ }
+ window.dispatchEvent(e);
+};
+
/**
* If JSON not included, use our own stringify. (Android 1.6)
* The restriction on ours is that it must be an array of simple types.
diff --git a/framework/assets/www/phonegap.js b/framework/assets/www/phonegap.js
deleted file mode 100644
index 69cf16f7..00000000
--- a/framework/assets/www/phonegap.js
+++ /dev/null
@@ -1,2861 +0,0 @@
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-
-/**
- * The order of events during page load and PhoneGap startup is as follows:
- *
- * onDOMContentLoaded Internal event that is received when the web page is loaded and parsed.
- * window.onload Body onload event.
- * onNativeReady Internal event that indicates the PhoneGap native side is ready.
- * onPhoneGapInit Internal event that kicks off creation of all PhoneGap JavaScript objects (runs constructors).
- * onPhoneGapReady Internal event fired when all PhoneGap JavaScript objects have been created
- * onPhoneGapInfoReady Internal event fired when device properties are available
- * onDeviceReady User event fired to indicate that PhoneGap is ready
- * onResume User event fired to indicate a start/resume lifecycle event
- *
- * The only PhoneGap events that user code should register for are:
- * onDeviceReady
- * onResume
- *
- * Listeners can be registered as:
- * document.addEventListener("deviceready", myDeviceReadyListener, false);
- * document.addEventListener("resume", myResumeListener, false);
- */
-
-if (typeof(DeviceInfo) != 'object')
- DeviceInfo = {};
-
-/**
- * This represents the PhoneGap API itself, and provides a global namespace for accessing
- * information about the state of PhoneGap.
- * @class
- */
-var PhoneGap = {
- queue: {
- ready: true,
- commands: [],
- timer: null
- }
-};
-
-
-/**
- * Custom pub-sub channel that can have functions subscribed to it
- */
-PhoneGap.Channel = function(type)
-{
- this.type = type;
- this.handlers = {};
- this.guid = 0;
- this.fired = false;
- this.enabled = true;
-};
-
-/**
- * Subscribes the given function to the channel. Any time that
- * Channel.fire is called so too will the function.
- * Optionally specify an execution context for the function
- * and a guid that can be used to stop subscribing to the channel.
- * Returns the guid.
- */
-PhoneGap.Channel.prototype.subscribe = function(f, c, g) {
- // need a function to call
- if (f == null) { return; }
-
- var func = f;
- if (typeof c == "object" && f instanceof Function) { func = PhoneGap.close(c, f); }
-
- g = g || func.observer_guid || f.observer_guid || this.guid++;
- func.observer_guid = g;
- f.observer_guid = g;
- this.handlers[g] = func;
- return g;
-};
-
-/**
- * Like subscribe but the function is only called once and then it
- * auto-unsubscribes itself.
- */
-PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
- var g = null;
- var _this = this;
- var m = function() {
- f.apply(c || null, arguments);
- _this.unsubscribe(g);
- }
- if (this.fired) {
- if (typeof c == "object" && f instanceof Function) { f = PhoneGap.close(c, f); }
- f.apply(this, this.fireArgs);
- } else {
- g = this.subscribe(m);
- }
- return g;
-};
-
-/**
- * Unsubscribes the function with the given guid from the channel.
- */
-PhoneGap.Channel.prototype.unsubscribe = function(g) {
- if (g instanceof Function) { g = g.observer_guid; }
- this.handlers[g] = null;
- delete this.handlers[g];
-};
-
-/**
- * Calls all functions subscribed to this channel.
- */
-PhoneGap.Channel.prototype.fire = function(e) {
- if (this.enabled) {
- var fail = false;
- for (var item in this.handlers) {
- var handler = this.handlers[item];
- if (handler instanceof Function) {
- var rv = (handler.apply(this, arguments)==false);
- fail = fail || rv;
- }
- }
- this.fired = true;
- this.fireArgs = arguments;
- return !fail;
- }
- return true;
-};
-
-/**
- * Calls the provided function only after all of the channels specified
- * have been fired.
- */
-PhoneGap.Channel.join = function(h, c) {
- var i = c.length;
- var f = function() {
- if (!(--i)) h();
- }
- for (var j=0; j 0) {
- s = s + ",";
- }
- var type = typeof args[i];
- if ((type == "number") || (type == "boolean")) {
- s = s + args[i];
- }
- else if (args[i] instanceof Array) {
- s = s + "[" + args[i] + "]";
- }
- else if (args[i] instanceof Object) {
- var start = true;
- s = s + '{';
- for (var name in args[i]) {
- if (!start) {
- s = s + ',';
- }
- s = s + '"' + name + '":';
- var nameType = typeof args[i][name];
- if ((nameType == "number") || (nameType == "boolean")) {
- s = s + args[i][name];
- }
- else {
- s = s + '"' + args[i][name] + '"';
- }
- start=false;
- }
- s = s + '}';
- }
- else {
- var a = args[i].replace(/\\/g, '\\\\');
- a = a.replace(/"/g, '\\"');
- s = s + '"' + a + '"';
- }
- }
- s = s + "]";
- return s;
- }
- else {
- return JSON.stringify(args);
- }
-};
-
-/**
- * Does a deep clone of the object.
- *
- * @param obj
- * @return
- */
-PhoneGap.clone = function(obj) {
- if(!obj) {
- return obj;
- }
-
- if(obj instanceof Array){
- var retVal = new Array();
- for(var i = 0; i < obj.length; ++i){
- retVal.push(PhoneGap.clone(obj[i]));
- }
- return retVal;
- }
-
- if (obj instanceof Function) {
- return obj;
- }
-
- if(!(obj instanceof Object)){
- return obj;
- }
-
- retVal = new Object();
- for(i in obj){
- if(!(i in retVal) || retVal[i] != obj[i]) {
- retVal[i] = PhoneGap.clone(obj[i]);
- }
- }
- return retVal;
-};
-
-PhoneGap.callbackId = 0;
-PhoneGap.callbacks = {};
-PhoneGap.callbackStatus = {
- NO_RESULT: 0,
- OK: 1,
- CLASS_NOT_FOUND_EXCEPTION: 2,
- ILLEGAL_ACCESS_EXCEPTION: 3,
- INSTANTIATION_EXCEPTION: 4,
- MALFORMED_URL_EXCEPTION: 5,
- IO_EXCEPTION: 6,
- INVALID_ACTION: 7,
- JSON_EXCEPTION: 8,
- ERROR: 9
- };
-
-
-/**
- * Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
- * The native side can return:
- * Synchronous: PluginResult object as a JSON string
- * Asynchrounous: Empty string ""
- * If async, the native side will PhoneGap.callbackSuccess or PhoneGap.callbackError,
- * depending upon the result of the action.
- *
- * @param {Function} success The success callback
- * @param {Function} fail The fail callback
- * @param {String} service The name of the service to use
- * @param {String} action Action to be run in PhoneGap
- * @param {String[]} [args] Zero or more arguments to pass to the method
- */
-PhoneGap.exec = function(success, fail, service, action, args) {
- try {
- var callbackId = service + PhoneGap.callbackId++;
- if (success || fail) {
- PhoneGap.callbacks[callbackId] = {success:success, fail:fail};
- }
-
- // Note: Device returns string, but for some reason emulator returns object - so convert to string.
- var r = ""+PluginManager.exec(service, action, callbackId, this.stringify(args), true);
-
- // If a result was returned
- if (r.length > 0) {
- eval("var v="+r+";");
-
- // If status is OK, then return value back to caller
- if (v.status == PhoneGap.callbackStatus.OK) {
-
- // If there is a success callback, then call it now with returned value
- if (success) {
- try {
- success(v.message);
- }
- catch (e) {
- console.log("Error in success callback: "+callbackId+" = "+e);
- }
-
- // Clear callback if not expecting any more results
- if (!v.keepCallback) {
- delete PhoneGap.callbacks[callbackId];
- }
- }
- return v.message;
- }
-
- // If no result
- else if (v.status == PhoneGap.callbackStatus.NO_RESULT) {
-
- // Clear callback if not expecting any more results
- if (!v.keepCallback) {
- delete PhoneGap.callbacks[callbackId];
- }
- }
-
- // If error, then display error
- else {
- console.log("Error: Status="+r.status+" Message="+v.message);
-
- // If there is a fail callback, then call it now with returned value
- if (fail) {
- try {
- fail(v.message);
- }
- catch (e) {
- console.log("Error in error callback: "+callbackId+" = "+e);
- }
-
- // Clear callback if not expecting any more results
- if (!v.keepCallback) {
- delete PhoneGap.callbacks[callbackId];
- }
- }
- return null;
- }
- }
- } catch (e) {
- console.log("Error: "+e);
- }
-};
-
-/**
- * Called by native code when returning successful result from an action.
- *
- * @param callbackId
- * @param args
- */
-PhoneGap.callbackSuccess = function(callbackId, args) {
- if (PhoneGap.callbacks[callbackId]) {
-
- // If result is to be sent to callback
- if (args.status == PhoneGap.callbackStatus.OK) {
- try {
- if (PhoneGap.callbacks[callbackId].success) {
- PhoneGap.callbacks[callbackId].success(args.message);
- }
- }
- catch (e) {
- console.log("Error in success callback: "+callbackId+" = "+e);
- }
- }
-
- // Clear callback if not expecting any more results
- if (!args.keepCallback) {
- delete PhoneGap.callbacks[callbackId];
- }
- }
-};
-
-/**
- * Called by native code when returning error result from an action.
- *
- * @param callbackId
- * @param args
- */
-PhoneGap.callbackError = function(callbackId, args) {
- if (PhoneGap.callbacks[callbackId]) {
- try {
- if (PhoneGap.callbacks[callbackId].fail) {
- PhoneGap.callbacks[callbackId].fail(args.message);
- }
- }
- catch (e) {
- console.log("Error in error callback: "+callbackId+" = "+e);
- }
-
- // Clear callback if not expecting any more results
- if (!args.keepCallback) {
- delete PhoneGap.callbacks[callbackId];
- }
- }
-};
-
-
-/**
- * Internal function used to dispatch the request to PhoneGap. It processes the
- * command queue and executes the next command on the list. If one of the
- * arguments is a JavaScript object, it will be passed on the QueryString of the
- * url, which will be turned into a dictionary on the other end.
- * @private
- */
-// TODO: Is this used?
-PhoneGap.run_command = function() {
- if (!PhoneGap.available || !PhoneGap.queue.ready)
- return;
-
- PhoneGap.queue.ready = false;
-
- var args = PhoneGap.queue.commands.shift();
- if (PhoneGap.queue.commands.length == 0) {
- clearInterval(PhoneGap.queue.timer);
- PhoneGap.queue.timer = null;
- }
-
- var uri = [];
- var dict = null;
- for (var i = 1; i < args.length; i++) {
- var arg = args[i];
- if (arg == undefined || arg == null)
- arg = '';
- if (typeof(arg) == 'object')
- dict = arg;
- else
- uri.push(encodeURIComponent(arg));
- }
- var url = "gap://" + args[0] + "/" + uri.join("/");
- if (dict != null) {
- var query_args = [];
- for (var name in dict) {
- if (typeof(name) != 'string')
- continue;
- query_args.push(encodeURIComponent(name) + "=" + encodeURIComponent(dict[name]));
- }
- if (query_args.length > 0)
- url += "?" + query_args.join("&");
- }
- document.location = url;
-
-};
-
-/**
- * This is only for Android.
- *
- * Internal function that uses XHR to call into PhoneGap Java code and retrieve
- * any JavaScript code that needs to be run. This is used for callbacks from
- * Java to JavaScript.
- */
-PhoneGap.JSCallback = function() {
- var xmlhttp = new XMLHttpRequest();
-
- // Callback function when XMLHttpRequest is ready
- xmlhttp.onreadystatechange=function(){
- if(xmlhttp.readyState == 4){
-
- // If callback has JavaScript statement to execute
- if (xmlhttp.status == 200) {
-
- var msg = xmlhttp.responseText;
- setTimeout(function() {
- try {
- var t = eval(msg);
- }
- catch (e) {
- console.log("JSCallback Error: "+e);
- }
- }, 1);
- setTimeout(PhoneGap.JSCallback, 1);
- }
-
- // If callback ping (used to keep XHR request from timing out)
- else if (xmlhttp.status == 404) {
- setTimeout(PhoneGap.JSCallback, 10);
- }
-
- // If error, restart callback server
- else {
- console.log("JSCallback Error: Request failed.");
- CallbackServer.restartServer();
- setTimeout(PhoneGap.JSCallback, 100);
- }
- }
- }
-
- xmlhttp.open("GET", "http://127.0.0.1:"+CallbackServer.getPort()+"/" , true);
- xmlhttp.send();
-};
-
-/**
- * The polling period to use with JSCallbackPolling.
- * This can be changed by the application. The default is 50ms.
- */
-PhoneGap.JSCallbackPollingPeriod = 50;
-
-/**
- * This is only for Android.
- *
- * Internal function that uses polling to call into PhoneGap Java code and retrieve
- * any JavaScript code that needs to be run. This is used for callbacks from
- * Java to JavaScript.
- */
-PhoneGap.JSCallbackPolling = function() {
- var msg = CallbackServer.getJavascript();
- if (msg) {
- setTimeout(function() {
- try {
- var t = eval(""+msg);
- }
- catch (e) {
- console.log("JSCallbackPolling Error: "+e);
- }
- }, 1);
- setTimeout(PhoneGap.JSCallbackPolling, 1);
- }
- else {
- setTimeout(PhoneGap.JSCallbackPolling, PhoneGap.JSCallbackPollingPeriod);
- }
-};
-
-/**
- * Create a UUID
- *
- * @return
- */
-PhoneGap.createUUID = function() {
- return PhoneGap.UUIDcreatePart(4) + '-' +
- PhoneGap.UUIDcreatePart(2) + '-' +
- PhoneGap.UUIDcreatePart(2) + '-' +
- PhoneGap.UUIDcreatePart(2) + '-' +
- PhoneGap.UUIDcreatePart(6);
-};
-
-PhoneGap.UUIDcreatePart = function(length) {
- var uuidpart = "";
- for (var i=0; i frequency + 10 sec
- PhoneGap.exec(
- function(timeout) {
- if (timeout < (frequency + 10000)) {
- PhoneGap.exec(null, null, "Accelerometer", "setTimeout", [frequency + 10000]);
- }
- },
- function(e) { }, "Accelerometer", "getTimeout", []);
-
- // Start watch timer
- var id = PhoneGap.createUUID();
- navigator.accelerometer.timers[id] = setInterval(function() {
- PhoneGap.exec(successCallback, errorCallback, "Accelerometer", "getAcceleration", []);
- }, (frequency ? frequency : 1));
-
- return id;
-};
-
-/**
- * Clears the specified accelerometer watch.
- *
- * @param {String} id The id of the watch returned from #watchAcceleration.
- */
-Accelerometer.prototype.clearWatch = function(id) {
-
- // Stop javascript timer & remove from timer list
- if (id && navigator.accelerometer.timers[id] != undefined) {
- clearInterval(navigator.accelerometer.timers[id]);
- delete navigator.accelerometer.timers[id];
- }
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.accelerometer == "undefined") navigator.accelerometer = new Accelerometer();
-});
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class provides access to the device camera.
- *
- * @constructor
- */
-Camera = function() {
- this.successCallback = null;
- this.errorCallback = null;
- this.options = null;
-};
-
-/**
- * Format of image that returned from getPicture.
- *
- * Example: navigator.camera.getPicture(success, fail,
- * { quality: 80,
- * destinationType: Camera.DestinationType.DATA_URL,
- * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
- */
-Camera.DestinationType = {
- DATA_URL: 0, // Return base64 encoded string
- FILE_URI: 1 // Return file uri (content://media/external/images/media/2 for Android)
-};
-Camera.prototype.DestinationType = Camera.DestinationType;
-
-/**
- * Source to getPicture from.
- *
- * Example: navigator.camera.getPicture(success, fail,
- * { quality: 80,
- * destinationType: Camera.DestinationType.DATA_URL,
- * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
- */
-Camera.PictureSourceType = {
- PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
- CAMERA : 1, // Take picture from camera
- SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
-};
-Camera.prototype.PictureSourceType = Camera.PictureSourceType;
-
-/**
- * Gets a picture from source defined by "options.sourceType", and returns the
- * image as defined by the "options.destinationType" option.
-
- * The defaults are sourceType=CAMERA and destinationType=DATA_URL.
- *
- * @param {Function} successCallback
- * @param {Function} errorCallback
- * @param {Object} options
- */
-Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
-
- // successCallback required
- if (typeof successCallback != "function") {
- console.log("Camera Error: successCallback is not a function");
- return;
- }
-
- // errorCallback optional
- if (errorCallback && (typeof errorCallback != "function")) {
- console.log("Camera Error: errorCallback is not a function");
- return;
- }
-
- this.options = options;
- var quality = 80;
- if (options.quality) {
- quality = this.options.quality;
- }
- var destinationType = Camera.DestinationType.DATA_URL;
- if (this.options.destinationType) {
- destinationType = this.options.destinationType;
- }
- var sourceType = Camera.PictureSourceType.CAMERA;
- if (typeof this.options.sourceType == "number") {
- sourceType = this.options.sourceType;
- }
- PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType]);
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.camera == "undefined") navigator.camera = new Camera();
-});
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class provides access to device Compass data.
- * @constructor
- */
-function Compass() {
- /**
- * The last known Compass position.
- */
- this.lastHeading = null;
-
- /**
- * List of compass watch timers
- */
- this.timers = {};
-};
-
-Compass.ERROR_MSG = ["Not running", "Starting", "", "Failed to start"];
-
-/**
- * Asynchronously aquires the current heading.
- *
- * @param {Function} successCallback The function to call when the heading data is available
- * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
- * @param {PositionOptions} options The options for getting the heading data such as timeout. (OPTIONAL)
- */
-Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, options) {
-
- // successCallback required
- if (typeof successCallback != "function") {
- console.log("Compass Error: successCallback is not a function");
- return;
- }
-
- // errorCallback optional
- if (errorCallback && (typeof errorCallback != "function")) {
- console.log("Compass Error: errorCallback is not a function");
- return;
- }
-
- // Get heading
- PhoneGap.exec(successCallback, errorCallback, "Compass", "getHeading", []);
-};
-
-/**
- * Asynchronously aquires the heading repeatedly at a given interval.
- *
- * @param {Function} successCallback The function to call each time the heading data is available
- * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
- * @param {HeadingOptions} options The options for getting the heading data such as timeout and the frequency of the watch. (OPTIONAL)
- * @return String The watch id that must be passed to #clearWatch to stop watching.
- */
-Compass.prototype.watchHeading= function(successCallback, errorCallback, options) {
-
- // Default interval (100 msec)
- var frequency = (options != undefined) ? options.frequency : 100;
-
- // successCallback required
- if (typeof successCallback != "function") {
- console.log("Compass Error: successCallback is not a function");
- return;
- }
-
- // errorCallback optional
- if (errorCallback && (typeof errorCallback != "function")) {
- console.log("Compass Error: errorCallback is not a function");
- return;
- }
-
- // Make sure compass timeout > frequency + 10 sec
- PhoneGap.exec(
- function(timeout) {
- if (timeout < (frequency + 10000)) {
- PhoneGap.exec(null, null, "Compass", "setTimeout", [frequency + 10000]);
- }
- },
- function(e) { }, "Compass", "getTimeout", []);
-
- // Start watch timer to get headings
- var id = PhoneGap.createUUID();
- navigator.compass.timers[id] = setInterval(
- function() {
- PhoneGap.exec(successCallback, errorCallback, "Compass", "getHeading", []);
- }, (frequency ? frequency : 1));
-
- return id;
-};
-
-
-/**
- * Clears the specified heading watch.
- *
- * @param {String} id The ID of the watch returned from #watchHeading.
- */
-Compass.prototype.clearWatch = function(id) {
-
- // Stop javascript timer & remove from timer list
- if (id && navigator.compass.timers[id]) {
- clearInterval(navigator.compass.timers[id]);
- delete navigator.compass.timers[id];
- }
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.compass == "undefined") navigator.compass = new Compass();
-});
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
-* Contains information about a single contact.
-* @param {DOMString} id unique identifier
-* @param {DOMString} displayName
-* @param {ContactName} name
-* @param {DOMString} nickname
-* @param {ContactField[]} phoneNumbers array of phone numbers
-* @param {ContactField[]} emails array of email addresses
-* @param {ContactAddress[]} addresses array of addresses
-* @param {ContactField[]} ims instant messaging user ids
-* @param {ContactOrganization[]} organizations
-* @param {DOMString} published date contact was first created
-* @param {DOMString} updated date contact was last updated
-* @param {DOMString} birthday contact's birthday
-* @param (DOMString} anniversary contact's anniversary
-* @param {DOMString} gender contact's gender
-* @param {DOMString} note user notes about contact
-* @param {DOMString} preferredUsername
-* @param {ContactField[]} photos
-* @param {ContactField[]} tags
-* @param {ContactField[]} relationships
-* @param {ContactField[]} urls contact's web sites
-* @param {ContactAccounts[]} accounts contact's online accounts
-* @param {DOMString} utcOffset UTC time zone offset
-* @param {DOMString} connected
-*/
-var Contact = function(id, displayName, name, nickname, phoneNumbers, emails, addresses,
- ims, organizations, published, updated, birthday, anniversary, gender, note,
- preferredUsername, photos, tags, relationships, urls, accounts, utcOffset, connected) {
- this.id = id || null;
- this.displayName = displayName || null;
- this.name = name || null; // ContactName
- this.nickname = nickname || null;
- this.phoneNumbers = phoneNumbers || null; // ContactField[]
- this.emails = emails || null; // ContactField[]
- this.addresses = addresses || null; // ContactAddress[]
- this.ims = ims || null; // ContactField[]
- this.organizations = organizations || null; // ContactOrganization[]
- this.published = published || null;
- this.updated = updated || null;
- this.birthday = birthday || null;
- this.anniversary = anniversary || null;
- this.gender = gender || null;
- this.note = note || null;
- this.preferredUsername = preferredUsername || null;
- this.photos = photos || null; // ContactField[]
- this.tags = tags || null; // ContactField[]
- this.relationships = relationships || null; // ContactField[]
- this.urls = urls || null; // ContactField[]
- this.accounts = accounts || null; // ContactAccount[]
- this.utcOffset = utcOffset || null;
- this.connected = connected || null;
-};
-
-/**
-* Removes contact from device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.remove = function(successCB, errorCB) {
- if (this.id == null) {
- var errorObj = new ContactError();
- errorObj.code = ContactError.NOT_FOUND_ERROR;
- errorCB(errorObj);
- }
-
- PhoneGap.exec(successCB, errorCB, "Contacts", "remove", [this.id]);
-};
-
-/**
-* Creates a deep copy of this Contact.
-* With the contact ID set to null.
-* @return copy of this Contact
-*/
-Contact.prototype.clone = function() {
- var clonedContact = PhoneGap.clone(this);
- clonedContact.id = null;
- return clonedContact;
-};
-
-/**
-* Persists contact to device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.save = function(successCB, errorCB) {
-};
-
-/**
-* Contact name.
-* @param formatted
-* @param familyName
-* @param givenName
-* @param middle
-* @param prefix
-* @param suffix
-*/
-var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
- this.formatted = formatted || null;
- this.familyName = familyName || null;
- this.givenName = givenName || null;
- this.middleName = middle || null;
- this.honorificPrefix = prefix || null;
- this.honorificSuffix = suffix || null;
-};
-
-/**
-* Generic contact field.
-* @param type
-* @param value
-* @param primary
-*/
-var ContactField = function(type, value, primary) {
- this.type = type || null;
- this.value = value || null;
- this.primary = primary || null;
-};
-
-/**
-* Contact address.
-* @param formatted
-* @param streetAddress
-* @param locality
-* @param region
-* @param postalCode
-* @param country
-*/
-var ContactAddress = function(formatted, streetAddress, locality, region, postalCode, country) {
- this.formatted = formatted || null;
- this.streetAddress = streetAddress || null;
- this.locality = locality || null;
- this.region = region || null;
- this.postalCode = postalCode || null;
- this.country = country || null;
-};
-
-/**
-* Contact organization.
-* @param name
-* @param dept
-* @param title
-* @param startDate
-* @param endDate
-* @param location
-* @param desc
-*/
-var ContactOrganization = function(name, dept, title, startDate, endDate, location, desc) {
- this.name = name || null;
- this.department = dept || null;
- this.title = title || null;
- this.startDate = startDate || null;
- this.endDate = endDate || null;
- this.location = location || null;
- this.description = desc || null;
-};
-
-/**
-* Contact account.
-* @param domain
-* @param username
-* @param userid
-*/
-var ContactAccount = function(domain, username, userid) {
- this.domain = domain || null;
- this.username = username || null;
- this.userid = userid || null;
-}
-
-/**
-* Represents a group of Contacts.
-*/
-var Contacts = function() {
- this.inProgress = false;
- this.records = new Array();
-}
-/**
-* Returns an array of Contacts matching the search criteria.
-* @param fields that should be searched
-* @param successCB success callback
-* @param errorCB error callback
-* @param {ContactFindOptions} options that can be applied to contact searching
-* @return array of Contacts matching search criteria
-*/
-Contacts.prototype.find = function(fields, successCB, errorCB, options) {
- PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]);
-};
-
-/**
-* This function creates a new contact, but it does not persist the contact
-* to device storage. To persist the contact to device storage, invoke
-* contact.save().
-* @param properties an object who's properties will be examined to create a new Contact
-* @returns new Contact object
-*/
-Contacts.prototype.create = function(properties) {
- var contact = new Contact();
- for (i in properties) {
- if (contact[i]!='undefined') {
- contact[i]=properties[i];
- }
- }
- return contact;
-};
-
-/**
- * ContactFindOptions.
- * @param filter used to match contacts against
- * @param multiple boolean used to determine if more than one contact should be returned
- * @param limit maximum number of results to return from the contacts search
- * @param updatedSince return only contact records that have been updated on or after the given time
- */
-var ContactFindOptions = function(filter, multiple, limit, updatedSince) {
- this.filter = filter || '';
- this.multiple = multiple || false;
- this.limit = limit || 1;
- this.updatedSince = updatedSince || '';
-};
-
-/**
- * ContactError.
- * An error code assigned by an implementation when an error has occurred
- */
-var ContactError = function() {
- this.code=null;
-};
-
-/**
- * Error codes
- */
-ContactError.UNKNOWN_ERROR = 0;
-ContactError.INVALID_ARGUMENT_ERROR = 1;
-ContactError.NOT_FOUND_ERROR = 2;
-ContactError.TIMEOUT_ERROR = 3;
-ContactError.PENDING_OPERATION_ERROR = 4;
-ContactError.IO_ERROR = 5;
-ContactError.NOT_SUPPORTED_ERROR = 6;
-ContactError.PERMISSION_DENIED_ERROR = 20;
-
-/**
- * Add the contact interface into the browser.
- */
-PhoneGap.addConstructor(function() {
- if(typeof navigator.service == "undefined") navigator.service = new Object();
- if(typeof navigator.service.contacts == "undefined") navigator.service.contacts = new Contacts();
-});
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-// TODO: Needs to be commented
-
-var Crypto = function() {
-};
-
-Crypto.prototype.encrypt = function(seed, string, callback) {
- this.encryptWin = callback;
- PhoneGap.exec(null, null, "Crypto", "encrypt", [seed, string]);
-};
-
-Crypto.prototype.decrypt = function(seed, string, callback) {
- this.decryptWin = callback;
- PhoneGap.exec(null, null, "Crypto", "decrypt", [seed, string]);
-};
-
-Crypto.prototype.gotCryptedString = function(string) {
- this.encryptWin(string);
-};
-
-Crypto.prototype.getPlainString = function(string) {
- this.decryptWin(string);
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.Crypto == "undefined") navigator.Crypto = new Crypto();
-});
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
- * phone, etc.
- * @constructor
- */
-function Device() {
- this.available = PhoneGap.available;
- this.platform = null;
- this.version = null;
- this.name = null;
- this.uuid = null;
- this.phonegap = null;
-
- var me = this;
- this.getInfo(
- function(info) {
- me.available = true;
- me.platform = info.platform;
- me.version = info.version;
- me.uuid = info.uuid;
- me.phonegap = info.phonegap;
- PhoneGap.onPhoneGapInfoReady.fire();
- },
- function(e) {
- me.available = false;
- console.log("Error initializing PhoneGap: " + e);
- alert("Error initializing PhoneGap: "+e);
- });
-}
-
-/**
- * Get device info
- *
- * @param {Function} successCallback The function to call when the heading data is available
- * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
- */
-Device.prototype.getInfo = function(successCallback, errorCallback) {
-
- // successCallback required
- if (typeof successCallback != "function") {
- console.log("Device Error: successCallback is not a function");
- return;
- }
-
- // errorCallback optional
- if (errorCallback && (typeof errorCallback != "function")) {
- console.log("Device Error: errorCallback is not a function");
- return;
- }
-
- // Get info
- PhoneGap.exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
-};
-
-/*
- * This is only for Android.
- *
- * You must explicitly override the back button.
- */
-Device.prototype.overrideBackButton = function() {
- BackButton.override();
-}
-
-/*
- * This is only for Android.
- *
- * This resets the back button to the default behaviour
- */
-Device.prototype.resetBackButton = function() {
- BackButton.reset();
-}
-
-/*
- * This is only for Android.
- *
- * This terminates the activity!
- */
-Device.prototype.exitApp = function() {
- BackButton.exitApp();
-}
-
-PhoneGap.addConstructor(function() {
- navigator.device = window.device = new Device();
-});
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class provides generic read and write access to the mobile device file system.
- * They are not used to read files from a server.
- */
-
-/**
- * List of files
- */
-function FileList() {
- this.files = {};
-};
-
-/**
- * Describes a single file in a FileList
- */
-function File() {
- this.name = null;
- this.type = null;
- this.urn = null;
-};
-
-/**
- * Create an event object since we can't set target on DOM event.
- *
- * @param type
- * @param target
- *
- */
-File._createEvent = function(type, target) {
- // Can't create event object, since we can't set target (its readonly)
- //var evt = document.createEvent('Events');
- //evt.initEvent("onload", false, false);
- var evt = {"type": type};
- evt.target = target;
- return evt;
-};
-
-function FileError() {
- // File error codes
- // Found in DOMException
- this.NOT_FOUND_ERR = 8;
- this.SECURITY_ERR = 18;
- this.ABORT_ERR = 20;
-
- // Added by this specification
- this.NOT_READABLE_ERR = 24;
- this.ENCODING_ERR = 26;
-
- this.code = null;
-};
-
-//-----------------------------------------------------------------------------
-// File manager
-//-----------------------------------------------------------------------------
-
-function FileMgr() {
-};
-
-FileMgr.prototype.getFileBasePaths = function() {
-};
-
-FileMgr.prototype.testSaveLocationExists = function(successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "testSaveLocationExists", []);
-};
-
-FileMgr.prototype.testFileExists = function(fileName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "testFileExists", [fileName]);
-};
-
-FileMgr.prototype.testDirectoryExists = function(dirName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "testDirectoryExists", [dirName]);
-};
-
-FileMgr.prototype.createDirectory = function(dirName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "createDirectory", [dirName]);
-};
-
-FileMgr.prototype.deleteDirectory = function(dirName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "deleteDirectory", [dirName]);
-};
-
-FileMgr.prototype.deleteFile = function(fileName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "deleteFile", [fileName]);
-};
-
-FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "getFreeDiskSpace", []);
-};
-
-FileMgr.prototype.writeAsText = function(fileName, data, append, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "writeAsText", [fileName, data, append]);
-};
-
-FileMgr.prototype.readAsText = function(fileName, encoding, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "readAsText", [fileName, encoding]);
-};
-
-FileMgr.prototype.readAsDataURL = function(fileName, successCallback, errorCallback) {
- PhoneGap.exec(successCallback, errorCallback, "File", "readAsDataURL", [fileName]);
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.fileMgr == "undefined") navigator.fileMgr = new FileMgr();
-});
-
-//-----------------------------------------------------------------------------
-// File Reader
-//-----------------------------------------------------------------------------
-// TODO: All other FileMgr function operate on the SD card as root. However,
-// for FileReader & FileWriter the root is not SD card. Should this be changed?
-
-/**
- * This class reads the mobile device file system.
- *
- * For Android:
- * The root directory is the root of the file system.
- * To read from the SD card, the file name is "sdcard/my_file.txt"
- */
-function FileReader() {
- this.fileName = "";
-
- this.readyState = 0;
-
- // File data
- this.result = null;
-
- // Error
- this.error = null;
-
- // Event handlers
- this.onloadstart = null; // When the read starts.
- this.onprogress = null; // While reading (and decoding) file or fileBlob data, and reporting partial file data (progess.loaded/progress.total)
- this.onload = null; // When the read has successfully completed.
- this.onerror = null; // When the read has failed (see errors).
- this.onloadend = null; // When the request has completed (either in success or failure).
- this.onabort = null; // When the read has been aborted. For instance, by invoking the abort() method.
-};
-
-// States
-FileReader.EMPTY = 0;
-FileReader.LOADING = 1;
-FileReader.DONE = 2;
-
-/**
- * Abort reading file.
- */
-FileReader.prototype.abort = function() {
- this.readyState = FileReader.DONE;
-
- // If abort callback
- if (typeof this.onabort == "function") {
- var evt = File._createEvent("abort", this);
- this.onabort(evt);
- }
-
- // TODO: Anything else to do? Maybe sent to native?
-};
-
-/**
- * Read text file.
- *
- * @param file The name of the file
- * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
- */
-FileReader.prototype.readAsText = function(file, encoding) {
- this.fileName = file;
-
- // LOADING state
- this.readyState = FileReader.LOADING;
-
- // If loadstart callback
- if (typeof this.onloadstart == "function") {
- var evt = File._createEvent("loadstart", this);
- this.onloadstart(evt);
- }
-
- // Default encoding is UTF-8
- var enc = encoding ? encoding : "UTF-8";
-
- var me = this;
-
- // Read file
- navigator.fileMgr.readAsText(file, enc,
-
- // Success callback
- function(r) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileReader.DONE) {
- return;
- }
-
- // Save result
- me.result = r;
-
- // DONE state
- me.readyState = FileReader.DONE;
-
- // If onload callback
- if (typeof me.onload == "function") {
- var evt = File._createEvent("load", me);
- me.onload(evt);
- }
-
- // If onloadend callback
- if (typeof me.onloadend == "function") {
- var evt = File._createEvent("loadend", me);
- me.onloadend(evt);
- }
- },
-
- // Error callback
- function(e) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileReader.DONE) {
- return;
- }
-
- // Save error
- me.error = e;
-
- // DONE state
- me.readyState = FileReader.DONE;
-
- // If onerror callback
- if (typeof me.onerror == "function") {
- var evt = File._createEvent("error", me);
- me.onerror(evt);
- }
-
- // If onloadend callback
- if (typeof me.onloadend == "function") {
- var evt = File._createEvent("loadend", me);
- me.onloadend(evt);
- }
- }
- );
-};
-
-
-/**
- * Read file and return data as a base64 encoded data url.
- * A data url is of the form:
- * data:[][;base64],
- *
- * @param file The name of the file
- */
-FileReader.prototype.readAsDataURL = function(file) {
- this.fileName = file;
-
- // LOADING state
- this.readyState = FileReader.LOADING;
-
- // If loadstart callback
- if (typeof this.onloadstart == "function") {
- var evt = File._createEvent("loadstart", this);
- this.onloadstart(evt);
- }
-
- var me = this;
-
- // Read file
- navigator.fileMgr.readAsDataURL(file,
-
- // Success callback
- function(r) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileReader.DONE) {
- return;
- }
-
- // Save result
- me.result = r;
-
- // DONE state
- me.readyState = FileReader.DONE;
-
- // If onload callback
- if (typeof me.onload == "function") {
- var evt = File._createEvent("load", me);
- me.onload(evt);
- }
-
- // If onloadend callback
- if (typeof me.onloadend == "function") {
- var evt = File._createEvent("loadend", me);
- me.onloadend(evt);
- }
- },
-
- // Error callback
- function(e) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileReader.DONE) {
- return;
- }
-
- // Save error
- me.error = e;
-
- // DONE state
- me.readyState = FileReader.DONE;
-
- // If onerror callback
- if (typeof me.onerror == "function") {
- var evt = File._createEvent("error", me);
- me.onerror(evt);
- }
-
- // If onloadend callback
- if (typeof me.onloadend == "function") {
- var evt = File._createEvent("loadend", me);
- me.onloadend(evt);
- }
- }
- );
-};
-
-/**
- * Read file and return data as a binary data.
- *
- * @param file The name of the file
- */
-FileReader.prototype.readAsBinaryString = function(file) {
- // TODO - Can't return binary data to browser.
- this.fileName = file;
-};
-
-//-----------------------------------------------------------------------------
-// File Writer
-//-----------------------------------------------------------------------------
-
-/**
- * This class writes to the mobile device file system.
- *
- * For Android:
- * The root directory is the root of the file system.
- * To write to the SD card, the file name is "sdcard/my_file.txt"
- */
-function FileWriter() {
- this.fileName = "";
-
- this.readyState = 0; // EMPTY
-
- this.result = null;
-
- // Error
- this.error = null;
-
- // Event handlers
- this.onwritestart = null; // When writing starts
- this.onprogress = null; // While writing the file, and reporting partial file data
- this.onwrite = null; // When the write has successfully completed.
- this.onwriteend = null; // When the request has completed (either in success or failure).
- this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
- this.onerror = null; // When the write has failed (see errors).
-};
-
-// States
-FileWriter.INIT = 0;
-FileWriter.WRITING = 1;
-FileWriter.DONE = 2;
-
-/**
- * Abort writing file.
- */
-FileWriter.prototype.abort = function() {
- this.readyState = FileWriter.DONE;
-
- // If abort callback
- if (typeof this.onabort == "function") {
- var evt = File._createEvent("abort", this);
- this.onabort(evt);
- }
-
- // TODO: Anything else to do? Maybe sent to native?
-};
-
-FileWriter.prototype.writeAsText = function(file, text, bAppend) {
- if (bAppend != true) {
- bAppend = false; // for null values
- }
-
- this.fileName = file;
-
- // WRITING state
- this.readyState = FileWriter.WRITING;
-
- var me = this;
-
- // Write file
- navigator.fileMgr.writeAsText(file, text, bAppend,
-
- // Success callback
- function(r) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileWriter.DONE) {
- return;
- }
-
- // Save result
- me.result = r;
-
- // DONE state
- me.readyState = FileWriter.DONE;
-
- // If onwrite callback
- if (typeof me.onwrite == "function") {
- var evt = File._createEvent("write", me);
- me.onwrite(evt);
- }
-
- // If onwriteend callback
- if (typeof me.onwriteend == "function") {
- var evt = File._createEvent("writeend", me);
- me.onwriteend(evt);
- }
- },
-
- // Error callback
- function(e) {
-
- // If DONE (cancelled), then don't do anything
- if (me.readyState == FileWriter.DONE) {
- return;
- }
-
- // Save error
- me.error = e;
-
- // DONE state
- me.readyState = FileWriter.DONE;
-
- // If onerror callback
- if (typeof me.onerror == "function") {
- var evt = File._createEvent("error", me);
- me.onerror(evt);
- }
-
- // If onwriteend callback
- if (typeof me.onwriteend == "function") {
- var evt = File._createEvent("writeend", me);
- me.onwriteend(evt);
- }
- }
- );
-
-};
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class provides access to device GPS data.
- * @constructor
- */
-function Geolocation() {
-
- // The last known GPS position.
- this.lastPosition = null;
-
- // Geolocation listeners
- this.listeners = {};
-};
-
-/**
- * Position error object
- *
- * @param code
- * @param message
- */
-function PositionError(code, message) {
- this.code = code;
- this.message = message;
-};
-
-PositionError.PERMISSION_DENIED = 1;
-PositionError.POSITION_UNAVAILABLE = 2;
-PositionError.TIMEOUT = 3;
-
-/**
- * Asynchronously aquires the current position.
- *
- * @param {Function} successCallback The function to call when the position data is available
- * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL)
- * @param {PositionOptions} options The options for getting the position data. (OPTIONAL)
- */
-Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) {
- if (navigator._geo.listeners["global"]) {
- console.log("Geolocation Error: Still waiting for previous getCurrentPosition() request.");
- try {
- errorCallback(new PositionError(PositionError.TIMEOUT, "Geolocation Error: Still waiting for previous getCurrentPosition() request."));
- } catch (e) {
- }
- return;
- }
- var maximumAge = 10000;
- var enableHighAccuracy = false;
- var timeout = 10000;
- if (typeof options != "undefined") {
- if (typeof options.maximumAge != "undefined") {
- maximumAge = options.maximumAge;
- }
- if (typeof options.enableHighAccuracy != "undefined") {
- enableHighAccuracy = options.enableHighAccuracy;
- }
- if (typeof options.timeout != "undefined") {
- timeout = options.timeout;
- }
- }
- navigator._geo.listeners["global"] = {"success" : successCallback, "fail" : errorCallback };
- PhoneGap.exec(null, null, "Geolocation", "getCurrentLocation", [enableHighAccuracy, timeout, maximumAge]);
-}
-
-/**
- * Asynchronously watches the geolocation for changes to geolocation. When a change occurs,
- * the successCallback is called with the new location.
- *
- * @param {Function} successCallback The function to call each time the location data is available
- * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL)
- * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL)
- * @return String The watch id that must be passed to #clearWatch to stop watching.
- */
-Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) {
- var maximumAge = 10000;
- var enableHighAccuracy = false;
- var timeout = 10000;
- if (typeof options != "undefined") {
- if (typeof options.frequency != "undefined") {
- maximumAge = options.frequency;
- }
- if (typeof options.maximumAge != "undefined") {
- maximumAge = options.maximumAge;
- }
- if (typeof options.enableHighAccuracy != "undefined") {
- enableHighAccuracy = options.enableHighAccuracy;
- }
- if (typeof options.timeout != "undefined") {
- timeout = options.timeout;
- }
- }
- var id = PhoneGap.createUUID();
- navigator._geo.listeners[id] = {"success" : successCallback, "fail" : errorCallback };
- PhoneGap.exec(null, null, "Geolocation", "start", [id, enableHighAccuracy, timeout, maximumAge]);
- return id;
-};
-
-/*
- * Native callback when watch position has a new position.
- * PRIVATE METHOD
- *
- * @param {String} id
- * @param {Number} lat
- * @param {Number} lng
- * @param {Number} alt
- * @param {Number} altacc
- * @param {Number} head
- * @param {Number} vel
- * @param {Number} stamp
- */
-Geolocation.prototype.success = function(id, lat, lng, alt, altacc, head, vel, stamp) {
- var coords = new Coordinates(lat, lng, alt, altacc, head, vel);
- var loc = new Position(coords, stamp);
- try {
- if (lat == "undefined" || lng == "undefined") {
- navigator._geo.listeners[id].fail(new PositionError(PositionError.POSITION_UNAVAILABLE, "Lat/Lng are undefined."));
- }
- else {
- navigator._geo.lastPosition = loc;
- navigator._geo.listeners[id].success(loc);
- }
- }
- catch (e) {
- console.log("Geolocation Error: Error calling success callback function.");
- }
-
- if (id == "global") {
- delete navigator._geo.listeners["global"];
- }
-};
-
-/**
- * Native callback when watch position has an error.
- * PRIVATE METHOD
- *
- * @param {String} id The ID of the watch
- * @param {Number} code The error code
- * @param {String} msg The error message
- */
-Geolocation.prototype.fail = function(id, code, msg) {
- try {
- navigator._geo.listeners[id].fail(new PositionError(code, msg));
- }
- catch (e) {
- console.log("Geolocation Error: Error calling error callback function.");
- }
-};
-
-/**
- * Clears the specified heading watch.
- *
- * @param {String} id The ID of the watch returned from #watchPosition
- */
-Geolocation.prototype.clearWatch = function(id) {
- PhoneGap.exec(null, null, "Geolocation", "stop", [id]);
- delete navigator._geo.listeners[id];
-};
-
-/**
- * Force the PhoneGap geolocation to be used instead of built-in.
- */
-Geolocation.usingPhoneGap = false;
-Geolocation.usePhoneGap = function() {
- if (Geolocation.usingPhoneGap) {
- return;
- }
- Geolocation.usingPhoneGap = true;
-
- // Set built-in geolocation methods to our own implementations
- // (Cannot replace entire geolocation, but can replace individual methods)
- navigator.geolocation.setLocation = navigator._geo.setLocation;
- navigator.geolocation.getCurrentPosition = navigator._geo.getCurrentPosition;
- navigator.geolocation.watchPosition = navigator._geo.watchPosition;
- navigator.geolocation.clearWatch = navigator._geo.clearWatch;
- navigator.geolocation.start = navigator._geo.start;
- navigator.geolocation.stop = navigator._geo.stop;
-};
-
-PhoneGap.addConstructor(function() {
- navigator._geo = new Geolocation();
-
- // No native geolocation object for Android 1.x, so use PhoneGap geolocation
- if (typeof navigator.geolocation == 'undefined') {
- navigator.geolocation = navigator._geo;
- Geolocation.usingPhoneGap = true;
- }
-});
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-function KeyEvent()
-{
-}
-
-KeyEvent.prototype.backTrigger = function()
-{
- var e = document.createEvent('Events');
- e.initEvent('backKeyDown');
- document.dispatchEvent(e);
-}
-
-if (document.keyEvent == null || typeof document.keyEvent == 'undefined')
-{
- window.keyEvent = document.keyEvent = new KeyEvent();
-}
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * List of media objects.
- * PRIVATE
- */
-PhoneGap.mediaObjects = {};
-
-/**
- * Object that receives native callbacks.
- * PRIVATE
- */
-PhoneGap.Media = function() {};
-
-/**
- * Get the media object.
- * PRIVATE
- *
- * @param id The media object id (string)
- */
-PhoneGap.Media.getMediaObject = function(id) {
- return PhoneGap.mediaObjects[id];
-};
-
-/**
- * Audio has status update.
- * PRIVATE
- *
- * @param id The media object id (string)
- * @param status The status code (int)
- * @param msg The status message (string)
- */
-PhoneGap.Media.onStatus = function(id, msg, value) {
- var media = PhoneGap.mediaObjects[id];
-
- // If state update
- if (msg == Media.MEDIA_STATE) {
- if (value == Media.MEDIA_STOPPED) {
- if (media.successCallback) {
- media.successCallback();
- }
- }
- if (media.statusCallback) {
- media.statusCallback(value);
- }
- }
- else if (msg == Media.MEDIA_DURATION) {
- media._duration = value;
- }
- else if (msg == Media.MEDIA_ERROR) {
- if (media.errorCallback) {
- media.errorCallback(value);
- }
- }
-};
-
-/**
- * This class provides access to the device media, interfaces to both sound and video
- *
- * @param src The file name or url to play
- * @param successCallback The callback to be called when the file is done playing or recording.
- * successCallback() - OPTIONAL
- * @param errorCallback The callback to be called if there is an error.
- * errorCallback(int errorCode) - OPTIONAL
- * @param statusCallback The callback to be called when media status has changed.
- * statusCallback(int statusCode) - OPTIONAL
- * @param positionCallback The callback to be called when media position has changed.
- * positionCallback(long position) - OPTIONAL
- */
-Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
-
- // successCallback optional
- if (successCallback && (typeof successCallback != "function")) {
- console.log("Media Error: successCallback is not a function");
- return;
- }
-
- // errorCallback optional
- if (errorCallback && (typeof errorCallback != "function")) {
- console.log("Media Error: errorCallback is not a function");
- return;
- }
-
- // statusCallback optional
- if (statusCallback && (typeof statusCallback != "function")) {
- console.log("Media Error: statusCallback is not a function");
- return;
- }
-
- // statusCallback optional
- if (positionCallback && (typeof positionCallback != "function")) {
- console.log("Media Error: positionCallback is not a function");
- return;
- }
-
- this.id = PhoneGap.createUUID();
- PhoneGap.mediaObjects[this.id] = this;
- this.src = src;
- this.successCallback = successCallback;
- this.errorCallback = errorCallback;
- this.statusCallback = statusCallback;
- this.positionCallback = positionCallback;
- this._duration = -1;
- this._position = -1;
-};
-
-// Media messages
-Media.MEDIA_STATE = 1;
-Media.MEDIA_DURATION = 2;
-Media.MEDIA_ERROR = 9;
-
-// Media states
-Media.MEDIA_NONE = 0;
-Media.MEDIA_STARTING = 1;
-Media.MEDIA_RUNNING = 2;
-Media.MEDIA_PAUSED = 3;
-Media.MEDIA_STOPPED = 4;
-Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
-
-// TODO: Will MediaError be used?
-/**
- * This class contains information about any Media errors.
- * @constructor
- */
-function MediaError() {
- this.code = null,
- this.message = "";
-};
-
-MediaError.MEDIA_ERR_ABORTED = 1;
-MediaError.MEDIA_ERR_NETWORK = 2;
-MediaError.MEDIA_ERR_DECODE = 3;
-MediaError.MEDIA_ERR_NONE_SUPPORTED = 4;
-
-/**
- * Start or resume playing audio file.
- */
-Media.prototype.play = function() {
- PhoneGap.exec(null, null, "Media", "startPlayingAudio", [this.id, this.src]);
-};
-
-/**
- * Stop playing audio file.
- */
-Media.prototype.stop = function() {
- return PhoneGap.exec(null, null, "Media", "stopPlayingAudio", [this.id]);
-};
-
-/**
- * Pause playing audio file.
- */
-Media.prototype.pause = function() {
- PhoneGap.exec(null, null, "Media", "pausePlayingAudio", [this.id]);
-};
-
-/**
- * Get duration of an audio file.
- * The duration is only set for audio that is playing, paused or stopped.
- *
- * @return duration or -1 if not known.
- */
-Media.prototype.getDuration = function() {
- return this._duration;
-};
-
-/**
- * Get position of audio.
- *
- * @return
- */
-Media.prototype.getCurrentPosition = function(success, fail) {
- PhoneGap.exec(success, fail, "Media", "getCurrentPositionAudio", [this.id]);
-};
-
-/**
- * Start recording audio file.
- */
-Media.prototype.startRecord = function() {
- PhoneGap.exec(null, null, "Media", "startRecordingAudio", [this.id, this.src]);
-};
-
-/**
- * Stop recording audio file.
- */
-Media.prototype.stopRecord = function() {
- PhoneGap.exec(null, null, "Media", "stopRecordingAudio", [this.id]);
-};
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class contains information about any NetworkStatus.
- * @constructor
- */
-function NetworkStatus() {
- //this.code = null;
- //this.message = "";
-};
-
-NetworkStatus.NOT_REACHABLE = 0;
-NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
-NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
-
-/**
- * This class provides access to device Network data (reachability).
- * @constructor
- */
-function Network() {
- /**
- * The last known Network status.
- * { hostName: string, ipAddress: string,
- remoteHostStatus: int(0/1/2), internetConnectionStatus: int(0/1/2), localWiFiConnectionStatus: int (0/2) }
- */
- this.lastReachability = null;
-};
-
-/**
- * Called by the geolocation framework when the reachability status has changed.
- * @param {Reachibility} reachability The current reachability status.
- */
-// TODO: Callback from native code not implemented for Android
-Network.prototype.updateReachability = function(reachability) {
- this.lastReachability = reachability;
-};
-
-/**
- * Determine if a URI is reachable over the network.
-
- * @param {Object} uri
- * @param {Function} callback
- * @param {Object} options (isIpAddress:boolean)
- */
-Network.prototype.isReachable = function(uri, callback, options) {
- var isIpAddress = false;
- if (options && options.isIpAddress) {
- isIpAddress = options.isIpAddress;
- }
- PhoneGap.exec(callback, null, "Network Status", "isReachable", [uri, isIpAddress]);
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.network == "undefined") navigator.network = new Network();
-});
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class provides access to notifications on the device.
- */
-function Notification() {
-}
-
-/**
- * Open a native alert dialog, with a customizable title and button text.
- *
- * @param {String} message Message to print in the body of the alert
- * @param {Function} completeCallback The callback that is called when user clicks on a button.
- * @param {String} title Title of the alert dialog (default: Alert)
- * @param {String} buttonLabel Label of the close button (default: OK)
- */
-Notification.prototype.alert = function(message, completeCallback, title, buttonLabel) {
- var _title = (title || "Alert");
- var _buttonLabel = (buttonLabel || "OK");
- PhoneGap.exec(completeCallback, null, "Notification", "alert", [message,_title,_buttonLabel]);
-};
-
-/**
- * Open a native confirm dialog, with a customizable title and button text.
- * The result that the user selects is returned to the result callback.
- *
- * @param {String} message Message to print in the body of the alert
- * @param {Function} resultCallback The callback that is called when user clicks on a button.
- * @param {String} title Title of the alert dialog (default: Confirm)
- * @param {String} buttonLabels Comma separated list of the labels of the buttons (default: 'OK,Cancel')
- */
-Notification.prototype.confirm = function(message, resultCallback, title, buttonLabels) {
- var _title = (title || "Confirm");
- var _buttonLabels = (buttonLabels || "OK,Cancel");
- PhoneGap.exec(resultCallback, null, "Notification", "confirm", [message,_title,_buttonLabels]);
-};
-
-/**
- * Start spinning the activity indicator on the statusbar
- */
-Notification.prototype.activityStart = function() {
- PhoneGap.exec(null, null, "Notification", "activityStart", ["Busy","Please wait..."]);
-};
-
-/**
- * Stop spinning the activity indicator on the statusbar, if it's currently spinning
- */
-Notification.prototype.activityStop = function() {
- PhoneGap.exec(null, null, "Notification", "activityStop", []);
-};
-
-/**
- * Display a progress dialog with progress bar that goes from 0 to 100.
- *
- * @param {String} title Title of the progress dialog.
- * @param {String} message Message to display in the dialog.
- */
-Notification.prototype.progressStart = function(title, message) {
- PhoneGap.exec(null, null, "Notification", "progressStart", [title, message]);
-};
-
-/**
- * Set the progress dialog value.
- *
- * @param {Number} value 0-100
- */
-Notification.prototype.progressValue = function(value) {
- PhoneGap.exec(null, null, "Notification", "progressValue", [value]);
-};
-
-/**
- * Close the progress dialog.
- */
-Notification.prototype.progressStop = function() {
- PhoneGap.exec(null, null, "Notification", "progressStop", []);
-};
-
-/**
- * Causes the device to blink a status LED.
- *
- * @param {Integer} count The number of blinks.
- * @param {String} colour The colour of the light.
- */
-Notification.prototype.blink = function(count, colour) {
- // NOT IMPLEMENTED
-};
-
-/**
- * Causes the device to vibrate.
- *
- * @param {Integer} mills The number of milliseconds to vibrate for.
- */
-Notification.prototype.vibrate = function(mills) {
- PhoneGap.exec(null, null, "Notification", "vibrate", [mills]);
-};
-
-/**
- * Causes the device to beep.
- * On Android, the default notification ringtone is played "count" times.
- *
- * @param {Integer} count The number of beeps.
- */
-Notification.prototype.beep = function(count) {
- PhoneGap.exec(null, null, "Notification", "beep", [count]);
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.notification == "undefined") navigator.notification = new Notification();
-});
-
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/**
- * This class contains position information.
- * @param {Object} lat
- * @param {Object} lng
- * @param {Object} acc
- * @param {Object} alt
- * @param {Object} altacc
- * @param {Object} head
- * @param {Object} vel
- * @constructor
- */
-function Position(coords, timestamp) {
- this.coords = coords;
- this.timestamp = new Date().getTime();
-}
-
-function Coordinates(lat, lng, alt, acc, head, vel, altacc) {
- /**
- * The latitude of the position.
- */
- this.latitude = lat;
- /**
- * The longitude of the position,
- */
- this.longitude = lng;
- /**
- * The accuracy of the position.
- */
- this.accuracy = acc;
- /**
- * The altitude of the position.
- */
- this.altitude = alt;
- /**
- * The direction the device is moving at the position.
- */
- this.heading = head;
- /**
- * The velocity with which the device is moving at the position.
- */
- this.speed = vel;
- /**
- * The altitude accuracy of the position.
- */
- this.altitudeAccuracy = (altacc != 'undefined') ? altacc : null;
-}
-
-/**
- * This class specifies the options for requesting position data.
- * @constructor
- */
-function PositionOptions() {
- /**
- * Specifies the desired position accuracy.
- */
- this.enableHighAccuracy = true;
- /**
- * The timeout after which if position data cannot be obtained the errorCallback
- * is called.
- */
- this.timeout = 10000;
-}
-
-/**
- * This class contains information about any GSP errors.
- * @constructor
- */
-function PositionError() {
- this.code = null;
- this.message = "";
-}
-
-PositionError.UNKNOWN_ERROR = 0;
-PositionError.PERMISSION_DENIED = 1;
-PositionError.POSITION_UNAVAILABLE = 2;
-PositionError.TIMEOUT = 3;
-/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-PhoneGap.addConstructor(function() {
- if (typeof navigator.splashScreen == "undefined") {
- navigator.splashScreen = SplashScreen; // SplashScreen object come from native side through addJavaScriptInterface
- }
-});/*
- * PhoneGap is available under *either* the terms of the modified BSD license *or* the
- * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
- *
- * Copyright (c) 2005-2010, Nitobi Software Inc.
- * Copyright (c) 2010, IBM Corporation
- */
-
-/*
- * This is purely for the Android 1.5/1.6 HTML 5 Storage
- * I was hoping that Android 2.0 would deprecate this, but given the fact that
- * most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
- */
-
-/**
- * Storage object that is called by native code when performing queries.
- * PRIVATE METHOD
- */
-var DroidDB = function() {
- this.queryQueue = {};
-};
-
-/**
- * Callback from native code when result from a query is available.
- * PRIVATE METHOD
- *
- * @param rawdata JSON string of the row data
- * @param id Query id
- */
-DroidDB.prototype.addResult = function(rawdata, id) {
- try {
- eval("var data = " + rawdata + ";");
- var query = this.queryQueue[id];
- query.resultSet.push(data);
- } catch (e) {
- console.log("DroidDB.addResult(): Error="+e);
- }
-};
-
-/**
- * Callback from native code when query is complete.
- * PRIVATE METHOD
- *
- * @param id Query id
- */
-DroidDB.prototype.completeQuery = function(id) {
- var query = this.queryQueue[id];
- if (query) {
- try {
- delete this.queryQueue[id];
-
- // Get transaction
- var tx = query.tx;
-
- // If transaction hasn't failed
- // Note: We ignore all query results if previous query
- // in the same transaction failed.
- if (tx && tx.queryList[id]) {
-
- // Save query results
- var r = new DroidDB_Result();
- r.rows.resultSet = query.resultSet;
- r.rows.length = query.resultSet.length;
- try {
- if (typeof query.successCallback == 'function') {
- query.successCallback(query.tx, r);
- }
- } catch (ex) {
- console.log("executeSql error calling user success callback: "+ex);
- }
-
- tx.queryComplete(id);
- }
- } catch (e) {
- console.log("executeSql error: "+e);
- }
- }
-};
-
-/**
- * Callback from native code when query fails
- * PRIVATE METHOD
- *
- * @param reason Error message
- * @param id Query id
- */
-DroidDB.prototype.fail = function(reason, id) {
- var query = this.queryQueue[id];
- if (query) {
- try {
- delete this.queryQueue[id];
-
- // Get transaction
- var tx = query.tx;
-
- // If transaction hasn't failed
- // Note: We ignore all query results if previous query
- // in the same transaction failed.
- if (tx && tx.queryList[id]) {
- tx.queryList = {};
-
- try {
- if (typeof query.errorCallback == 'function') {
- query.errorCallback(query.tx, reason);
- }
- } catch (ex) {
- console.log("executeSql error calling user error callback: "+ex);
- }
-
- tx.queryFailed(id, reason);
- }
-
- } catch (e) {
- console.log("executeSql error: "+e);
- }
- }
-};
-
-var DatabaseShell = function() {
-};
-
-/**
- * Start a transaction.
- * Does not support rollback in event of failure.
- *
- * @param process {Function} The transaction function
- * @param successCallback {Function}
- * @param errorCallback {Function}
- */
-DatabaseShell.prototype.transaction = function(process, successCallback, errorCallback) {
- var tx = new DroidDB_Tx();
- tx.successCallback = successCallback;
- tx.errorCallback = errorCallback;
- try {
- process(tx);
- } catch (e) {
- console.log("Transaction error: "+e);
- if (tx.errorCallback) {
- try {
- tx.errorCallback(e);
- } catch (ex) {
- console.log("Transaction error calling user error callback: "+e);
- }
- }
- }
-};
-
-/**
- * Transaction object
- * PRIVATE METHOD
- */
-var DroidDB_Tx = function() {
-
- // Set the id of the transaction
- this.id = PhoneGap.createUUID();
-
- // Callbacks
- this.successCallback = null;
- this.errorCallback = null;
-
- // Query list
- this.queryList = {};
-};
-
-/**
- * Mark query in transaction as complete.
- * If all queries are complete, call the user's transaction success callback.
- *
- * @param id Query id
- */
-DroidDB_Tx.prototype.queryComplete = function(id) {
- delete this.queryList[id];
-
- // If no more outstanding queries, then fire transaction success
- if (this.successCallback) {
- var count = 0;
- for (var i in this.queryList) {
- count++;
- }
- if (count == 0) {
- try {
- this.successCallback();
- } catch(e) {
- console.log("Transaction error calling user success callback: " + e);
- }
- }
- }
-};
-
-/**
- * Mark query in transaction as failed.
- *
- * @param id Query id
- * @param reason Error message
- */
-DroidDB_Tx.prototype.queryFailed = function(id, reason) {
-
- // The sql queries in this transaction have already been run, since
- // we really don't have a real transaction implemented in native code.
- // However, the user callbacks for the remaining sql queries in transaction
- // will not be called.
- this.queryList = {};
-
- if (this.errorCallback) {
- try {
- this.errorCallback(reason);
- } catch(e) {
- console.log("Transaction error calling user error callback: " + e);
- }
- }
-};
-
-/**
- * SQL query object
- * PRIVATE METHOD
- *
- * @param tx The transaction object that this query belongs to
- */
-var DroidDB_Query = function(tx) {
-
- // Set the id of the query
- this.id = PhoneGap.createUUID();
-
- // Add this query to the queue
- droiddb.queryQueue[this.id] = this;
-
- // Init result
- this.resultSet = [];
-
- // Set transaction that this query belongs to
- this.tx = tx;
-
- // Add this query to transaction list
- this.tx.queryList[this.id] = this;
-
- // Callbacks
- this.successCallback = null;
- this.errorCallback = null;
-
-}
-
-/**
- * Execute SQL statement
- *
- * @param sql SQL statement to execute
- * @param params Statement parameters
- * @param successCallback Success callback
- * @param errorCallback Error callback
- */
-DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) {
-
- // Init params array
- if (typeof params == 'undefined') {
- params = [];
- }
-
- // Create query and add to queue
- var query = new DroidDB_Query(this);
- droiddb.queryQueue[query.id] = query;
-
- // Save callbacks
- query.successCallback = successCallback;
- query.errorCallback = errorCallback;
-
- // Call native code
- PhoneGap.exec(null, null, "Storage", "executeSql", [sql, params, query.id]);
-};
-
-/**
- * SQL result set that is returned to user.
- * PRIVATE METHOD
- */
-DroidDB_Result = function() {
- this.rows = new DroidDB_Rows();
-};
-
-/**
- * SQL result set object
- * PRIVATE METHOD
- */
-DroidDB_Rows = function() {
- this.resultSet = []; // results array
- this.length = 0; // number of rows
-};
-
-/**
- * Get item from SQL result set
- *
- * @param row The row number to return
- * @return The row object
- */
-DroidDB_Rows.prototype.item = function(row) {
- return this.resultSet[row];
-};
-
-/**
- * Open database
- *
- * @param name Database name
- * @param version Database version
- * @param display_name Database display name
- * @param size Database size in bytes
- * @return Database object
- */
-DroidDB_openDatabase = function(name, version, display_name, size) {
- PhoneGap.exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
- var db = new DatabaseShell();
- return db;
-};
-
-PhoneGap.addConstructor(function() {
- if (typeof window.openDatabase == "undefined") {
- navigator.openDatabase = window.openDatabase = DroidDB_openDatabase;
- window.droiddb = new DroidDB();
- }
-});
diff --git a/framework/res/xml/plugins.xml b/framework/res/xml/plugins.xml
index 3d8d48d8..dcc229ae 100644
--- a/framework/res/xml/plugins.xml
+++ b/framework/res/xml/plugins.xml
@@ -16,4 +16,5 @@
+
\ No newline at end of file
diff --git a/framework/src/com/phonegap/AudioHandler.java b/framework/src/com/phonegap/AudioHandler.java
index 9673b076..e7f77d90 100755
--- a/framework/src/com/phonegap/AudioHandler.java
+++ b/framework/src/com/phonegap/AudioHandler.java
@@ -7,17 +7,15 @@
*/
package com.phonegap;
-import java.util.HashMap;
-import java.util.Map.Entry;
-
+import android.content.Context;
+import android.media.AudioManager;
+import com.phonegap.api.Plugin;
+import com.phonegap.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
-import com.phonegap.api.Plugin;
-import com.phonegap.api.PluginResult;
-
-import android.content.Context;
-import android.media.AudioManager;
+import java.util.HashMap;
+import java.util.Map.Entry;
/**
* This class called by PhonegapActivity to play and record audio.
@@ -71,8 +69,13 @@ public class AudioHandler extends Plugin {
}
else if (action.equals("stopPlayingAudio")) {
this.stopPlayingAudio(args.getString(0));
- }
- else if (action.equals("getCurrentPositionAudio")) {
+ } 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);
}
@@ -295,5 +298,20 @@ public class AudioHandler extends Plugin {
else {
return -1;
}
- }
+ }
+
+ /**
+ * Set the volume for an audio device
+ *
+ * @param id The id of the audio player
+ * @param volume Volume to adjust to 0.0f - 1.0f
+ */
+ public void setVolume(String id, float volume) {
+ AudioPlayer audio = this.players.get(id);
+ if (audio != null) {
+ audio.setVolume(volume);
+ } else {
+ System.out.println("AudioHandler.setVolume() Error: Unknown Audio Player " + id);
+ }
+ }
}
diff --git a/framework/src/com/phonegap/AudioPlayer.java b/framework/src/com/phonegap/AudioPlayer.java
index 2d99fdbc..0f8c0606 100755
--- a/framework/src/com/phonegap/AudioPlayer.java
+++ b/framework/src/com/phonegap/AudioPlayer.java
@@ -7,8 +7,6 @@
*/
package com.phonegap;
-import java.io.File;
-import java.io.IOException;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
@@ -18,6 +16,9 @@ import android.media.MediaRecorder;
import android.os.Environment;
import android.util.Log;
+import java.io.File;
+import java.io.IOException;
+
/**
* This class implements the audio playback and recording capabilities used by PhoneGap.
* It is called by the AudioHandler PhoneGap class.
@@ -85,7 +86,10 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
// Stop any play or record
if (this.mPlayer != null) {
- this.stopPlaying();
+ if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
+ this.mPlayer.stop();
+ this.setState(MEDIA_STOPPED);
+ }
this.mPlayer.release();
this.mPlayer = null;
}
@@ -417,4 +421,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = state;
}
+
+ /**
+ * Set the volume for audio player
+ *
+ * @param volume
+ */
+ public void setVolume(float volume) {
+ this.mPlayer.setVolume(volume, volume);
+ }
}
diff --git a/framework/src/com/phonegap/BatteryListener.java b/framework/src/com/phonegap/BatteryListener.java
new file mode 100755
index 00000000..ef939db3
--- /dev/null
+++ b/framework/src/com/phonegap/BatteryListener.java
@@ -0,0 +1,145 @@
+/*
+ * PhoneGap is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2005-2010, Nitobi Software Inc.
+ * Copyright (c) 2010-2011, IBM Corporation
+ */
+package com.phonegap;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.phonegap.api.Plugin;
+import com.phonegap.api.PluginResult;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+public class BatteryListener extends Plugin {
+
+ private static final String LOG_TAG = "BatteryManager";
+
+ BroadcastReceiver receiver;
+
+ private String batteryCallbackId = null;
+
+ /**
+ * Constructor.
+ */
+ public BatteryListener() {
+ this.receiver = null;
+ }
+
+ /**
+ * 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.INVALID_ACTION;
+ String result = "Unsupported Operation: " + action;
+
+ if (action.equals("start")) {
+ if (this.batteryCallbackId != null) {
+ return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
+ }
+ this.batteryCallbackId = callbackId;
+
+ // We need to listen to power events to update battery status
+ IntentFilter intentFilter = new IntentFilter() ;
+ intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ if (this.receiver == null) {
+ this.receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateBatteryInfo(intent);
+ }
+ };
+ ctx.registerReceiver(this.receiver, intentFilter);
+ }
+
+ // 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.setKeepCallback(true);
+ return pluginResult;
+ }
+
+ else if (action.equals("stop")) {
+ removeBatteryListener();
+ this.sendUpdate(new JSONObject(), false); // release status callback in JS side
+ this.batteryCallbackId = null;
+ return new PluginResult(PluginResult.Status.OK);
+ }
+
+ return new PluginResult(status, result);
+ }
+
+ /**
+ * Stop battery receiver.
+ */
+ public void onDestroy() {
+ removeBatteryListener();
+ }
+
+ /**
+ * Stop the battery receiver and set it to null.
+ */
+ private void removeBatteryListener() {
+ if (this.receiver != null) {
+ try {
+ this.ctx.unregisterReceiver(this.receiver);
+ this.receiver = null;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Creates a JSONObject with the current battery information
+ *
+ * @param batteryIntent the current battery information
+ * @return a JSONObject containing the battery status information
+ */
+ private JSONObject getBatteryInfo(Intent batteryIntent) {
+ JSONObject obj = new JSONObject();
+ try {
+ obj.put("level", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, 0));
+ obj.put("isPlugged", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) > 0 ? true : false);
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, e.getMessage(), e);
+ }
+ return obj;
+ }
+
+ /**
+ * Updates the JavaScript side whenever the battery changes
+ *
+ * @param batteryIntent the current battery information
+ * @return
+ */
+ private void updateBatteryInfo(Intent batteryIntent) {
+ sendUpdate(this.getBatteryInfo(batteryIntent), true);
+ }
+
+ /**
+ * Create a new plugin result and send it back to JavaScript
+ *
+ * @param connection the network info to set as navigator.connection
+ */
+ private void sendUpdate(JSONObject info, boolean keepCallback) {
+ if (this.batteryCallbackId != null) {
+ PluginResult result = new PluginResult(PluginResult.Status.OK, info);
+ result.setKeepCallback(keepCallback);
+ this.success(result, this.batteryCallbackId);
+ }
+ }
+}
diff --git a/framework/src/com/phonegap/CameraLauncher.java b/framework/src/com/phonegap/CameraLauncher.java
index 6ca85c43..58526653 100755
--- a/framework/src/com/phonegap/CameraLauncher.java
+++ b/framework/src/com/phonegap/CameraLauncher.java
@@ -35,100 +35,102 @@ import android.util.Log;
*/
public class CameraLauncher extends Plugin {
- 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 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 SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
-
- 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 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 targetHeight; // desired height of the image
- private Uri imageUri; // Uri of captured image
- public String callbackId;
-
+ 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 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 SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
+
+ 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 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 targetHeight; // desired height of the image
+ private Uri imageUri;
+ private int encodingType;
+ // Uri of captured image
+ public String callbackId;
+
/**
* Constructor.
*/
- public CameraLauncher() {
- }
+ public CameraLauncher() {
+ }
- /**
- * 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 = "";
- this.callbackId = callbackId;
-
- try {
- if (action.equals("takePicture")) {
- int destType = DATA_URL;
- if (args.length() > 1) {
- destType = args.getInt(1);
- }
- int srcType = CAMERA;
- if (args.length() > 2) {
- srcType = args.getInt(2);
- }
+ /**
+ * 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 = "";
+ this.callbackId = callbackId;
+
+ try {
+ if (action.equals("takePicture")) {
+ int destType = DATA_URL;
+ if (args.length() > 1) {
+ destType = args.getInt(1);
+ }
+ int srcType = CAMERA;
+ if (args.length() > 2) {
+ srcType = args.getInt(2);
+ }
if (args.length() > 3) {
this.targetWidth = args.getInt(3);
}
if (args.length() > 4) {
this.targetHeight = args.getInt(4);
}
- int encodingType = JPEG;
+ this.encodingType = JPEG;
if (args.length() > 5) {
- encodingType = args.getInt(5);
+ this.encodingType = args.getInt(5);
}
- if (srcType == CAMERA) {
- this.takePicture(args.getInt(0), destType, encodingType);
- }
- else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
- this.getImage(args.getInt(0), srcType, destType);
- }
- PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
- r.setKeepCallback(true);
- return r;
- }
- return new PluginResult(status, result);
- } catch (JSONException e) {
- e.printStackTrace();
- return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
- }
- }
-
+ if (srcType == CAMERA) {
+ this.takePicture(args.getInt(0), destType, encodingType);
+ }
+ else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+ this.getImage(args.getInt(0), srcType, destType);
+ }
+ PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
+ r.setKeepCallback(true);
+ return r;
+ }
+ return new PluginResult(status, result);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+ }
+ }
+
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
- /**
- * Take a picture with the camera.
- * When an image is captured or the camera view is cancelled, the result is returned
- * in PhonegapActivity.onActivityResult, which forwards the result to this.onActivityResult.
- *
- * The image can either be returned as a base64 string or a URI that points to the file.
- * To display base64 string in an img tag, set the source to:
- * img.src="data:image/jpeg;base64,"+result;
- * or to display URI in an img tag
- * img.src=result;
- *
- * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
- * @param returnType Set the type of image to return.
- */
- public void takePicture(int quality, int returnType, int encodingType) {
- this.mQuality = quality;
-
- // Display camera
+ /**
+ * Take a picture with the camera.
+ * When an image is captured or the camera view is cancelled, the result is returned
+ * in PhonegapActivity.onActivityResult, which forwards the result to this.onActivityResult.
+ *
+ * The image can either be returned as a base64 string or a URI that points to the file.
+ * To display base64 string in an img tag, set the source to:
+ * img.src="data:image/jpeg;base64,"+result;
+ * or to display URI in an img tag
+ * img.src=result;
+ *
+ * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+ * @param returnType Set the type of image to return.
+ */
+ public void takePicture(int quality, int returnType, int encodingType) {
+ this.mQuality = quality;
+
+ // Display camera
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// Specify file so that large image is captured and returned
@@ -138,14 +140,14 @@ public class CameraLauncher extends Plugin {
this.imageUri = Uri.fromFile(photo);
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
- }
+ }
- /**
- * Create a file in the applications temporary directory based upon the supplied encoding.
- *
- * @param encodingType of the image to be taken
- * @return a File object pointing to the temporary picture
- */
+ /**
+ * Create a file in the applications temporary directory based upon the supplied encoding.
+ *
+ * @param encodingType of the image to be taken
+ * @return a File object pointing to the temporary picture
+ */
private File createCaptureFile(int encodingType) {
File photo = null;
if (encodingType == JPEG) {
@@ -157,46 +159,46 @@ public class CameraLauncher extends Plugin {
}
/**
- * Get image from photo library.
- *
- * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
- * @param srcType The album to get image from.
- * @param returnType Set the type of image to return.
- */
- // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
- public void getImage(int quality, int srcType, int returnType) {
- this.mQuality = quality;
+ * Get image from photo library.
+ *
+ * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+ * @param srcType The album to get image from.
+ * @param returnType Set the type of image to return.
+ */
+ // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
+ public void getImage(int quality, int srcType, int returnType) {
+ this.mQuality = quality;
- Intent intent = new Intent();
- intent.setType("image/*");
- intent.setAction(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
- new String("Get Picture")), (srcType+1)*16 + returnType + 1);
- }
+ Intent intent = new Intent();
+ intent.setType("image/*");
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
+ new String("Get Picture")), (srcType+1)*16 + returnType + 1);
+ }
- /**
- * Scales the bitmap according to the requested size.
- *
- * @param bitmap The bitmap to scale.
- * @return Bitmap A new Bitmap object of the same bitmap after scaling.
- */
- public Bitmap scaleBitmap(Bitmap bitmap) {
+ /**
+ * Scales the bitmap according to the requested size.
+ *
+ * @param bitmap The bitmap to scale.
+ * @return Bitmap A new Bitmap object of the same bitmap after scaling.
+ */
+ public Bitmap scaleBitmap(Bitmap bitmap) {
int newWidth = this.targetWidth;
int newHeight = this.targetHeight;
int origWidth = bitmap.getWidth();
int origHeight = bitmap.getHeight();
// If no new width or height were specified return the original bitmap
- if (newWidth <= 0 && newHeight <= 0) {
- return bitmap;
- }
- // Only the width was specified
- else if (newWidth > 0 && newHeight <= 0) {
+ if (newWidth <= 0 && newHeight <= 0) {
+ return bitmap;
+ }
+ // Only the width was specified
+ else if (newWidth > 0 && newHeight <= 0) {
newHeight = (newWidth * origHeight) / origWidth;
}
- // only the height was specified
- else if (newWidth <= 0 && newHeight > 0) {
+ // only the height was specified
+ else if (newWidth <= 0 && newHeight > 0) {
newWidth = (newHeight * origWidth) / origHeight;
}
// If the user specified both a positive width and height
@@ -205,7 +207,7 @@ public class CameraLauncher extends Plugin {
// Alternatively, the specified width and height could have been
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
// would result in whitespace in the new image.
- else {
+ else {
double newRatio = newWidth / (double)newHeight;
double origRatio = origWidth / (double)origHeight;
@@ -217,156 +219,169 @@ public class CameraLauncher extends Plugin {
}
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
- }
-
+ }
+
/**
* Called when the camera view exits.
*
- * @param requestCode The request code originally supplied to startActivityForResult(),
- * allowing you to identify who this result came from.
- * @param resultCode The integer result code returned by the child activity through its setResult().
- * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+ * @param requestCode The request code originally supplied to startActivityForResult(),
+ * allowing you to identify who this result came from.
+ * @param resultCode The integer result code returned by the child activity through its setResult().
+ * @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) {
-
- // Get src and dest types from request code
- int srcType = (requestCode/16) - 1;
- int destType = (requestCode % 16) - 1;
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+
+ // Get src and dest types from request code
+ int srcType = (requestCode/16) - 1;
+ int destType = (requestCode % 16) - 1;
- // If CAMERA
- if (srcType == CAMERA) {
- // If image available
- if (resultCode == Activity.RESULT_OK) {
- try {
- // Read in bitmap of captured image
- Bitmap bitmap;
- try {
- bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
- } catch (FileNotFoundException e) {
- Uri uri = intent.getData();
- android.content.ContentResolver resolver = this.ctx.getContentResolver();
- bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
- }
+ // If CAMERA
+ if (srcType == CAMERA) {
+ // If image available
+ if (resultCode == Activity.RESULT_OK) {
+ try {
+ // Create an ExifHelper to save the exif data that is lost during compression
+ ExifHelper exif = new ExifHelper();
+ if (this.encodingType == JPEG) {
+ exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Pic.jpg");
+ exif.readExifData();
+ }
- bitmap = scaleBitmap(bitmap);
-
- // If sending base64 image back
- if (destType == DATA_URL) {
- this.processPicture(bitmap);
- }
+ // Read in bitmap of captured image
+ Bitmap bitmap;
+ try {
+ bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
+ } catch (FileNotFoundException e) {
+ Uri uri = intent.getData();
+ android.content.ContentResolver resolver = this.ctx.getContentResolver();
+ bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
+ }
- // If sending filename back
- else if (destType == FILE_URI){
- // Create entry in media store for image
- // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
- ContentValues values = new ContentValues();
- values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
- Uri uri = null;
- try {
- uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
- } catch (UnsupportedOperationException e) {
- System.out.println("Can't write to external media storage.");
- try {
- uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
- } catch (UnsupportedOperationException ex) {
- System.out.println("Can't write to internal media storage.");
- this.failPicture("Error capturing image - no media storage found.");
- return;
- }
- }
+ bitmap = scaleBitmap(bitmap);
+
+ // If sending base64 image back
+ if (destType == DATA_URL) {
+ this.processPicture(bitmap);
+ }
- // Add compressed version of captured image to returned media store Uri
- OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
- bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
- os.close();
+ // If sending filename back
+ else if (destType == FILE_URI){
+ // Create entry in media store for image
+ // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
+ ContentValues values = new ContentValues();
+ values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+ Uri uri = null;
+ try {
+ uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+ } catch (UnsupportedOperationException e) {
+ System.out.println("Can't write to external media storage.");
+ try {
+ uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
+ } catch (UnsupportedOperationException ex) {
+ System.out.println("Can't write to internal media storage.");
+ this.failPicture("Error capturing image - no media storage found.");
+ return;
+ }
+ }
- // Send Uri back to JavaScript for viewing image
- this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
- }
- bitmap.recycle();
- bitmap = null;
- System.gc();
- } catch (IOException e) {
- e.printStackTrace();
- this.failPicture("Error capturing image.");
- }
- }
+ // Add compressed version of captured image to returned media store Uri
+ OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
+ os.close();
+
+ // Restore exif data to file
+ if (this.encodingType == JPEG) {
+ exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
+ exif.writeExifData();
+ }
- // If cancelled
- else if (resultCode == Activity.RESULT_CANCELED) {
- this.failPicture("Camera cancelled.");
- }
+ // Send Uri back to JavaScript for viewing image
+ this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
+ }
+ bitmap.recycle();
+ bitmap = null;
+ System.gc();
+ } catch (IOException e) {
+ e.printStackTrace();
+ this.failPicture("Error capturing image.");
+ }
+ }
- // If something else
- else {
- this.failPicture("Did not complete!");
- }
- }
-
- // If retrieving photo from library
- else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
- if (resultCode == Activity.RESULT_OK) {
- Uri uri = intent.getData();
- android.content.ContentResolver resolver = this.ctx.getContentResolver();
- // If sending base64 image back
- if (destType == DATA_URL) {
- try {
- Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
- bitmap = scaleBitmap(bitmap);
- this.processPicture(bitmap);
- bitmap.recycle();
- bitmap = null;
- System.gc();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- this.failPicture("Error retrieving image.");
- }
- }
-
- // If sending filename back
- else if (destType == FILE_URI) {
- this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
- }
- }
- else if (resultCode == Activity.RESULT_CANCELED) {
- this.failPicture("Selection cancelled.");
- }
- else {
- this.failPicture("Selection did not complete!");
- }
- }
- }
-
- /**
- * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
- *
- * @param bitmap
- */
- public void processPicture(Bitmap bitmap) {
- ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
- try {
- if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
- byte[] code = jpeg_data.toByteArray();
- byte[] output = Base64.encodeBase64(code);
- String js_out = new String(output);
- this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
- js_out = null;
- output = null;
- code = null;
- }
- }
- catch(Exception e) {
- this.failPicture("Error compressing image.");
- }
- jpeg_data = null;
- }
-
- /**
- * Send error message to JavaScript.
- *
- * @param err
- */
- public void failPicture(String err) {
- this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
- }
-}
+ // If cancelled
+ else if (resultCode == Activity.RESULT_CANCELED) {
+ this.failPicture("Camera cancelled.");
+ }
+
+ // If something else
+ else {
+ this.failPicture("Did not complete!");
+ }
+ }
+
+ // If retrieving photo from library
+ else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+ if (resultCode == Activity.RESULT_OK) {
+ Uri uri = intent.getData();
+ android.content.ContentResolver resolver = this.ctx.getContentResolver();
+ // If sending base64 image back
+ if (destType == DATA_URL) {
+ try {
+ Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
+ bitmap = scaleBitmap(bitmap);
+ this.processPicture(bitmap);
+ bitmap.recycle();
+ bitmap = null;
+ System.gc();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ this.failPicture("Error retrieving image.");
+ }
+ }
+
+ // If sending filename back
+ else if (destType == FILE_URI) {
+ this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
+ }
+ }
+ else if (resultCode == Activity.RESULT_CANCELED) {
+ this.failPicture("Selection cancelled.");
+ }
+ else {
+ this.failPicture("Selection did not complete!");
+ }
+ }
+ }
+
+ /**
+ * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
+ *
+ * @param bitmap
+ */
+ public void processPicture(Bitmap bitmap) {
+ ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
+ try {
+ if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
+ byte[] code = jpeg_data.toByteArray();
+ byte[] output = Base64.encodeBase64(code);
+ String js_out = new String(output);
+ this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
+ js_out = null;
+ output = null;
+ code = null;
+ }
+ }
+ catch(Exception e) {
+ this.failPicture("Error compressing image.");
+ }
+ jpeg_data = null;
+ }
+
+ /**
+ * Send error message to JavaScript.
+ *
+ * @param err
+ */
+ public void failPicture(String err) {
+ this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/com/phonegap/Capture.java b/framework/src/com/phonegap/Capture.java
index b078e5df..e9261442 100644
--- a/framework/src/com/phonegap/Capture.java
+++ b/framework/src/com/phonegap/Capture.java
@@ -18,12 +18,10 @@ import org.json.JSONObject;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.net.Uri;
-import android.os.Environment;
import android.util.Log;
import com.phonegap.api.Plugin;
@@ -31,146 +29,145 @@ import com.phonegap.api.PluginResult;
public class Capture extends Plugin {
- private static final String _DATA = "_data"; // The column name where the file path is stored
- 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_VIDEO = 2; // Constant for capture video
- private static final String LOG_TAG = "Capture";
- 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 double duration; // optional duration parameter for video recording
- private JSONArray results; // The array of results to be returned to the user
- private Uri imageUri; // Uri of captured image
+ 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_VIDEO = 2; // Constant for capture video
+ private static final String LOG_TAG = "Capture";
+ 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 double duration; // optional duration parameter for video recording
+ private JSONArray results; // The array of results to be returned to the user
+ private Uri imageUri; // Uri of captured image
- @Override
- public PluginResult execute(String action, JSONArray args, String callbackId) {
- this.callbackId = callbackId;
- this.limit = 1;
- this.duration = 0.0f;
- this.results = new JSONArray();
-
- JSONObject options = args.optJSONObject(0);
- if (options != null) {
- limit = options.optLong("limit", 1);
- duration = options.optDouble("duration", 0.0f);
- }
+ @Override
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+ this.callbackId = callbackId;
+ this.limit = 1;
+ this.duration = 0.0f;
+ this.results = new JSONArray();
+
+ JSONObject options = args.optJSONObject(0);
+ if (options != null) {
+ limit = options.optLong("limit", 1);
+ duration = options.optDouble("duration", 0.0f);
+ }
- if (action.equals("getFormatData")) {
- try {
- JSONObject obj = getFormatData(args.getString(0), args.getString(1));
- return new PluginResult(PluginResult.Status.OK, obj);
- } catch (JSONException e) {
- return new PluginResult(PluginResult.Status.ERROR);
- }
- }
- else if (action.equals("captureAudio")) {
- this.captureAudio();
- }
- else if (action.equals("captureImage")) {
- this.captureImage();
- }
- else if (action.equals("captureVideo")) {
- this.captureVideo(duration);
- }
-
- PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
- r.setKeepCallback(true);
- return r;
- }
+ if (action.equals("getFormatData")) {
+ try {
+ JSONObject obj = getFormatData(args.getString(0), args.getString(1));
+ return new PluginResult(PluginResult.Status.OK, obj);
+ } catch (JSONException e) {
+ return new PluginResult(PluginResult.Status.ERROR);
+ }
+ }
+ else if (action.equals("captureAudio")) {
+ this.captureAudio();
+ }
+ else if (action.equals("captureImage")) {
+ this.captureImage();
+ }
+ else if (action.equals("captureVideo")) {
+ this.captureVideo(duration);
+ }
+
+ PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
+ r.setKeepCallback(true);
+ return r;
+ }
- /**
- * Provides the media data file data depending on it's mime type
- *
- * @param filePath path to the file
- * @param mimeType of the file
- * @return a MediaFileData object
- */
- private JSONObject getFormatData(String filePath, String mimeType) {
- JSONObject obj = new JSONObject();
- try {
- // setup defaults
- obj.put("height", 0);
- obj.put("width", 0);
- obj.put("bitrate", 0);
- obj.put("duration", 0);
- obj.put("codecs", "");
+ /**
+ * Provides the media data file data depending on it's mime type
+ *
+ * @param filePath path to the file
+ * @param mimeType of the file
+ * @return a MediaFileData object
+ */
+ private JSONObject getFormatData(String filePath, String mimeType) {
+ JSONObject obj = new JSONObject();
+ try {
+ // setup defaults
+ obj.put("height", 0);
+ obj.put("width", 0);
+ obj.put("bitrate", 0);
+ obj.put("duration", 0);
+ obj.put("codecs", "");
- // If the mimeType isn't set the rest will fail
- // so let's see if we can determine it.
- if (mimeType == null || mimeType.equals("")) {
- mimeType = FileUtils.getMimeType(filePath);
- }
-
- if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) {
- obj = getImageData(filePath, obj);
- }
- else if (filePath.endsWith("audio/3gpp")) {
- obj = getAudioVideoData(filePath, obj, false);
- }
- else if (mimeType.equals("video/3gpp")) {
- obj = getAudioVideoData(filePath, obj, true);
- }
- }
- catch (JSONException e) {
- Log.d(LOG_TAG, "Error: setting media file data object");
- }
- return obj;
- }
+ // If the mimeType isn't set the rest will fail
+ // so let's see if we can determine it.
+ if (mimeType == null || mimeType.equals("")) {
+ mimeType = FileUtils.getMimeType(filePath);
+ }
+
+ if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) {
+ obj = getImageData(filePath, obj);
+ }
+ else if (filePath.endsWith("audio/3gpp")) {
+ obj = getAudioVideoData(filePath, obj, false);
+ }
+ else if (mimeType.equals("video/3gpp")) {
+ obj = getAudioVideoData(filePath, obj, true);
+ }
+ }
+ catch (JSONException e) {
+ Log.d(LOG_TAG, "Error: setting media file data object");
+ }
+ return obj;
+ }
- /**
- * Get the Image specific attributes
- *
- * @param filePath path to the file
- * @param obj represents the Media File Data
- * @return a JSONObject that represents the Media File Data
- * @throws JSONException
- */
- private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
- Bitmap bitmap = BitmapFactory.decodeFile(filePath);
- obj.put("height", bitmap.getHeight());
- obj.put("width", bitmap.getWidth());
- return obj;
- }
+ /**
+ * Get the Image specific attributes
+ *
+ * @param filePath path to the file
+ * @param obj represents the Media File Data
+ * @return a JSONObject that represents the Media File Data
+ * @throws JSONException
+ */
+ private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
+ Bitmap bitmap = BitmapFactory.decodeFile(filePath);
+ obj.put("height", bitmap.getHeight());
+ obj.put("width", bitmap.getWidth());
+ return obj;
+ }
- /**
- * Get the Image specific attributes
- *
- * @param filePath path to the file
- * @param obj represents the Media File Data
- * @param video if true get video attributes as well
- * @return a JSONObject that represents the Media File Data
- * @throws JSONException
- */
- private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException {
- MediaPlayer player = new MediaPlayer();
- try {
- player.setDataSource(filePath);
- player.prepare();
- obj.put("duration", player.getDuration());
- if (video) {
- obj.put("height", player.getVideoHeight());
- obj.put("width", player.getVideoWidth());
- }
- }
- catch (IOException e) {
- Log.d(LOG_TAG, "Error: loading video file");
- }
- return obj;
- }
+ /**
+ * Get the Image specific attributes
+ *
+ * @param filePath path to the file
+ * @param obj represents the Media File Data
+ * @param video if true get video attributes as well
+ * @return a JSONObject that represents the Media File Data
+ * @throws JSONException
+ */
+ private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException {
+ MediaPlayer player = new MediaPlayer();
+ try {
+ player.setDataSource(filePath);
+ player.prepare();
+ obj.put("duration", player.getDuration());
+ if (video) {
+ obj.put("height", player.getVideoHeight());
+ obj.put("width", player.getVideoWidth());
+ }
+ }
+ catch (IOException e) {
+ Log.d(LOG_TAG, "Error: loading video file");
+ }
+ return obj;
+ }
- /**
- * Sets up an intent to capture audio. Result handled by onActivityResult()
- */
- private void captureAudio() {
+ /**
+ * Sets up an intent to capture audio. Result handled by onActivityResult()
+ */
+ private void captureAudio() {
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
}
- /**
- * Sets up an intent to capture images. Result handled by onActivityResult()
- */
- private void captureImage() {
+ /**
+ * Sets up an intent to capture images. Result handled by onActivityResult()
+ */
+ private void captureImage() {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// Specify file so that large image is captured and returned
@@ -181,179 +178,174 @@ public class Capture extends Plugin {
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
}
- /**
- * Sets up an intent to capture video. Result handled by onActivityResult()
- */
- private void captureVideo(double duration) {
+ /**
+ * Sets up an intent to capture video. Result handled by onActivityResult()
+ */
+ private void captureVideo(double duration) {
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
// Introduced in API 8
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
}
-
+
/**
* Called when the video view exits.
*
- * @param requestCode The request code originally supplied to startActivityForResult(),
- * allowing you to identify who this result came from.
- * @param resultCode The integer result code returned by the child activity through its setResult().
- * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+ * @param requestCode The request code originally supplied to startActivityForResult(),
+ * allowing you to identify who this result came from.
+ * @param resultCode The integer result code returned by the child activity through its setResult().
+ * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
* @throws JSONException
*/
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- // Result received okay
- if (resultCode == Activity.RESULT_OK) {
- // An audio clip was requested
- if (requestCode == CAPTURE_AUDIO) {
- // Get the uri of the audio clip
- Uri data = intent.getData();
- // create a file object from the uri
- results.put(createMediaFile(data));
+ // Result received okay
+ if (resultCode == Activity.RESULT_OK) {
+ // An audio clip was requested
+ if (requestCode == CAPTURE_AUDIO) {
+ // Get the uri of the audio clip
+ Uri data = intent.getData();
+ // create a file object from the uri
+ results.put(createMediaFile(data));
- if (results.length() >= limit) {
- // Send Uri back to JavaScript for listening to audio
- this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
- } else {
- // still need to capture more audio clips
- captureAudio();
- }
- } else if (requestCode == CAPTURE_IMAGE) {
- // For some reason if I try to do:
- // Uri data = intent.getData();
- // It crashes in the emulator and on my phone with a null pointer exception
- // To work around it I had to grab the code from CameraLauncher.java
- try {
- // Read in bitmap of captured image
- Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
+ if (results.length() >= limit) {
+ // Send Uri back to JavaScript for listening to audio
+ this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
+ } else {
+ // still need to capture more audio clips
+ captureAudio();
+ }
+ } else if (requestCode == CAPTURE_IMAGE) {
+ // For some reason if I try to do:
+ // Uri data = intent.getData();
+ // It crashes in the emulator and on my phone with a null pointer exception
+ // To work around it I had to grab the code from CameraLauncher.java
+ try {
+ // Create an ExifHelper to save the exif data that is lost during compression
+ ExifHelper exif = new ExifHelper();
+ exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Capture.jpg");
+ exif.readExifData();
+
+ // Read in bitmap of captured image
+ Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
- // Create entry in media store for image
- // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
- ContentValues values = new ContentValues();
- values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
- Uri uri = null;
- try {
- uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
- } catch (UnsupportedOperationException e) {
- System.out.println("Can't write to external media storage.");
- try {
- uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
- } catch (UnsupportedOperationException ex) {
- System.out.println("Can't write to internal media storage.");
- this.fail("Error capturing image - no media storage found.");
- return;
- }
- }
+ // Create entry in media store for image
+ // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
+ ContentValues values = new ContentValues();
+ values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+ Uri uri = null;
+ try {
+ uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+ } catch (UnsupportedOperationException e) {
+ System.out.println("Can't write to external media storage.");
+ try {
+ uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
+ } catch (UnsupportedOperationException ex) {
+ System.out.println("Can't write to internal media storage.");
+ this.fail("Error capturing image - no media storage found.");
+ return;
+ }
+ }
- // Add compressed version of captured image to returned media store Uri
- OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
- os.close();
+ // Add compressed version of captured image to returned media store Uri
+ OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
+ os.close();
- bitmap.recycle();
- bitmap = null;
- System.gc();
-
- // Add image to results
- results.put(createMediaFile(uri));
-
- if (results.length() >= limit) {
- // Send Uri back to JavaScript for viewing image
- this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
- } else {
- // still need to capture more images
- captureImage();
- }
- } catch (IOException e) {
- e.printStackTrace();
- this.fail("Error capturing image.");
- }
- } else if (requestCode == CAPTURE_VIDEO) {
- // Get the uri of the video clip
- Uri data = intent.getData();
- // create a file object from the uri
- results.put(createMediaFile(data));
+ bitmap.recycle();
+ bitmap = null;
+ System.gc();
+
+ // Restore exif data to file
+ exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
+ exif.writeExifData();
+
+ // Add image to results
+ results.put(createMediaFile(uri));
+
+ if (results.length() >= limit) {
+ // Send Uri back to JavaScript for viewing image
+ this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
+ } else {
+ // still need to capture more images
+ captureImage();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ this.fail("Error capturing image.");
+ }
+ } else if (requestCode == CAPTURE_VIDEO) {
+ // Get the uri of the video clip
+ Uri data = intent.getData();
+ // create a file object from the uri
+ results.put(createMediaFile(data));
- if (results.length() >= limit) {
- // Send Uri back to JavaScript for viewing video
- this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
- } else {
- // still need to capture more video clips
- captureVideo(duration);
- }
- }
- }
- // If canceled
- else if (resultCode == Activity.RESULT_CANCELED) {
- // If we have partial results send them back to the user
- if (results.length() > 0) {
- this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
- }
- // user canceled the action
- else {
- this.fail("Canceled.");
- }
- }
- // If something else
- else {
- // If we have partial results send them back to the user
- if (results.length() > 0) {
- this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
- }
- // something bad happened
- else {
- this.fail("Did not complete!");
- }
- }
- }
-
- /**
- * Creates a JSONObject that represents a File from the Uri
- *
- * @param data the Uri of the audio/image/video
- * @return a JSONObject that represents a File
- */
- private JSONObject createMediaFile(Uri data) {
- File fp = new File(getRealPathFromURI(data));
-
- JSONObject obj = new JSONObject();
-
- try {
- // File properties
- obj.put("name", fp.getName());
- obj.put("fullPath", fp.getAbsolutePath());
- obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
- obj.put("lastModifiedDate", fp.lastModified());
- obj.put("size", fp.length());
- } catch (JSONException e) {
- // this will never happen
- e.printStackTrace();
- }
-
- return obj;
- }
-
- /**
- * Queries the media store to find out what the file path is for the Uri we supply
- *
- * @param contentUri the Uri of the audio/image/video
- * @return the full path to the file
- */
- private String getRealPathFromURI(Uri contentUri) {
- String[] proj = { _DATA };
- Cursor cursor = this.ctx.managedQuery(contentUri, proj, null, null, null);
- int column_index = cursor.getColumnIndexOrThrow(_DATA);
- cursor.moveToFirst();
- return cursor.getString(column_index);
+ if (results.length() >= limit) {
+ // Send Uri back to JavaScript for viewing video
+ this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
+ } else {
+ // still need to capture more video clips
+ captureVideo(duration);
+ }
+ }
+ }
+ // If canceled
+ else if (resultCode == Activity.RESULT_CANCELED) {
+ // If we have partial results send them back to the user
+ if (results.length() > 0) {
+ this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
+ }
+ // user canceled the action
+ else {
+ this.fail("Canceled.");
+ }
+ }
+ // If something else
+ else {
+ // If we have partial results send them back to the user
+ if (results.length() > 0) {
+ this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
+ }
+ // something bad happened
+ else {
+ this.fail("Did not complete!");
+ }
+ }
}
- /**
- * Send error message to JavaScript.
- *
- * @param err
- */
- public void fail(String err) {
- this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
- }
+ /**
+ * Creates a JSONObject that represents a File from the Uri
+ *
+ * @param data the Uri of the audio/image/video
+ * @return a JSONObject that represents a File
+ * @throws IOException
+ */
+ private JSONObject createMediaFile(Uri data){
+ File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
+ JSONObject obj = new JSONObject();
+
+ try {
+ // File properties
+ obj.put("name", fp.getName());
+ obj.put("fullPath", fp.getAbsolutePath());
+ obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
+ obj.put("lastModifiedDate", fp.lastModified());
+ obj.put("size", fp.length());
+ } catch (JSONException e) {
+ // this will never happen
+ e.printStackTrace();
+ }
+
+ return obj;
+ }
+
+ /**
+ * Send error message to JavaScript.
+ *
+ * @param err
+ */
+ public void fail(String err) {
+ this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
+ }
}
\ No newline at end of file
diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java
old mode 100644
new mode 100755
index d9ecccd9..0b6b4d50
--- a/framework/src/com/phonegap/DroidGap.java
+++ b/framework/src/com/phonegap/DroidGap.java
@@ -91,78 +91,90 @@ import com.phonegap.api.PluginManager;
*
* Properties: The application can be configured using the following properties:
*
- * // Display a native loading dialog. Format for value = "Title,Message".
- * // (String - default=null)
- * super.setStringProperty("loadingDialog", "Wait,Loading Demo...");
+ * // Display a native loading dialog. Format for value = "Title,Message".
+ * // (String - default=null)
+ * super.setStringProperty("loadingDialog", "Wait,Loading Demo...");
*
- * // Cause all links on web page to be loaded into existing web view,
- * // instead of being loaded into new browser. (Boolean - default=false)
- * super.setBooleanProperty("loadInWebView", true);
+ * // Display a native loading dialog when loading sub-pages. Format for value = "Title,Message".
+ * // (String - default=null)
+ * super.setStringProperty("loadingPageDialog", "Loading page...");
+ *
+ * // Cause all links on web page to be loaded into existing web view,
+ * // instead of being loaded into new browser. (Boolean - default=false)
+ * super.setBooleanProperty("loadInWebView", true);
*
- * // Load a splash screen image from the resource drawable directory.
- * // (Integer - default=0)
- * super.setIntegerProperty("splashscreen", R.drawable.splash);
+ * // Load a splash screen image from the resource drawable directory.
+ * // (Integer - default=0)
+ * super.setIntegerProperty("splashscreen", R.drawable.splash);
+ *
+ * // Set the background color.
+ * // (Integer - default=0 or BLACK)
+ * super.setIntegerProperty("backgroundColor", Color.WHITE);
*
- * // Time in msec to wait before triggering a timeout error when loading
- * // with super.loadUrl(). (Integer - default=20000)
- * super.setIntegerProperty("loadUrlTimeoutValue", 60000);
+ * // Time in msec to wait before triggering a timeout error when loading
+ * // with super.loadUrl(). (Integer - default=20000)
+ * super.setIntegerProperty("loadUrlTimeoutValue", 60000);
*
- * // URL to load if there's an error loading specified URL with loadUrl().
- * // Should be a local URL starting with file://. (String - default=null)
- * super.setStringProperty("errorUrl", "file:///android_asset/www/error.html");
+ * // URL to load if there's an error loading specified URL with loadUrl().
+ * // Should be a local URL starting with file://. (String - default=null)
+ * super.setStringProperty("errorUrl", "file:///android_asset/www/error.html");
*
- * // Enable app to keep running in background. (Boolean - default=true)
- * super.setBooleanProperty("keepRunning", false);
+ * // Enable app to keep running in background. (Boolean - default=true)
+ * super.setBooleanProperty("keepRunning", false);
*/
public class DroidGap extends PhonegapActivity {
- // The webview for our app
- protected WebView appView;
- protected WebViewClient webViewClient;
+ // The webview for our app
+ protected WebView appView;
+ protected WebViewClient webViewClient;
- protected LinearLayout root;
- public boolean bound = false;
- public CallbackServer callbackServer;
- protected PluginManager pluginManager;
- protected boolean cancelLoadUrl = false;
- protected boolean clearHistory = false;
- protected ProgressDialog spinnerDialog = null;
+ protected LinearLayout root;
+ public boolean bound = false;
+ public CallbackServer callbackServer;
+ protected PluginManager pluginManager;
+ protected boolean cancelLoadUrl = false;
+ protected boolean clearHistory = false;
+ protected ProgressDialog spinnerDialog = null;
- // The initial URL for our app
- // ie http://server/path/index.html#abc?query
- private String url;
-
- // The base of the initial URL for our app.
- // Does not include file name. Ends with /
- // ie http://server/path/
- private String baseUrl = null;
+ // The initial URL for our app
+ // ie http://server/path/index.html#abc?query
+ private String url;
+
+ // The base of the initial URL for our app.
+ // Does not include file name. Ends with /
+ // ie http://server/path/
+ private String baseUrl = null;
- // Plugin to call when activity result is received
- protected IPlugin activityResultCallback = null;
- protected boolean activityResultKeepRunning;
+ // Plugin to call when activity result is received
+ protected IPlugin activityResultCallback = null;
+ protected boolean activityResultKeepRunning;
- // Flag indicates that a loadUrl timeout occurred
- private int loadUrlTimeout = 0;
-
- /*
- * The variables below are used to cache some of the activity properties.
- */
+ // Flag indicates that a loadUrl timeout occurred
+ private int loadUrlTimeout = 0;
+
+ // Default background color for activity
+ // (this is not the color for the webview, which is set in HTML)
+ private int backgroundColor = Color.BLACK;
+
+ /*
+ * The variables below are used to cache some of the activity properties.
+ */
- // Flag indicates that a URL navigated to from PhoneGap app should be loaded into same webview
- // instead of being loaded into the web browser.
- protected boolean loadInWebView = false;
+ // Flag indicates that a URL navigated to from PhoneGap app should be loaded into same webview
+ // instead of being loaded into the web browser.
+ protected boolean loadInWebView = false;
- // Draw a splash screen using an image located in the drawable resource directory.
- // This is not the same as calling super.loadSplashscreen(url)
- protected int splashscreen = 0;
+ // Draw a splash screen using an image located in the drawable resource directory.
+ // This is not the same as calling super.loadSplashscreen(url)
+ protected int splashscreen = 0;
- // LoadUrl timeout value in msec (default of 20 sec)
- protected int loadUrlTimeoutValue = 20000;
-
- // Keep app running when pause is received. (default = true)
- // If true, then the JavaScript and native code continue to run in the background
- // when another application (activity) is started.
- protected boolean keepRunning = true;
+ // LoadUrl timeout value in msec (default of 20 sec)
+ protected int loadUrlTimeoutValue = 20000;
+
+ // Keep app running when pause is received. (default = true)
+ // If true, then the JavaScript and native code continue to run in the background
+ // when another application (activity) is started.
+ protected boolean keepRunning = true;
/**
* Called when the activity is first created.
@@ -171,55 +183,55 @@ public class DroidGap extends PhonegapActivity {
*/
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
+ super.onCreate(savedInstanceState);
+ getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
- Display display = getWindowManager().getDefaultDisplay();
- int width = display.getWidth();
- int height = display.getHeight();
-
- root = new LinearLayoutSoftKeyboardDetect(this, width, height);
- root.setOrientation(LinearLayout.VERTICAL);
- root.setBackgroundColor(Color.BLACK);
- root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT, 0.0F));
+ Display display = getWindowManager().getDefaultDisplay();
+ int width = display.getWidth();
+ int height = display.getHeight();
+
+ root = new LinearLayoutSoftKeyboardDetect(this, width, height);
+ root.setOrientation(LinearLayout.VERTICAL);
+ root.setBackgroundColor(this.backgroundColor);
+ root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT, 0.0F));
- // If url was passed in to intent, then init webview, which will load the url
- Bundle bundle = this.getIntent().getExtras();
- if (bundle != null) {
- String url = bundle.getString("url");
- if (url != null) {
- this.init();
- }
- }
- // Setup the hardware volume controls to handle volume control
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ // If url was passed in to intent, then init webview, which will load the url
+ Bundle bundle = this.getIntent().getExtras();
+ if (bundle != null) {
+ String url = bundle.getString("url");
+ if (url != null) {
+ this.init();
+ }
+ }
+ // Setup the hardware volume controls to handle volume control
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
/**
* Create and initialize web container.
*/
- public void init() {
-
- // Create web container
- this.appView = new WebView(DroidGap.this);
- this.appView.setId(100);
-
- this.appView.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT,
- 1.0F));
+ public void init() {
+
+ // Create web container
+ this.appView = new WebView(DroidGap.this);
+ this.appView.setId(100);
+
+ this.appView.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 1.0F));
WebViewReflect.checkCompatibility();
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
- this.appView.setWebChromeClient(new GapClient(DroidGap.this));
+ this.appView.setWebChromeClient(new GapClient(DroidGap.this));
}
else {
- this.appView.setWebChromeClient(new EclairClient(DroidGap.this));
+ this.appView.setWebChromeClient(new EclairClient(DroidGap.this));
}
this.setWebViewClient(this.appView, new GapViewClient(this));
@@ -259,205 +271,209 @@ public class DroidGap extends PhonegapActivity {
// If url specified, then load it
String url = this.getStringProperty("url", null);
if (url != null) {
- System.out.println("Loading initial URL="+url);
- this.loadUrl(url);
+ System.out.println("Loading initial URL="+url);
+ this.loadUrl(url);
}
- }
-
- /**
- * Set the WebViewClient.
- *
- * @param appView
- * @param client
- */
- protected void setWebViewClient(WebView appView, WebViewClient client) {
- this.webViewClient = client;
- appView.setWebViewClient(client);
- }
+ }
+
+ /**
+ * Set the WebViewClient.
+ *
+ * @param appView
+ * @param client
+ */
+ protected void setWebViewClient(WebView appView, WebViewClient client) {
+ this.webViewClient = client;
+ appView.setWebViewClient(client);
+ }
/**
* Bind PhoneGap objects to JavaScript.
*
* @param appView
*/
- private void bindBrowser(WebView appView) {
- this.callbackServer = new CallbackServer();
- this.pluginManager = new PluginManager(appView, this);
+ private void bindBrowser(WebView appView) {
+ this.callbackServer = new CallbackServer();
+ this.pluginManager = new PluginManager(appView, this);
- }
+ }
- /**
- * Look at activity parameters and process them.
- * This must be called from the main UI thread.
- */
- private void handleActivityParameters() {
+ /**
+ * Look at activity parameters and process them.
+ * This must be called from the main UI thread.
+ */
+ private void handleActivityParameters() {
- // Init web view if not already done
- if (this.appView == null) {
- this.init();
- }
+ // Init web view if not already done
+ if (this.appView == null) {
+ this.init();
+ }
- // If spashscreen
- this.splashscreen = this.getIntegerProperty("splashscreen", 0);
- if (this.splashscreen != 0) {
- root.setBackgroundResource(this.splashscreen);
- }
+ // If backgroundColor
+ this.backgroundColor = this.getIntegerProperty("backgroundColor", Color.BLACK);
+ this.root.setBackgroundColor(this.backgroundColor);
- // If loadInWebView
- this.loadInWebView = this.getBooleanProperty("loadInWebView", false);
+ // If spashscreen
+ this.splashscreen = this.getIntegerProperty("splashscreen", 0);
+ if (this.splashscreen != 0) {
+ root.setBackgroundResource(this.splashscreen);
+ }
- // If loadUrlTimeoutValue
- int timeout = this.getIntegerProperty("loadUrlTimeoutValue", 0);
- if (timeout > 0) {
- this.loadUrlTimeoutValue = timeout;
- }
-
- // If keepRunning
- this.keepRunning = this.getBooleanProperty("keepRunning", true);
- }
-
+ // If loadInWebView
+ this.loadInWebView = this.getBooleanProperty("loadInWebView", false);
+
+ // If loadUrlTimeoutValue
+ int timeout = this.getIntegerProperty("loadUrlTimeoutValue", 0);
+ if (timeout > 0) {
+ this.loadUrlTimeoutValue = timeout;
+ }
+
+ // If keepRunning
+ this.keepRunning = this.getBooleanProperty("keepRunning", true);
+ }
+
/**
* Load the url into the webview.
*
* @param url
*/
- public void loadUrl(final String url) {
- System.out.println("loadUrl("+url+")");
- this.url = url;
- if (this.baseUrl == null) {
- int i = url.lastIndexOf('/');
- if (i > 0) {
- this.baseUrl = url.substring(0, i+1);
- }
- else {
- this.baseUrl = this.url + "/";
- }
- }
- System.out.println("url="+url+" baseUrl="+baseUrl);
+ public void loadUrl(final String url) {
+ System.out.println("loadUrl("+url+")");
+ this.url = url;
+ if (this.baseUrl == null) {
+ int i = url.lastIndexOf('/');
+ if (i > 0) {
+ this.baseUrl = url.substring(0, i+1);
+ }
+ else {
+ this.baseUrl = this.url + "/";
+ }
+ }
+ System.out.println("url="+url+" baseUrl="+baseUrl);
- // Load URL on UI thread
- final DroidGap me = this;
- this.runOnUiThread(new Runnable() {
- public void run() {
+ // Load URL on UI thread
+ final DroidGap me = this;
+ this.runOnUiThread(new Runnable() {
+ public void run() {
- // Handle activity parameters
- me.handleActivityParameters();
+ // Handle activity parameters
+ me.handleActivityParameters();
- // Initialize callback server
- me.callbackServer.init(url);
+ // Initialize callback server
+ me.callbackServer.init(url);
- // If loadingDialog, then show the App loading dialog
- String loading = me.getStringProperty("loadingDialog", null);
- if (loading != null) {
+ // If loadingDialog, then show the App loading dialog
+ String loading = me.getStringProperty("loadingDialog", null);
+ if (loading != null) {
- String title = "";
- String message = "Loading Application...";
+ String title = "";
+ String message = "Loading Application...";
- if (loading.length() > 0) {
- int comma = loading.indexOf(',');
- if (comma > 0) {
- title = loading.substring(0, comma);
- message = loading.substring(comma+1);
- }
- else {
- title = "";
- message = loading;
- }
- }
- me.spinnerStart(title, message);
- }
+ if (loading.length() > 0) {
+ int comma = loading.indexOf(',');
+ if (comma > 0) {
+ title = loading.substring(0, comma);
+ message = loading.substring(comma+1);
+ }
+ else {
+ title = "";
+ message = loading;
+ }
+ }
+ me.spinnerStart(title, message);
+ }
- // Create a timeout timer for loadUrl
- final int currentLoadUrlTimeout = me.loadUrlTimeout;
- Runnable runnable = new Runnable() {
- public void run() {
- try {
- synchronized(this) {
- wait(me.loadUrlTimeoutValue);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ // Create a timeout timer for loadUrl
+ final int currentLoadUrlTimeout = me.loadUrlTimeout;
+ Runnable runnable = new Runnable() {
+ public void run() {
+ try {
+ synchronized(this) {
+ wait(me.loadUrlTimeoutValue);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
- // If timeout, then stop loading and handle error
- if (me.loadUrlTimeout == currentLoadUrlTimeout) {
- me.appView.stopLoading();
- me.webViewClient.onReceivedError(me.appView, -6, "The connection to the server was unsuccessful.", url);
- }
- }
- };
- Thread thread = new Thread(runnable);
- thread.start();
- me.appView.loadUrl(url);
- }
- });
- }
-
- /**
- * Load the url into the webview after waiting for period of time.
- * This is used to display the splashscreen for certain amount of time.
- *
- * @param url
- * @param time The number of ms to wait before loading webview
- */
- public void loadUrl(final String url, final int time) {
- System.out.println("loadUrl("+url+","+time+")");
- final DroidGap me = this;
+ // If timeout, then stop loading and handle error
+ if (me.loadUrlTimeout == currentLoadUrlTimeout) {
+ me.appView.stopLoading();
+ me.webViewClient.onReceivedError(me.appView, -6, "The connection to the server was unsuccessful.", url);
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ me.appView.loadUrl(url);
+ }
+ });
+ }
+
+ /**
+ * Load the url into the webview after waiting for period of time.
+ * This is used to display the splashscreen for certain amount of time.
+ *
+ * @param url
+ * @param time The number of ms to wait before loading webview
+ */
+ public void loadUrl(final String url, final int time) {
+ System.out.println("loadUrl("+url+","+time+")");
+ final DroidGap me = this;
- // Handle activity parameters
- this.runOnUiThread(new Runnable() {
- public void run() {
- me.handleActivityParameters();
- }
- });
+ // Handle activity parameters
+ this.runOnUiThread(new Runnable() {
+ public void run() {
+ me.handleActivityParameters();
+ }
+ });
- Runnable runnable = new Runnable() {
- public void run() {
- try {
- synchronized(this) {
- this.wait(time);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (!me.cancelLoadUrl) {
- me.loadUrl(url);
- }
- else{
- me.cancelLoadUrl = false;
- System.out.println("Aborting loadUrl("+url+"): Another URL was loaded before timer expired.");
- }
- }
- };
- Thread thread = new Thread(runnable);
- thread.start();
- }
-
- /**
- * Cancel loadUrl before it has been loaded.
- */
- public void cancelLoadUrl() {
- this.cancelLoadUrl = true;
- }
-
- /**
- * Clear the resource cache.
- */
- public void clearCache() {
- if (this.appView == null) {
- this.init();
- }
- this.appView.clearCache(true);
- }
+ Runnable runnable = new Runnable() {
+ public void run() {
+ try {
+ synchronized(this) {
+ this.wait(time);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if (!me.cancelLoadUrl) {
+ me.loadUrl(url);
+ }
+ else{
+ me.cancelLoadUrl = false;
+ System.out.println("Aborting loadUrl("+url+"): Another URL was loaded before timer expired.");
+ }
+ }
+ };
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+ /**
+ * Cancel loadUrl before it has been loaded.
+ */
+ public void cancelLoadUrl() {
+ this.cancelLoadUrl = true;
+ }
+
+ /**
+ * Clear the resource cache.
+ */
+ public void clearCache() {
+ if (this.appView == null) {
+ this.init();
+ }
+ this.appView.clearCache(true);
+ }
/**
* Clear web history in this web view.
*/
public void clearHistory() {
- this.clearHistory = true;
- if (this.appView != null) {
- this.appView.clearHistory();
- }
+ this.clearHistory = true;
+ if (this.appView != null) {
+ this.appView.clearHistory();
+ }
}
@Override
@@ -467,8 +483,8 @@ public class DroidGap extends PhonegapActivity {
* @param Configuration newConfig
*/
public void onConfigurationChanged(Configuration newConfig) {
- //don't reload the current page when the orientation is changed
- super.onConfigurationChanged(newConfig);
+ //don't reload the current page when the orientation is changed
+ super.onConfigurationChanged(newConfig);
}
/**
@@ -479,15 +495,15 @@ public class DroidGap extends PhonegapActivity {
* @return
*/
public boolean getBooleanProperty(String name, boolean defaultValue) {
- Bundle bundle = this.getIntent().getExtras();
- if (bundle == null) {
- return defaultValue;
- }
- Boolean p = (Boolean)bundle.get(name);
- if (p == null) {
- return defaultValue;
- }
- return p.booleanValue();
+ Bundle bundle = this.getIntent().getExtras();
+ if (bundle == null) {
+ return defaultValue;
+ }
+ Boolean p = (Boolean)bundle.get(name);
+ if (p == null) {
+ return defaultValue;
+ }
+ return p.booleanValue();
}
/**
@@ -498,15 +514,15 @@ public class DroidGap extends PhonegapActivity {
* @return
*/
public int getIntegerProperty(String name, int defaultValue) {
- Bundle bundle = this.getIntent().getExtras();
- if (bundle == null) {
- return defaultValue;
- }
- Integer p = (Integer)bundle.get(name);
- if (p == null) {
- return defaultValue;
- }
- return p.intValue();
+ Bundle bundle = this.getIntent().getExtras();
+ if (bundle == null) {
+ return defaultValue;
+ }
+ Integer p = (Integer)bundle.get(name);
+ if (p == null) {
+ return defaultValue;
+ }
+ return p.intValue();
}
/**
@@ -517,15 +533,15 @@ public class DroidGap extends PhonegapActivity {
* @return
*/
public String getStringProperty(String name, String defaultValue) {
- Bundle bundle = this.getIntent().getExtras();
- if (bundle == null) {
- return defaultValue;
- }
- String p = bundle.getString(name);
- if (p == null) {
- return defaultValue;
- }
- return p;
+ Bundle bundle = this.getIntent().getExtras();
+ if (bundle == null) {
+ return defaultValue;
+ }
+ String p = bundle.getString(name);
+ if (p == null) {
+ return defaultValue;
+ }
+ return p;
}
/**
@@ -536,15 +552,15 @@ public class DroidGap extends PhonegapActivity {
* @return
*/
public double getDoubleProperty(String name, double defaultValue) {
- Bundle bundle = this.getIntent().getExtras();
- if (bundle == null) {
- return defaultValue;
- }
- Double p = (Double)bundle.get(name);
- if (p == null) {
- return defaultValue;
- }
- return p.doubleValue();
+ Bundle bundle = this.getIntent().getExtras();
+ if (bundle == null) {
+ return defaultValue;
+ }
+ Double p = (Double)bundle.get(name);
+ if (p == null) {
+ return defaultValue;
+ }
+ return p.doubleValue();
}
/**
@@ -554,7 +570,7 @@ public class DroidGap extends PhonegapActivity {
* @param value
*/
public void setBooleanProperty(String name, boolean value) {
- this.getIntent().putExtra(name, value);
+ this.getIntent().putExtra(name, value);
}
/**
@@ -564,7 +580,7 @@ public class DroidGap extends PhonegapActivity {
* @param value
*/
public void setIntegerProperty(String name, int value) {
- this.getIntent().putExtra(name, value);
+ this.getIntent().putExtra(name, value);
}
/**
@@ -574,7 +590,7 @@ public class DroidGap extends PhonegapActivity {
* @param value
*/
public void setStringProperty(String name, String value) {
- this.getIntent().putExtra(name, value);
+ this.getIntent().putExtra(name, value);
}
/**
@@ -584,7 +600,7 @@ public class DroidGap extends PhonegapActivity {
* @param value
*/
public void setDoubleProperty(String name, double value) {
- this.getIntent().putExtra(name, value);
+ this.getIntent().putExtra(name, value);
}
@Override
@@ -594,20 +610,20 @@ public class DroidGap extends PhonegapActivity {
protected void onPause() {
super.onPause();
if (this.appView == null) {
- return;
+ return;
}
- // Send pause event to JavaScript
- this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
+ // Send pause event to JavaScript
+ this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
- // Forward to plugins
- this.pluginManager.onPause(this.keepRunning);
+ // Forward to plugins
+ this.pluginManager.onPause(this.keepRunning);
// If app doesn't want to run in background
if (!this.keepRunning) {
- // Pause JavaScript timers (including setInterval)
- this.appView.pauseTimers();
+ // Pause JavaScript timers (including setInterval)
+ this.appView.pauseTimers();
}
}
@@ -616,10 +632,10 @@ public class DroidGap extends PhonegapActivity {
* Called when the activity receives a new intent
**/
protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
+ super.onNewIntent(intent);
- //Forward to plugins
- this.pluginManager.onNewIntent(intent);
+ //Forward to plugins
+ this.pluginManager.onNewIntent(intent);
}
@Override
@@ -629,26 +645,26 @@ public class DroidGap extends PhonegapActivity {
protected void onResume() {
super.onResume();
if (this.appView == null) {
- return;
+ return;
}
- // Send resume event to JavaScript
- this.appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};");
+ // Send resume event to JavaScript
+ this.appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};");
- // Forward to plugins
- this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
+ // Forward to plugins
+ this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
// If app doesn't want to run in background
if (!this.keepRunning || this.activityResultKeepRunning) {
- // Restore multitasking state
- if (this.activityResultKeepRunning) {
- this.keepRunning = this.activityResultKeepRunning;
- this.activityResultKeepRunning = false;
- }
+ // Restore multitasking state
+ if (this.activityResultKeepRunning) {
+ this.keepRunning = this.activityResultKeepRunning;
+ this.activityResultKeepRunning = false;
+ }
- // Resume JavaScript timers (including setInterval)
- this.appView.resumeTimers();
+ // Resume JavaScript timers (including setInterval)
+ this.appView.resumeTimers();
}
}
@@ -657,21 +673,21 @@ public class DroidGap extends PhonegapActivity {
* The final call you receive before your activity is destroyed.
*/
public void onDestroy() {
- super.onDestroy();
-
+ super.onDestroy();
+
if (this.appView != null) {
-
- // Make sure pause event is sent if onPause hasn't been called before onDestroy
- this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
+
+ // Make sure pause event is sent if onPause hasn't been called before onDestroy
+ this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
- // Send destroy event to JavaScript
- this.appView.loadUrl("javascript:try{PhoneGap.onDestroy.fire();}catch(e){};");
+ // Send destroy event to JavaScript
+ this.appView.loadUrl("javascript:try{PhoneGap.onDestroy.fire();}catch(e){};");
- // Load blank page so that JavaScript onunload is called
- this.appView.loadUrl("about:blank");
-
- // Forward to plugins
- this.pluginManager.onDestroy();
+ // Load blank page so that JavaScript onunload is called
+ this.appView.loadUrl("about:blank");
+
+ // Forward to plugins
+ this.pluginManager.onDestroy();
}
}
@@ -683,7 +699,7 @@ public class DroidGap extends PhonegapActivity {
* @param className
*/
public void addService(String serviceType, String className) {
- this.pluginManager.addService(serviceType, className);
+ this.pluginManager.addService(serviceType, className);
}
/**
@@ -693,7 +709,7 @@ public class DroidGap extends PhonegapActivity {
* @param message
*/
public void sendJavascript(String statement) {
- this.callbackServer.sendJavascript(statement);
+ this.callbackServer.sendJavascript(statement);
}
@@ -705,79 +721,85 @@ public class DroidGap extends PhonegapActivity {
*
* @param url The url to load.
* @param usePhoneGap Load url in PhoneGap webview.
- * @param clearPrev Clear the activity stack, so new app becomes top of stack
- * @param params DroidGap parameters for new app
+ * @param clearPrev Clear the activity stack, so new app becomes top of stack
+ * @param params DroidGap parameters for new app
* @throws android.content.ActivityNotFoundException
*/
public void showWebPage(String url, boolean usePhoneGap, boolean clearPrev, HashMap params) throws android.content.ActivityNotFoundException {
- Intent intent = null;
- if (usePhoneGap) {
- intent = new Intent().setClass(this, com.phonegap.DroidGap.class);
- intent.putExtra("url", url);
+ Intent intent = null;
+ if (usePhoneGap) {
+ try {
+ intent = new Intent().setClass(this, Class.forName(this.getComponentName().getClassName()));
+ intent.putExtra("url", url);
- // Add parameters
- if (params != null) {
- java.util.Set> s = params.entrySet();
- java.util.Iterator> it = s.iterator();
- while(it.hasNext()) {
- Entry entry = it.next();
- String key = entry.getKey();
- Object value = entry.getValue();
- if (value == null) {
- }
- else if (value.getClass().equals(String.class)) {
- intent.putExtra(key, (String)value);
- }
- else if (value.getClass().equals(Boolean.class)) {
- intent.putExtra(key, (Boolean)value);
- }
- else if (value.getClass().equals(Integer.class)) {
- intent.putExtra(key, (Integer)value);
- }
- }
+ // Add parameters
+ if (params != null) {
+ java.util.Set> s = params.entrySet();
+ java.util.Iterator> it = s.iterator();
+ while(it.hasNext()) {
+ Entry entry = it.next();
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value == null) {
+ }
+ else if (value.getClass().equals(String.class)) {
+ intent.putExtra(key, (String)value);
+ }
+ else if (value.getClass().equals(Boolean.class)) {
+ intent.putExtra(key, (Boolean)value);
+ }
+ else if (value.getClass().equals(Integer.class)) {
+ intent.putExtra(key, (Integer)value);
+ }
+ }
- }
- }
- else {
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- }
- this.startActivity(intent);
-
- // Finish current activity
- if (clearPrev) {
- this.finish();
- }
+ }
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ }
+ }
+ else {
+ intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ }
+ this.startActivity(intent);
+
+ // Finish current activity
+ if (clearPrev) {
+ this.finish();
+ }
}
/**
* Show the spinner. Must be called from the UI thread.
*
- * @param title Title of the dialog
- * @param message The message of the dialog
+ * @param title Title of the dialog
+ * @param message The message of the dialog
*/
public void spinnerStart(final String title, final String message) {
- if (this.spinnerDialog != null) {
- this.spinnerDialog.dismiss();
- this.spinnerDialog = null;
- }
- final DroidGap me = this;
- this.spinnerDialog = ProgressDialog.show(DroidGap.this, title , message, true, true,
- new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- me.spinnerDialog = null;
- }
- });
+ if (this.spinnerDialog != null) {
+ this.spinnerDialog.dismiss();
+ this.spinnerDialog = null;
+ }
+ final DroidGap me = this;
+ this.spinnerDialog = ProgressDialog.show(DroidGap.this, title , message, true, true,
+ new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ me.spinnerDialog = null;
+ }
+ });
}
/**
* Stop spinner.
*/
public void spinnerStop() {
- if (this.spinnerDialog != null) {
- this.spinnerDialog.dismiss();
- this.spinnerDialog = null;
- }
+ if (this.spinnerDialog != null) {
+ this.spinnerDialog.dismiss();
+ this.spinnerDialog = null;
+ }
}
/**
@@ -812,11 +834,11 @@ public class DroidGap extends PhonegapActivity {
dlg.setTitle("Alert");
dlg.setCancelable(false);
dlg.setPositiveButton(android.R.string.ok,
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- result.confirm();
- }
- });
+ new AlertDialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ result.confirm();
+ }
+ });
dlg.create();
dlg.show();
return true;
@@ -837,15 +859,15 @@ public class DroidGap extends PhonegapActivity {
dlg.setTitle("Confirm");
dlg.setCancelable(false);
dlg.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- result.confirm();
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ result.confirm();
}
});
dlg.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- result.cancel();
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ result.cancel();
}
});
dlg.create();
@@ -866,83 +888,91 @@ public class DroidGap extends PhonegapActivity {
*/
@Override
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
- // loaded in webview and not another loaded in an iframe.
- boolean reqOk = false;
- if (url.indexOf(this.ctx.baseUrl) == 0) {
- reqOk = true;
- }
-
- // Calling PluginManager.exec() to call a native service using
- // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
- if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
- JSONArray array;
- try {
- array = new JSONArray(defaultValue.substring(4));
- String service = array.getString(0);
- String action = array.getString(1);
- String callbackId = array.getString(2);
- boolean async = array.getBoolean(3);
- String r = pluginManager.exec(service, action, callbackId, message, async);
- result.confirm(r);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
-
- // Polling for JavaScript messages
- else if (reqOk && defaultValue.equals("gap_poll:")) {
- String r = callbackServer.getJavascript();
- result.confirm(r);
- }
-
- // Calling into CallbackServer
- else if (reqOk && defaultValue.equals("gap_callbackServer:")) {
- String r = "";
- if (message.equals("usePolling")) {
- r = ""+callbackServer.usePolling();
- }
- else if (message.equals("restartServer")) {
- callbackServer.restartServer();
- }
- else if (message.equals("getPort")) {
- r = Integer.toString(callbackServer.getPort());
- }
- else if (message.equals("getToken")) {
- r = callbackServer.getToken();
- }
- result.confirm(r);
- }
-
- // Show dialog
- else {
- final JsPromptResult res = result;
- AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
- dlg.setMessage(message);
- final EditText input = new EditText(this.ctx);
- if (defaultValue != null) {
- input.setText(defaultValue);
- }
- dlg.setView(input);
- dlg.setCancelable(false);
- dlg.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String usertext = input.getText().toString();
- res.confirm(usertext);
- }
- });
- dlg.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- res.cancel();
- }
- });
- dlg.create();
- dlg.show();
- }
- return true;
+
+ // Security check to make sure any requests are coming from the page initially
+ // loaded in webview and not another loaded in an iframe.
+ boolean reqOk = false;
+ if (url.indexOf(this.ctx.baseUrl) == 0) {
+ reqOk = true;
+ }
+
+ // Calling PluginManager.exec() to call a native service using
+ // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
+ if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
+ JSONArray array;
+ try {
+ array = new JSONArray(defaultValue.substring(4));
+ String service = array.getString(0);
+ String action = array.getString(1);
+ String callbackId = array.getString(2);
+ boolean async = array.getBoolean(3);
+ String r = pluginManager.exec(service, action, callbackId, message, async);
+ result.confirm(r);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Polling for JavaScript messages
+ else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
+ String r = callbackServer.getJavascript();
+ result.confirm(r);
+ }
+
+ // Calling into CallbackServer
+ else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) {
+ String r = "";
+ if (message.equals("usePolling")) {
+ r = ""+callbackServer.usePolling();
+ }
+ else if (message.equals("restartServer")) {
+ callbackServer.restartServer();
+ }
+ else if (message.equals("getPort")) {
+ r = Integer.toString(callbackServer.getPort());
+ }
+ else if (message.equals("getToken")) {
+ r = callbackServer.getToken();
+ }
+ result.confirm(r);
+ }
+
+ // PhoneGap JS has initialized, so show webview
+ // (This solves white flash seen when rendering HTML)
+ else if (reqOk && defaultValue != null && defaultValue.equals("gap_init:")) {
+ appView.setVisibility(View.VISIBLE);
+ ctx.spinnerStop();
+ result.confirm("OK");
+ }
+
+ // Show dialog
+ else {
+ final JsPromptResult res = result;
+ AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
+ dlg.setMessage(message);
+ final EditText input = new EditText(this.ctx);
+ if (defaultValue != null) {
+ input.setText(defaultValue);
+ }
+ dlg.setView(input);
+ dlg.setCancelable(false);
+ dlg.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String usertext = input.getText().toString();
+ res.confirm(usertext);
+ }
+ });
+ dlg.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ res.cancel();
+ }
+ });
+ dlg.create();
+ dlg.show();
+ }
+ return true;
}
}
@@ -952,69 +982,69 @@ public class DroidGap extends PhonegapActivity {
*/
public class EclairClient extends GapClient {
- private String TAG = "PhoneGapLog";
- private long MAX_QUOTA = 100 * 1024 * 1024;
+ private String TAG = "PhoneGapLog";
+ private long MAX_QUOTA = 100 * 1024 * 1024;
- /**
- * Constructor.
- *
- * @param ctx
- */
- public EclairClient(Context ctx) {
- super(ctx);
- }
+ /**
+ * Constructor.
+ *
+ * @param ctx
+ */
+ public EclairClient(Context ctx) {
+ super(ctx);
+ }
- /**
- * Handle database quota exceeded notification.
- *
- * @param url
- * @param databaseIdentifier
- * @param currentQuota
- * @param estimatedSize
- * @param totalUsedQuota
- * @param quotaUpdater
- */
- @Override
- public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
- long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
- {
- Log.d(TAG, "event raised onExceededDatabaseQuota estimatedSize: " + Long.toString(estimatedSize) + " currentQuota: " + Long.toString(currentQuota) + " totalUsedQuota: " + Long.toString(totalUsedQuota));
+ /**
+ * Handle database quota exceeded notification.
+ *
+ * @param url
+ * @param databaseIdentifier
+ * @param currentQuota
+ * @param estimatedSize
+ * @param totalUsedQuota
+ * @param quotaUpdater
+ */
+ @Override
+ public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
+ {
+ Log.d(TAG, "event raised onExceededDatabaseQuota estimatedSize: " + Long.toString(estimatedSize) + " currentQuota: " + Long.toString(currentQuota) + " totalUsedQuota: " + Long.toString(totalUsedQuota));
- if( estimatedSize < MAX_QUOTA)
- {
- //increase for 1Mb
- long newQuota = estimatedSize;
- Log.d(TAG, "calling quotaUpdater.updateQuota newQuota: " + Long.toString(newQuota) );
- quotaUpdater.updateQuota(newQuota);
- }
- else
- {
- // Set the quota to whatever it is and force an error
- // TODO: get docs on how to handle this properly
- quotaUpdater.updateQuota(currentQuota);
- }
- }
+ if( estimatedSize < MAX_QUOTA)
+ {
+ //increase for 1Mb
+ long newQuota = estimatedSize;
+ Log.d(TAG, "calling quotaUpdater.updateQuota newQuota: " + Long.toString(newQuota) );
+ quotaUpdater.updateQuota(newQuota);
+ }
+ else
+ {
+ // Set the quota to whatever it is and force an error
+ // TODO: get docs on how to handle this properly
+ quotaUpdater.updateQuota(currentQuota);
+ }
+ }
- // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
- @Override
- public void onConsoleMessage(String message, int lineNumber, String sourceID)
- {
- // This is a kludgy hack!!!!
- Log.d(TAG, sourceID + ": Line " + Integer.toString(lineNumber) + " : " + message);
- }
+ // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
+ @Override
+ public void onConsoleMessage(String message, int lineNumber, String sourceID)
+ {
+ // This is a kludgy hack!!!!
+ Log.d(TAG, sourceID + ": Line " + Integer.toString(lineNumber) + " : " + message);
+ }
- @Override
- /**
- * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
- *
- * @param origin
- * @param callback
- */
- public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
- // TODO Auto-generated method stub
- super.onGeolocationPermissionsShowPrompt(origin, callback);
- callback.invoke(origin, true, false);
- }
+ @Override
+ /**
+ * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+ *
+ * @param origin
+ * @param callback
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+ // TODO Auto-generated method stub
+ super.onGeolocationPermissionsShowPrompt(origin, callback);
+ callback.invoke(origin, true, false);
+ }
}
@@ -1038,204 +1068,221 @@ public class DroidGap extends PhonegapActivity {
* Give the host application a chance to take over the control when a new url
* is about to be loaded in the current WebView.
*
- * @param view The WebView that is initiating the callback.
- * @param url The url to be loaded.
- * @return true to override, false for default behavior
+ * @param view The WebView that is initiating the callback.
+ * @param url The url to be loaded.
+ * @return true to override, false for default behavior
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- // If dialing phone (tel:5551212)
- if (url.startsWith(WebView.SCHEME_TEL)) {
- try {
- Intent intent = new Intent(Intent.ACTION_DIAL);
- intent.setData(Uri.parse(url));
- startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error dialing "+url+": "+ e.toString());
- }
- return true;
- }
-
- // If displaying map (geo:0,0?q=address)
- else if (url.startsWith("geo:")) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error showing map "+url+": "+ e.toString());
- }
- return true;
- }
-
- // If sending email (mailto:abc@corp.com)
- else if (url.startsWith(WebView.SCHEME_MAILTO)) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error sending email "+url+": "+ e.toString());
- }
- return true;
- }
-
- // If sms:5551212?body=This is the message
- else if (url.startsWith("sms:")) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
+ // If dialing phone (tel:5551212)
+ if (url.startsWith(WebView.SCHEME_TEL)) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ intent.setData(Uri.parse(url));
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error dialing "+url+": "+ e.toString());
+ }
+ return true;
+ }
+
+ // If displaying map (geo:0,0?q=address)
+ else if (url.startsWith("geo:")) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error showing map "+url+": "+ e.toString());
+ }
+ return true;
+ }
+
+ // If sending email (mailto:abc@corp.com)
+ else if (url.startsWith(WebView.SCHEME_MAILTO)) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error sending email "+url+": "+ e.toString());
+ }
+ return true;
+ }
+
+ // If sms:5551212?body=This is the message
+ else if (url.startsWith("sms:")) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
- // Get address
- String address = null;
- int parmIndex = url.indexOf('?');
- if (parmIndex == -1) {
- address = url.substring(4);
- }
- else {
- address = url.substring(4, parmIndex);
+ // Get address
+ String address = null;
+ int parmIndex = url.indexOf('?');
+ if (parmIndex == -1) {
+ address = url.substring(4);
+ }
+ else {
+ address = url.substring(4, parmIndex);
- // If body, then set sms body
- Uri uri = Uri.parse(url);
- String query = uri.getQuery();
- if (query != null) {
- if (query.startsWith("body=")) {
- intent.putExtra("sms_body", query.substring(5));
- }
- }
- }
- intent.setData(Uri.parse("sms:"+address));
- intent.putExtra("address", address);
- intent.setType("vnd.android-dir/mms-sms");
- startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error sending sms "+url+":"+ e.toString());
- }
- return true;
- }
+ // If body, then set sms body
+ Uri uri = Uri.parse(url);
+ String query = uri.getQuery();
+ if (query != null) {
+ if (query.startsWith("body=")) {
+ intent.putExtra("sms_body", query.substring(5));
+ }
+ }
+ }
+ intent.setData(Uri.parse("sms:"+address));
+ intent.putExtra("address", address);
+ intent.setType("vnd.android-dir/mms-sms");
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error sending sms "+url+":"+ e.toString());
+ }
+ return true;
+ }
- // All else
- else {
+ // All else
+ else {
- // If our app or file:, then load into our webview
- // NOTE: This replaces our app with new URL. When BACK is pressed,
- // our app is reloaded and restarted. All state is lost.
- if (this.ctx.loadInWebView || url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0) {
- try {
- // Init parameters to new DroidGap activity and propagate existing parameters
- HashMap params = new HashMap();
- params.put("loadingDialog", null);
- if (this.ctx.loadInWebView) {
- params.put("loadInWebView", true);
- }
- params.put("keepRunning", this.ctx.keepRunning);
- params.put("loadUrlTimeoutValue", this.ctx.loadUrlTimeoutValue);
- String errorUrl = this.ctx.getStringProperty("errorUrl", null);
- if (errorUrl != null) {
- params.put("errorUrl", errorUrl);
- }
+ // If our app or file:, then load into our webview
+ // NOTE: This replaces our app with new URL. When BACK is pressed,
+ // our app is reloaded and restarted. All state is lost.
+ if (this.ctx.loadInWebView || url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0) {
+ try {
+ // Init parameters to new DroidGap activity and propagate existing parameters
+ HashMap params = new HashMap();
+ String loadingPage = this.ctx.getStringProperty("loadingPageDialog", null);
+ if (loadingPage != null) {
+ params.put("loadingDialog", loadingPage);
+ params.put("loadingPageDialog", loadingPage);
+ }
+ if (this.ctx.loadInWebView) {
+ params.put("loadInWebView", true);
+ }
+ params.put("keepRunning", this.ctx.keepRunning);
+ params.put("loadUrlTimeoutValue", this.ctx.loadUrlTimeoutValue);
+ String errorUrl = this.ctx.getStringProperty("errorUrl", null);
+ if (errorUrl != null) {
+ params.put("errorUrl", errorUrl);
+ }
+ params.put("backgroundColor", this.ctx.backgroundColor);
- this.ctx.showWebPage(url, true, false, params);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error loading url into DroidGap - "+url+":"+ e.toString());
- }
- }
-
- // If not our application, let default viewer handle
- else {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- System.out.println("Error loading url "+url+":"+ e.toString());
- }
- }
- return true;
- }
+ this.ctx.showWebPage(url, true, false, params);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error loading url into DroidGap - "+url+":"+ e.toString());
+ }
+ }
+
+ // If not our application, let default viewer handle
+ else {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ System.out.println("Error loading url "+url+":"+ e.toString());
+ }
+ }
+ return true;
+ }
}
-
+
/**
* Notify the host application that a page has finished loading.
*
- * @param view The webview initiating the callback.
- * @param url The url of the page.
+ * @param view The webview initiating the callback.
+ * @param url The url of the page.
*/
@Override
public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
+ super.onPageFinished(view, url);
- // Clear timeout flag
- this.ctx.loadUrlTimeout++;
+ // Clear timeout flag
+ this.ctx.loadUrlTimeout++;
- // 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
- // from the JS side when the JS gets to that code.
- if (!url.equals("about:blank")) {
- appView.loadUrl("javascript:try{ PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}");
- }
+ // 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
+ // from the JS side when the JS gets to that code.
+ if (!url.equals("about:blank")) {
+ appView.loadUrl("javascript:try{ PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}");
+ }
- // Make app view visible
- appView.setVisibility(View.VISIBLE);
+ // Make app visible after 2 sec in case there was a JS error and PhoneGap JS never initialized correctly
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ ctx.runOnUiThread(new Runnable() {
+ public void run() {
+ appView.setVisibility(View.VISIBLE);
+ ctx.spinnerStop();
+ }
+ });
+ } catch (InterruptedException e) {
+ }
+ }
+ });
+ t.start();
+
- // Stop "app loading" spinner if showing
- this.ctx.spinnerStop();
-
- // Clear history, so that previous screen isn't there when Back button is pressed
- if (this.ctx.clearHistory) {
- this.ctx.clearHistory = false;
- this.ctx.appView.clearHistory();
- }
-
- // Shutdown if blank loaded
- if (url.equals("about:blank")) {
- if (this.ctx.callbackServer != null) {
- this.ctx.callbackServer.destroy();
- }
- }
+ // Clear history, so that previous screen isn't there when Back button is pressed
+ if (this.ctx.clearHistory) {
+ this.ctx.clearHistory = false;
+ this.ctx.appView.clearHistory();
+ }
+
+ // Shutdown if blank loaded
+ if (url.equals("about:blank")) {
+ if (this.ctx.callbackServer != null) {
+ this.ctx.callbackServer.destroy();
+ }
+ }
}
/**
* 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.
*
- * @param view The WebView that is initiating the callback.
- * @param errorCode The error code corresponding to an ERROR_* value.
- * @param description A String describing the error.
- * @param failingUrl The url that failed to load.
+ * @param view The WebView that is initiating the callback.
+ * @param errorCode The error code corresponding to an ERROR_* value.
+ * @param description A String describing the error.
+ * @param failingUrl The url that failed to load.
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- System.out.println("onReceivedError: Error code="+errorCode+" Description="+description+" URL="+failingUrl);
+ System.out.println("onReceivedError: Error code="+errorCode+" Description="+description+" URL="+failingUrl);
- // Clear timeout flag
- this.ctx.loadUrlTimeout++;
+ // Clear timeout flag
+ this.ctx.loadUrlTimeout++;
- // Stop "app loading" spinner if showing
- this.ctx.spinnerStop();
+ // Stop "app loading" spinner if showing
+ this.ctx.spinnerStop();
- // Handle error
- this.ctx.onReceivedError(errorCode, description, failingUrl);
+ // Handle error
+ this.ctx.onReceivedError(errorCode, description, failingUrl);
}
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- final String packageName = this.ctx.getPackageName();
- final PackageManager pm = this.ctx.getPackageManager();
- ApplicationInfo appInfo;
- try {
- appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
- if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- // debug = true
- handler.proceed();
- return;
- } else {
- // debug = false
- super.onReceivedSslError(view, handler, error);
- }
- } catch (NameNotFoundException e) {
- // When it doubt, lock it out!
- super.onReceivedSslError(view, handler, error);
- }
+ final String packageName = this.ctx.getPackageName();
+ final PackageManager pm = this.ctx.getPackageManager();
+ ApplicationInfo appInfo;
+ try {
+ appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
+ if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ // debug = true
+ handler.proceed();
+ return;
+ } else {
+ // debug = false
+ super.onReceivedSslError(view, handler, error);
+ }
+ } catch (NameNotFoundException e) {
+ // When it doubt, lock it out!
+ super.onReceivedSslError(view, handler, error);
+ }
}
}
@@ -1248,47 +1295,47 @@ public class DroidGap extends PhonegapActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (this.appView == null) {
- return super.onKeyDown(keyCode, event);
+ return super.onKeyDown(keyCode, event);
}
- // If back key
- if (keyCode == KeyEvent.KEYCODE_BACK) {
+ // If back key
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
- // If back key is bound, then send event to JavaScript
- if (this.bound) {
- this.appView.loadUrl("javascript:PhoneGap.fireEvent('backbutton');");
- return true;
- }
+ // If back key is bound, then send event to JavaScript
+ if (this.bound) {
+ this.appView.loadUrl("javascript:PhoneGap.fireDocumentEvent('backbutton');");
+ return true;
+ }
- // If not bound
- else {
+ // If not bound
+ else {
- // Go to previous page in webview if it is possible to go back
- if (this.appView.canGoBack()) {
- this.appView.goBack();
- return true;
- }
+ // Go to previous page in webview if it is possible to go back
+ if (this.appView.canGoBack()) {
+ this.appView.goBack();
+ return true;
+ }
- // If not, then invoke behavior of super class
- else {
- return super.onKeyDown(keyCode, event);
- }
- }
- }
+ // If not, then invoke behavior of super class
+ else {
+ return super.onKeyDown(keyCode, event);
+ }
+ }
+ }
- // If menu key
- else if (keyCode == KeyEvent.KEYCODE_MENU) {
- this.appView.loadUrl("javascript:PhoneGap.fireEvent('menubutton');");
- return true;
- }
+ // If menu key
+ else if (keyCode == KeyEvent.KEYCODE_MENU) {
+ this.appView.loadUrl("javascript:PhoneGap.fireDocumentEvent('menubutton');");
+ return true;
+ }
- // If search key
- else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
- this.appView.loadUrl("javascript:PhoneGap.fireEvent('searchbutton');");
- return true;
- }
+ // If search key
+ else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+ this.appView.loadUrl("javascript:PhoneGap.fireDocumentEvent('searchbutton');");
+ return true;
+ }
- return false;
+ return false;
}
/**
@@ -1297,36 +1344,36 @@ public class DroidGap extends PhonegapActivity {
*
* This is done to eliminate the need to modify DroidGap.java to receive activity results.
*
- * @param intent The intent to start
- * @param requestCode Identifies who to send the result to
+ * @param intent The intent to start
+ * @param requestCode Identifies who to send the result to
*
* @throws RuntimeException
*/
@Override
public void startActivityForResult(Intent intent, int requestCode) throws RuntimeException {
- System.out.println("startActivityForResult(intent,"+requestCode+")");
- super.startActivityForResult(intent, requestCode);
+ System.out.println("startActivityForResult(intent,"+requestCode+")");
+ super.startActivityForResult(intent, requestCode);
}
/**
* Launch an activity for which you would like a result when it finished. When this activity exits,
* your onActivityResult() method will be called.
*
- * @param command The command object
- * @param intent The intent to start
- * @param requestCode The request code that is passed to callback to identify the activity
+ * @param command The command object
+ * @param intent The intent to start
+ * @param requestCode The request code that is passed to callback to identify the activity
*/
public void startActivityForResult(IPlugin command, Intent intent, int requestCode) {
- this.activityResultCallback = command;
- this.activityResultKeepRunning = this.keepRunning;
-
- // If multitasking turned on, then disable it for activities that return results
- if (command != null) {
- this.keepRunning = false;
- }
-
- // Start activity
- super.startActivityForResult(intent, requestCode);
+ this.activityResultCallback = command;
+ this.activityResultKeepRunning = this.keepRunning;
+
+ // If multitasking turned on, then disable it for activities that return results
+ if (command != null) {
+ this.keepRunning = false;
+ }
+
+ // Start activity
+ super.startActivityForResult(intent, requestCode);
}
@Override
@@ -1334,52 +1381,52 @@ public class DroidGap extends PhonegapActivity {
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
- * @param requestCode The request code originally supplied to startActivityForResult(),
- * allowing you to identify who this result came from.
- * @param resultCode The integer result code returned by the child activity through its setResult().
- * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+ * @param requestCode The request code originally supplied to startActivityForResult(),
+ * allowing you to identify who this result came from.
+ * @param resultCode The integer result code returned by the child activity through its setResult().
+ * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- IPlugin callback = this.activityResultCallback;
- if (callback != null) {
- callback.onActivityResult(requestCode, resultCode, intent);
- }
+ super.onActivityResult(requestCode, resultCode, intent);
+ IPlugin callback = this.activityResultCallback;
+ if (callback != null) {
+ callback.onActivityResult(requestCode, resultCode, intent);
+ }
}
@Override
public void setActivityResultCallback(IPlugin plugin) {
- this.activityResultCallback = plugin;
+ this.activityResultCallback = plugin;
}
/**
* 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.
*
- * @param errorCode The error code corresponding to an ERROR_* value.
- * @param description A String describing the error.
- * @param failingUrl The url that failed to load.
+ * @param errorCode The error code corresponding to an ERROR_* value.
+ * @param description A String describing the error.
+ * @param failingUrl The url that failed to load.
*/
public void onReceivedError(int errorCode, String description, String failingUrl) {
- final DroidGap me = this;
+ final DroidGap me = this;
- // If errorUrl specified, then load it
- final String errorUrl = me.getStringProperty("errorUrl", null);
- if ((errorUrl != null) && errorUrl.startsWith("file://") && (!failingUrl.equals(errorUrl))) {
+ // If errorUrl specified, then load it
+ final String errorUrl = me.getStringProperty("errorUrl", null);
+ if ((errorUrl != null) && errorUrl.startsWith("file://") && (!failingUrl.equals(errorUrl))) {
- // Load URL on UI thread
- me.runOnUiThread(new Runnable() {
- public void run() {
- me.appView.loadUrl(errorUrl);
- }
- });
- }
+ // Load URL on UI thread
+ me.runOnUiThread(new Runnable() {
+ public void run() {
+ me.appView.loadUrl(errorUrl);
+ }
+ });
+ }
- // If not, then display error dialog
- else {
- me.appView.loadUrl("about:blank");
- me.displayError("Application Error", description + " ("+failingUrl+")", "OK", true);
- }
+ // If not, then display error dialog
+ else {
+ me.appView.loadUrl("about:blank");
+ me.displayError("Application Error", description + " ("+failingUrl+")", "OK", true);
+ }
}
/**
@@ -1391,26 +1438,26 @@ public class DroidGap extends PhonegapActivity {
* @param exit
*/
public void displayError(final String title, final String message, final String button, final boolean exit) {
- final DroidGap me = this;
- me.runOnUiThread(new Runnable() {
- public void run() {
- AlertDialog.Builder dlg = new AlertDialog.Builder(me);
- dlg.setMessage(message);
- dlg.setTitle(title);
- dlg.setCancelable(false);
- dlg.setPositiveButton(button,
- new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- if (exit) {
- me.finish();
- }
- }
- });
- dlg.create();
- dlg.show();
- }
- });
+ final DroidGap me = this;
+ me.runOnUiThread(new Runnable() {
+ public void run() {
+ AlertDialog.Builder dlg = new AlertDialog.Builder(me);
+ dlg.setMessage(message);
+ dlg.setTitle(title);
+ dlg.setCancelable(false);
+ dlg.setPositiveButton(button,
+ new AlertDialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ if (exit) {
+ me.finish();
+ }
+ }
+ });
+ dlg.create();
+ dlg.show();
+ }
+ });
}
/**
@@ -1419,77 +1466,77 @@ public class DroidGap extends PhonegapActivity {
*/
class LinearLayoutSoftKeyboardDetect extends LinearLayout {
- private static final String LOG_TAG = "SoftKeyboardDetect";
-
- 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 screenWidth = 0;
- private int screenHeight = 0;
-
- public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
- super(context);
- screenWidth = width;
- screenHeight = height;
- }
+ private static final String LOG_TAG = "SoftKeyboardDetect";
+
+ 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 screenWidth = 0;
+ private int screenHeight = 0;
+
+ public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
+ super(context);
+ screenWidth = width;
+ screenHeight = height;
+ }
- @Override
- /**
- * Start listening to new measurement events. Fire events when the height
- * gets smaller fire a show keyboard event and when height gets bigger fire
- * a hide keyboard event.
- *
- * Note: We are using callbackServer.sendJavascript() instead of
- * this.appView.loadUrl() as changing the URL of the app would cause the
- * soft keyboard to go away.
- *
- * @param widthMeasureSpec
- * @param heightMeasureSpec
- */
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- Log.d(LOG_TAG, "We are in our onMeasure method");
+ @Override
+ /**
+ * Start listening to new measurement events. Fire events when the height
+ * gets smaller fire a show keyboard event and when height gets bigger fire
+ * a hide keyboard event.
+ *
+ * Note: We are using callbackServer.sendJavascript() instead of
+ * this.appView.loadUrl() as changing the URL of the app would cause the
+ * soft keyboard to go away.
+ *
+ * @param widthMeasureSpec
+ * @param heightMeasureSpec
+ */
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ Log.d(LOG_TAG, "We are in our onMeasure method");
- // Get the current height of the visible part of the screen.
- // This height will not included the status bar.
- int height = MeasureSpec.getSize(heightMeasureSpec);
- int width = MeasureSpec.getSize(widthMeasureSpec);
-
- Log.d(LOG_TAG, "Old Height = " + oldHeight);
- Log.d(LOG_TAG, "Height = " + height);
- Log.d(LOG_TAG, "Old Width = " + oldWidth);
- Log.d(LOG_TAG, "Width = " + width);
-
-
- // If the oldHeight = 0 then this is the first measure event as the app starts up.
- // If oldHeight == height then we got a measurement change that doesn't affect us.
- if (oldHeight == 0 || oldHeight == height) {
- Log.d(LOG_TAG, "Ignore this event");
- }
- // Account for orientation change and ignore this event/Fire orientation change
- else if(screenHeight == width)
- {
- int tmp_var = screenHeight;
- screenHeight = screenWidth;
- screenWidth = tmp_var;
- Log.d(LOG_TAG, "Orientation Change");
- }
- // If the height as gotten bigger then we will assume the soft keyboard has
- // gone away.
- else if (height > oldHeight) {
- Log.d(LOG_TAG, "Throw hide keyboard event");
- callbackServer.sendJavascript("PhoneGap.fireEvent('hidekeyboard');");
- }
- // If the height as gotten smaller then we will assume the soft keyboard has
- // been displayed.
- else if (height < oldHeight) {
- Log.d(LOG_TAG, "Throw show keyboard event");
- callbackServer.sendJavascript("PhoneGap.fireEvent('showkeyboard');");
- }
+ // Get the current height of the visible part of the screen.
+ // This height will not included the status bar.
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ Log.d(LOG_TAG, "Old Height = " + oldHeight);
+ Log.d(LOG_TAG, "Height = " + height);
+ Log.d(LOG_TAG, "Old Width = " + oldWidth);
+ Log.d(LOG_TAG, "Width = " + width);
+
+
+ // If the oldHeight = 0 then this is the first measure event as the app starts up.
+ // If oldHeight == height then we got a measurement change that doesn't affect us.
+ if (oldHeight == 0 || oldHeight == height) {
+ Log.d(LOG_TAG, "Ignore this event");
+ }
+ // Account for orientation change and ignore this event/Fire orientation change
+ else if(screenHeight == width)
+ {
+ int tmp_var = screenHeight;
+ screenHeight = screenWidth;
+ screenWidth = tmp_var;
+ Log.d(LOG_TAG, "Orientation Change");
+ }
+ // If the height as gotten bigger then we will assume the soft keyboard has
+ // gone away.
+ else if (height > oldHeight) {
+ Log.d(LOG_TAG, "Throw hide keyboard event");
+ callbackServer.sendJavascript("PhoneGap.fireDocumentEvent('hidekeyboard');");
+ }
+ // If the height as gotten smaller then we will assume the soft keyboard has
+ // been displayed.
+ else if (height < oldHeight) {
+ Log.d(LOG_TAG, "Throw show keyboard event");
+ callbackServer.sendJavascript("PhoneGap.fireDocumentEvent('showkeyboard');");
+ }
- // Update the old height for the next event
- oldHeight = height;
- oldWidth = width;
- }
+ // Update the old height for the next event
+ oldHeight = height;
+ oldWidth = width;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/com/phonegap/ExifHelper.java b/framework/src/com/phonegap/ExifHelper.java
new file mode 100644
index 00000000..cd9e0a0c
--- /dev/null
+++ b/framework/src/com/phonegap/ExifHelper.java
@@ -0,0 +1,153 @@
+/*
+ * PhoneGap is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011, IBM Corporation
+ */
+package com.phonegap;
+
+import java.io.IOException;
+
+import android.media.ExifInterface;
+
+public class ExifHelper {
+ private String aperature = null;
+ private String datetime = null;
+ private String exposureTime = null;
+ private String flash = null;
+ private String focalLength = null;
+ private String gpsAltitude = null;
+ private String gpsAltitudeRef = null;
+ private String gpsDateStamp = null;
+ private String gpsLatitude = null;
+ private String gpsLatitudeRef = null;
+ private String gpsLongitude = null;
+ private String gpsLongitudeRef = null;
+ private String gpsProcessingMethod = null;
+ private String gpsTimestamp = null;
+ private String iso = null;
+ private String make = null;
+ private String model = null;
+ private String orientation = null;
+ private String whiteBalance = null;
+
+ private ExifInterface inFile = null;
+ private ExifInterface outFile = null;
+
+ /**
+ * The file before it is compressed
+ *
+ * @param filePath
+ * @throws IOException
+ */
+ public void createInFile(String filePath) throws IOException {
+ this.inFile = new ExifInterface(filePath);
+ }
+
+ /**
+ * The file after it has been compressed
+ *
+ * @param filePath
+ * @throws IOException
+ */
+ public void createOutFile(String filePath) throws IOException {
+ this.outFile = new ExifInterface(filePath);
+ }
+
+ /**
+ * Reads all the EXIF data from the input file.
+ */
+ public void readExifData() {
+ this.aperature = inFile.getAttribute(ExifInterface.TAG_APERTURE);
+ this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
+ this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
+ this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
+ this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
+ this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
+ this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
+ this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
+ this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
+ this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
+ this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
+ this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
+ this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
+ this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
+ this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
+ this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
+ this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
+ this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
+ this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
+ }
+
+ /**
+ * Writes the previously stored EXIF data to the output file.
+ *
+ * @throws IOException
+ */
+ public void writeExifData() throws IOException {
+ // Don't try to write to a null file
+ if (this.outFile == null) {
+ return;
+ }
+
+ if (this.aperature != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperature);
+ }
+ if (this.datetime != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
+ }
+ if (this.exposureTime != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
+ }
+ if (this.flash != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
+ }
+ if (this.focalLength != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
+ }
+ if (this.gpsAltitude != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
+ }
+ if (this.gpsAltitudeRef != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
+ }
+ if (this.gpsDateStamp != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
+ }
+ if (this.gpsLatitude != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
+ }
+ if (this.gpsLatitudeRef != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
+ }
+ if (this.gpsLongitude != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
+ }
+ if (this.gpsLongitudeRef != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
+ }
+ if (this.gpsProcessingMethod != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
+ }
+ if (this.gpsTimestamp != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
+ }
+ if (this.iso != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
+ }
+ if (this.make != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
+ }
+ if (this.model != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
+ }
+ if (this.orientation != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
+ }
+ if (this.whiteBalance != null) {
+ this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
+ }
+
+ this.outFile.saveAttributes();
+ }
+}
\ No newline at end of file
diff --git a/framework/src/com/phonegap/FileUtils.java b/framework/src/com/phonegap/FileUtils.java
index 240a507e..6d6ad655 100755
--- a/framework/src/com/phonegap/FileUtils.java
+++ b/framework/src/com/phonegap/FileUtils.java
@@ -25,6 +25,7 @@ import android.provider.MediaStore;
import android.util.Log;
import android.webkit.MimeTypeMap;
+import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import com.phonegap.file.EncodingException;
@@ -39,7 +40,8 @@ import com.phonegap.file.TypeMismatchException;
*/
public class FileUtils extends Plugin {
private static final String LOG_TAG = "FileUtils";
-
+ private static final String _DATA = "_data"; // The column name where the file path is stored
+
public static int NOT_FOUND_ERR = 1;
public static int SECURITY_ERR = 2;
public static int ABORT_ERR = 3;
@@ -988,5 +990,19 @@ public class FileUtils extends Plugin {
return new FileInputStream(path);
}
}
+
+ /**
+ * Queries the media store to find out what the file path is for the Uri we supply
+ *
+ * @param contentUri the Uri of the audio/image/video
+ * @param ctx the current applicaiton context
+ * @return the full path to the file
+ */
+ protected static String getRealPathFromURI(Uri contentUri, PhonegapActivity ctx) {
+ String[] proj = { _DATA };
+ Cursor cursor = ctx.managedQuery(contentUri, proj, null, null, null);
+ int column_index = cursor.getColumnIndexOrThrow(_DATA);
+ cursor.moveToFirst();
+ return cursor.getString(column_index);
+ }
}
-
diff --git a/framework/src/com/phonegap/NetworkManager.java b/framework/src/com/phonegap/NetworkManager.java
index 19a8a5c6..c462436b 100755
--- a/framework/src/com/phonegap/NetworkManager.java
+++ b/framework/src/com/phonegap/NetworkManager.java
@@ -22,201 +22,209 @@ import android.net.NetworkInfo;
import android.util.Log;
public class NetworkManager extends Plugin {
-
+
public static int NOT_REACHABLE = 0;
- public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
- public static int REACHABLE_VIA_WIFI_NETWORK = 2;
+ public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
+ public static int REACHABLE_VIA_WIFI_NETWORK = 2;
- public static final String WIFI = "wifi";
- public static final String WIMAX = "wimax";
- // mobile
- public static final String MOBILE = "mobile";
- // 2G network types
- public static final String GSM = "gsm";
- public static final String GPRS = "gprs";
- public static final String EDGE = "edge";
- // 3G network types
- public static final String CDMA = "cdma";
- public static final String UMTS = "umts";
- // 4G network types
- public static final String LTE = "lte";
- public static final String UMB = "umb";
- // return types
- public static final String TYPE_UNKNOWN = "unknown";
- public static final String TYPE_ETHERNET = "ethernet";
- public static final String TYPE_WIFI = "wifi";
- public static final String TYPE_2G = "2g";
- public static final String TYPE_3G = "3g";
- public static final String TYPE_4G = "4g";
- public static final String TYPE_NONE = "none";
-
- private static final String LOG_TAG = "NetworkManager";
+ public static final String WIFI = "wifi";
+ public static final String WIMAX = "wimax";
+ // mobile
+ public static final String MOBILE = "mobile";
+ // 2G network types
+ public static final String GSM = "gsm";
+ public static final String GPRS = "gprs";
+ public static final String EDGE = "edge";
+ // 3G network types
+ public static final String CDMA = "cdma";
+ public static final String UMTS = "umts";
+ public static final String HSPA = "hspa";
+ public static final String HSUPA = "hsupa";
+ public static final String HSDPA = "hsdpa";
+ // 4G network types
+ public static final String LTE = "lte";
+ public static final String UMB = "umb";
+ public static final String HSPA_PLUS = "hspa+";
+ // return types
+ public static final String TYPE_UNKNOWN = "unknown";
+ public static final String TYPE_ETHERNET = "ethernet";
+ public static final String TYPE_WIFI = "wifi";
+ public static final String TYPE_2G = "2g";
+ public static final String TYPE_3G = "3g";
+ public static final String TYPE_4G = "4g";
+ public static final String TYPE_NONE = "none";
+
+ private static final String LOG_TAG = "NetworkManager";
- private String connectionCallbackId;
+ private String connectionCallbackId;
- ConnectivityManager sockMan;
- BroadcastReceiver receiver;
-
- /**
- * Constructor.
- */
- public NetworkManager() {
- this.receiver = null;
- }
+ ConnectivityManager sockMan;
+ BroadcastReceiver receiver;
+
+ /**
+ * Constructor.
+ */
+ public NetworkManager() {
+ this.receiver = null;
+ }
- /**
- * 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(PhonegapActivity ctx) {
- super.setContext(ctx);
- this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
- this.connectionCallbackId = null;
-
- // We need to listen to connectivity events to update navigator.connection
- IntentFilter intentFilter = new IntentFilter() ;
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- if (this.receiver == null) {
- this.receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
- }
- };
- ctx.registerReceiver(this.receiver, intentFilter);
- }
+ /**
+ * 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(PhonegapActivity ctx) {
+ super.setContext(ctx);
+ this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
+ this.connectionCallbackId = null;
+
+ // We need to listen to connectivity events to update navigator.connection
+ IntentFilter intentFilter = new IntentFilter() ;
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ if (this.receiver == null) {
+ this.receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
+ }
+ };
+ ctx.registerReceiver(this.receiver, intentFilter);
+ }
- }
-
- /**
- * 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.INVALID_ACTION;
- String result = "Unsupported Operation: " + action;
-
- if (action.equals("getConnectionInfo")) {
- this.connectionCallbackId = callbackId;
- NetworkInfo info = sockMan.getActiveNetworkInfo();
- PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
- pluginResult.setKeepCallback(true);
- return pluginResult;
- }
-
- 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.INVALID_ACTION;
+ String result = "Unsupported Operation: " + action;
+
+ if (action.equals("getConnectionInfo")) {
+ this.connectionCallbackId = callbackId;
+ NetworkInfo info = sockMan.getActiveNetworkInfo();
+ PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
+ pluginResult.setKeepCallback(true);
+ return pluginResult;
+ }
+
+ return new PluginResult(status, result);
+ }
- /**
- * 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) {
- // All methods take a while, so always use async
- return false;
- }
-
- /**
- * Stop network receiver.
- */
- public void onDestroy() {
- if (this.receiver != null) {
- try {
- this.ctx.unregisterReceiver(this.receiver);
- } catch (Exception e) {
- Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
- }
- }
- }
+ /**
+ * 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) {
+ // All methods take a while, so always use async
+ return false;
+ }
+
+ /**
+ * Stop network receiver.
+ */
+ public void onDestroy() {
+ if (this.receiver != null) {
+ try {
+ this.ctx.unregisterReceiver(this.receiver);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
+ }
+ }
+ }
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
- /**
- * Updates the JavaScript side whenever the connection changes
- *
- * @param info the current active network info
- * @return
- */
- private void updateConnectionInfo(NetworkInfo info) {
+ /**
+ * Updates the JavaScript side whenever the connection changes
+ *
+ * @param info the current active network info
+ * @return
+ */
+ private void updateConnectionInfo(NetworkInfo info) {
// send update to javascript "navigator.network.connection"
sendUpdate(this.getConnectionInfo(info));
- }
+ }
- /**
- * Get the latest network connection information
- *
- * @param info the current active network info
- * @return a JSONObject that represents the network info
- */
- private String getConnectionInfo(NetworkInfo info) {
- String type = TYPE_NONE;
- if (info != null) {
- // If we are not connected to any network set type to none
- if (!info.isConnected()) {
- type = TYPE_NONE;
- }
- else {
- type = getType(info);
- }
- }
+ /**
+ * Get the latest network connection information
+ *
+ * @param info the current active network info
+ * @return a JSONObject that represents the network info
+ */
+ private String getConnectionInfo(NetworkInfo info) {
+ String type = TYPE_NONE;
+ if (info != null) {
+ // If we are not connected to any network set type to none
+ if (!info.isConnected()) {
+ type = TYPE_NONE;
+ }
+ else {
+ type = getType(info);
+ }
+ }
return type;
- }
-
- /**
- * Create a new plugin result and send it back to JavaScript
- *
- * @param connection the network info to set as navigator.connection
- */
- private void sendUpdate(String type) {
- PluginResult result = new PluginResult(PluginResult.Status.OK, type);
- result.setKeepCallback(true);
- this.success(result, this.connectionCallbackId);
- }
-
- /**
- * Determine the type of connection
- *
- * @param info the network info so we can determine connection type.
- * @return the type of mobile network we are on
- */
- private String getType(NetworkInfo info) {
- if (info != null) {
- String type = info.getTypeName();
+ }
+
+ /**
+ * Create a new plugin result and send it back to JavaScript
+ *
+ * @param connection the network info to set as navigator.connection
+ */
+ private void sendUpdate(String type) {
+ PluginResult result = new PluginResult(PluginResult.Status.OK, type);
+ result.setKeepCallback(true);
+ this.success(result, this.connectionCallbackId);
+ }
+
+ /**
+ * Determine the type of connection
+ *
+ * @param info the network info so we can determine connection type.
+ * @return the type of mobile network we are on
+ */
+ private String getType(NetworkInfo info) {
+ if (info != null) {
+ String type = info.getTypeName();
if (type.toLowerCase().equals(WIFI)) {
return TYPE_WIFI;
}
else if (type.toLowerCase().equals(MOBILE)) {
- type = info.getSubtypeName();
- if (type.toLowerCase().equals(GSM) ||
- type.toLowerCase().equals(GPRS) ||
- type.toLowerCase().equals(EDGE)) {
- return TYPE_2G;
- }
- else if (type.toLowerCase().equals(CDMA) ||
- type.toLowerCase().equals(UMTS)) {
- return TYPE_3G;
- }
- else if (type.toLowerCase().equals(LTE) ||
- type.toLowerCase().equals(UMB)) {
- return TYPE_4G;
- }
- }
- }
- else {
- return TYPE_NONE;
- }
- return TYPE_UNKNOWN;
- }
+ type = info.getSubtypeName();
+ if (type.toLowerCase().equals(GSM) ||
+ type.toLowerCase().equals(GPRS) ||
+ type.toLowerCase().equals(EDGE)) {
+ return TYPE_2G;
+ }
+ else if (type.toLowerCase().equals(CDMA) ||
+ type.toLowerCase().equals(UMTS) ||
+ type.toLowerCase().equals(HSUPA) ||
+ type.toLowerCase().equals(HSDPA) ||
+ type.toLowerCase().equals(HSPA)) {
+ return TYPE_3G;
+ }
+ else if (type.toLowerCase().equals(LTE) ||
+ type.toLowerCase().equals(UMB) ||
+ type.toLowerCase().equals(HSPA_PLUS)) {
+ return TYPE_4G;
+ }
+ }
+ }
+ else {
+ return TYPE_NONE;
+ }
+ return TYPE_UNKNOWN;
+ }
}