diff --git a/tutorial/accelerometer.html b/tutorial/accelerometer.html new file mode 100755 index 00000000..84441968 --- /dev/null +++ b/tutorial/accelerometer.html @@ -0,0 +1,232 @@ + + + + + + PhoneGap + + + + + + + + + + + +
+ + Back + + Accelerometer +
+ + +
+ +
+ + +
+

Start

+
+ + + + + + + + diff --git a/tutorial/beep.wav b/tutorial/beep.wav new file mode 100755 index 00000000..05f5997f Binary files /dev/null and b/tutorial/beep.wav differ diff --git a/tutorial/contacts.html b/tutorial/contacts.html new file mode 100644 index 00000000..09cc137c --- /dev/null +++ b/tutorial/contacts.html @@ -0,0 +1,176 @@ + + + + + + PhoneGap + + + + + + + + +
+ + Back + + Contacts +
+ + +

Getting contact count ...

+ + +
+

Pick a Contact

+
+
+ + + + +
+

Get first 10 contacts

+
+
+ + + + + + diff --git a/tutorial/geolocation.html b/tutorial/geolocation.html new file mode 100755 index 00000000..4e6c5d15 --- /dev/null +++ b/tutorial/geolocation.html @@ -0,0 +1,176 @@ + + + + + + PhoneGap + + + + + + + +
+ + Back + + GeoLocation +
+
+ +
Getting your current location ...
+ +

Find who are tweeting within 1 mile radius of where you are!

+ + + +
+ +
+ +
+ + diff --git a/tutorial/images/FoggyRocks.png b/tutorial/images/FoggyRocks.png new file mode 100644 index 00000000..25975562 Binary files /dev/null and b/tutorial/images/FoggyRocks.png differ diff --git a/tutorial/images/TutBG.png b/tutorial/images/TutBG.png new file mode 100644 index 00000000..db3a2069 Binary files /dev/null and b/tutorial/images/TutBG.png differ diff --git a/tutorial/images/back_button.png b/tutorial/images/back_button.png new file mode 100644 index 00000000..ca0a70a6 Binary files /dev/null and b/tutorial/images/back_button.png differ diff --git a/tutorial/images/back_button_clicked.png b/tutorial/images/back_button_clicked.png new file mode 100644 index 00000000..ca68ce2e Binary files /dev/null and b/tutorial/images/back_button_clicked.png differ diff --git a/tutorial/images/backgroundStripes.png b/tutorial/images/backgroundStripes.png new file mode 100755 index 00000000..cab0e983 Binary files /dev/null and b/tutorial/images/backgroundStripes.png differ diff --git a/tutorial/images/bar_large.png b/tutorial/images/bar_large.png new file mode 100644 index 00000000..354c722f Binary files /dev/null and b/tutorial/images/bar_large.png differ diff --git a/tutorial/images/bar_media.png b/tutorial/images/bar_media.png new file mode 100644 index 00000000..5d7f9c34 Binary files /dev/null and b/tutorial/images/bar_media.png differ diff --git a/tutorial/images/header.png b/tutorial/images/header.png new file mode 100644 index 00000000..f78a44be Binary files /dev/null and b/tutorial/images/header.png differ diff --git a/tutorial/images/header2.png b/tutorial/images/header2.png new file mode 100644 index 00000000..8ad80e5f Binary files /dev/null and b/tutorial/images/header2.png differ diff --git a/tutorial/images/header3.png b/tutorial/images/header3.png new file mode 100644 index 00000000..07d45c8f Binary files /dev/null and b/tutorial/images/header3.png differ diff --git a/tutorial/images/list_arrow.png b/tutorial/images/list_arrow.png new file mode 100644 index 00000000..9f68c719 Binary files /dev/null and b/tutorial/images/list_arrow.png differ diff --git a/tutorial/images/list_item_selected_bg.png b/tutorial/images/list_item_selected_bg.png new file mode 100644 index 00000000..6bb0ad05 Binary files /dev/null and b/tutorial/images/list_item_selected_bg.png differ diff --git a/tutorial/images/on_off_bg.png b/tutorial/images/on_off_bg.png new file mode 100644 index 00000000..36b2eac9 Binary files /dev/null and b/tutorial/images/on_off_bg.png differ diff --git a/tutorial/images/selection.png b/tutorial/images/selection.png new file mode 100644 index 00000000..537e3f0b Binary files /dev/null and b/tutorial/images/selection.png differ diff --git a/tutorial/index.html b/tutorial/index.html new file mode 100755 index 00000000..7db14d67 --- /dev/null +++ b/tutorial/index.html @@ -0,0 +1,72 @@ + + + + + + PhoneGap + + + + + + +
+ PhoneGap Tutorial +
+ + + + +
+

Accelerometer

+
+ + +
+

Notification

+
+
+ + +
+

Contacts

+
+
+ + +
+

GeoLocation

+
+
+ + +
Form Inputs +
+
+ + + +
+

Media

+
+
+ + + + diff --git a/tutorial/inputs.html b/tutorial/inputs.html new file mode 100755 index 00000000..67a80eef --- /dev/null +++ b/tutorial/inputs.html @@ -0,0 +1,98 @@ + + + + + + PhoneGap + + + + + + + + +
+ + Back + + Form Inputs +
+ +
+
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ +
+ + + + + + diff --git a/tutorial/master.css b/tutorial/master.css new file mode 100755 index 00000000..dddb7cdb --- /dev/null +++ b/tutorial/master.css @@ -0,0 +1,304 @@ + +body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6 +{ + margin: 0pt; + padding: 0pt; +} + + + +body +{ + background:#000 url(images/TutBG.png) repeat-y fixed 0 0; + color:#666; + font-family:Helvetica,'Lucida Grande',sans-serif; + line-height:1.5em; + margin:0px; + margin-bottom:20px; + +} + +#header{ + position: relative; + left: 0px; + top: 0px; + height: 44px; + font-size: 16pt; + border-top-width: 0px; + border-right-width: 1px; + border-bottom-width: 0px; + border-left-width: 1px; + width: auto; + margin-right: 0px; + margin-left: 0px; + background: url( header.png ); +} + +.header_title{ + text-align: center; + position: relative; + font-weight: bold; + color: rgb(255, 255, 255); + text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0px; +} + +.view{ + background: url( images/backgroundStripes.png ); + background-repeat: repeat; + min-height: 406px; +} + +.topBar +{ + color:#eee; + font-size:1.2em; + text-align:center; + margin:0; + margin-top:0px; + padding:0; + background-image: url( 'images/header.png' ); + background-repeat: repeat-x; + height:44px; + text-height:44px; +} + + +.pageTitle +{ + text-align: center; + color:#FFF; + line-height:44px; +} + +.back_button +{ + font-weight: bold; + font-size: 12px; + color: rgb(255, 255, 255); + text-shadow: rgba(0, 0, 0, 0.6) 0px -1px 0px; + text-align: center; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + height: 22px; + padding-top: 4px; + padding-bottom: 4px; + width: 60px; + line-height:22px; + right: auto; + bottom: auto; + margin-top: 0px; + position:absolute; + left:4px; + top:11px; + -webkit-border-image: url(images/back_button.png) 0 5 0 16 / 1px 5px 1px 16px stretch stretch; +} + +.list +{ + margin-top: 5px; +} + +.list li{ + width: 290px; + height: 20px; + background-color: #FFF; + border-left: 1px solid #AAA; + border-right: 1px solid #AAA; + border-bottom: 1px solid #AAA; + + list-style-type: none; + padding: 12px 5px 10px 5px; + margin-left: -36px; +} + +.list li.active{ + background-image: url( 'selection.png' ); + background-repeat: repeat-x; + background-color: #194fdb !important; +} + +.list li:first-of-type{ + border-top: 1px solid #AAA; + -webkit-border-top-right-radius: 8px 8px; + -webkit-border-top-left-radius: 8px 8px; +} + +.list li:last-of-type{ + border-top: none; + border-bottom: 1px solid #AAA; + + -webkit-border-bottom-left-radius: 8px 8px; + -webkit-border-bottom-right-radius: 8px 8px; +} + +.list li:only-of-type{ + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; + + -webkit-border-top-right-radius: 8px 8px; + -webkit-border-top-left-radius: 8px 8px; + -webkit-border-bottom-left-radius: 8px 8px; + -webkit-border-bottom-right-radius: 8px 8px; + +} + +.list .list_label{ + font-weight: bold; + color: #000; + text-align: left; + width: 145px; + float: left; +} + +.list .list_value{ + color: #6e82a8; + text-align: right; + width: 140px; + float: right; +} + +.list .selected_item{ + color: #4c566c; +} + +.list_section_label{ + font-size: 16px; + font-weight: bold; + margin-left: 15px; + text-shadow: rgba(255, 255, 255, 1) 0px 1px 0px; + color: #4c566c; +} + +.list_section_note{ + font-size: 14px; + margin-left: 15px; + text-shadow: rgba(255, 255, 255, 1) 0px 1px 0px; + color: #4c566c; + text-align: center; + margin-bottom: 15px; + margin-top: -5px; +} + + + +.item +{ + background:rgba(64,64,64,0.5); + border: 1px solid rgba(128,128,128,0.5); + -webkit-border-radius: 5px; + border-radius: 5px; + clear:both; + margin:15px 6px 0; + width:295px; + padding:4px 0px 2px 10px; +} + +a +{ + color:#FFF; + text-decoration:none; +} + + +#info{ + background:#ffa; + border: 1px solid #ffd324; + -webkit-border-radius: 5px; + border-radius: 5px; + clear:both; + margin:15px 6px 0; + width:295px; + padding:4px 0px 2px 10px; +} + +#info h4{ + font-size:.95em; + margin:0; + padding:0; +} + +#stage.theme{ + padding-top:3px; +} + +/* Definition List */ +#Page1 > dl{ + padding-top:10px; + clear:both; + margin:0; + list-style-type:none; + padding-left:10px; + overflow:auto; +} + +#Page1 > dl > dt{ + font-weight:bold; + float:left; + margin-left:5px; +} + +#Page1 > dl > dd{ + width:45px; + float:left; + color:#a87; + font-weight:bold; +} + +/* Content Styling */ +h1, h2, p{ + margin:1em 0 .5em 13px; +} + +h1{ + color:#eee; + font-size:1.6em; + text-align:center; + margin:0; + margin-top:15px; + padding:0; +} + +h2{ + clear:both; + margin:0; + padding:3px; + font-size:1em; + text-align:center; +} + + + +/* Stage Buttons */ +#stage.theme a.btn +{ + border: 1px solid #555; + -webkit-border-radius: 5px; + border-radius: 5px; + text-align:center; + display:block; + float:left; + background:#444; + width:150px; + color:#9ab; + font-size:1.1em; + text-decoration:none; + padding:1.2em 0; + margin:3px 0px 3px 5px; +} + +a.btn.large +{ + width:64px; + height:32px; + padding:1.2em 0; +} + + + + + + + + + diff --git a/tutorial/media.html b/tutorial/media.html new file mode 100755 index 00000000..b00cdd6e --- /dev/null +++ b/tutorial/media.html @@ -0,0 +1,111 @@ + + + + + + PhoneGap + + + + + + + + +
+ + Back + + Media +
+ +

percBass.wav

+ +
+

Play

+
+
+ + + + + + diff --git a/tutorial/notification.html b/tutorial/notification.html new file mode 100755 index 00000000..42afaef8 --- /dev/null +++ b/tutorial/notification.html @@ -0,0 +1,105 @@ + + + + + + PhoneGap + + + + + + +
+ + Back + + Notification +
+ + +
+

Show Custom Alert

+
+ + +
+

Show Activity Indicator

+
+
+ + +
+

Vibrate

+
+
+ + +
+

Show Loading ( 2 Seconds )

+
+
+ + +
+

Beep

+
+
+ + + diff --git a/tutorial/percBass.wav b/tutorial/percBass.wav new file mode 100755 index 00000000..e63dcc4a Binary files /dev/null and b/tutorial/percBass.wav differ diff --git a/tutorial/phonegap.js b/tutorial/phonegap.js new file mode 100644 index 00000000..d569266a --- /dev/null +++ b/tutorial/phonegap.js @@ -0,0 +1,1272 @@ +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 + */ +PhoneGap = { + queue: { + ready: true, + commands: [], + timer: null + }, + _constructors: [] +}; + +/** + * Boolean flag indicating if the PhoneGap API is available and initialized. + */ // TODO: Remove this, it is unused here ... -jm +PhoneGap.available = DeviceInfo.uuid != undefined; + +/** + * Add an initialization function to a queue that ensures it will run and initialize + * application constructors only once PhoneGap has been initialized. + * @param {Function} func The function callback you want run once PhoneGap is initialized + */ +PhoneGap.addConstructor = function(func) { + var state = document.readyState; + if ( state == 'loaded' || state == 'complete' ) + { + func(); + } + else + { + PhoneGap._constructors.push(func); + } +}; + +(function() + { + var timer = setInterval(function() + { + + var state = document.readyState; + + if ( state == 'loaded' || state == 'complete' ) + { + clearInterval(timer); // stop looking + // run our constructors list + while (PhoneGap._constructors.length > 0) + { + var constructor = PhoneGap._constructors.shift(); + try + { + constructor(); + } + catch(e) + { + if (typeof(debug['log']) == 'function') + { + debug.log("Failed to run constructor: " + debug.processMessage(e)); + } + else + { + alert("Failed to run constructor: " + e.message); + } + } + } + // all constructors run, now fire the deviceready event + var e = document.createEvent('Events'); + e.initEvent('deviceready'); + document.dispatchEvent(e); + } + }, 5); +})(); + + +/** + * Execute a PhoneGap command in a queued fashion, to ensure commands do not + * execute with any race conditions, and only run when PhoneGap is ready to + * recieve them. + * @param {String} command Command to be run in PhoneGap, e.g. "ClassName.method" + * @param {String[]} [args] Zero or more arguments to pass to the method + */ +PhoneGap.exec = function() { + PhoneGap.queue.commands.push(arguments); + if (PhoneGap.queue.timer == null) + PhoneGap.queue.timer = setInterval(PhoneGap.run_command, 10); +}; + +/** + * 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 + */ +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; + +}; +function Acceleration(x, y, z) +{ + this.x = x; + this.y = y; + this.z = z; + this.timestamp = new Date().getTime(); +} + +// Need to define these for android +_accel = {}; +_accel.x = 0; +_accel.y = 0; +_accel.z = 0; + +function gotAccel(x, y, z) +{ + _accel.x = x; + _accel.y = y; + _accel.z = z; +} + +/** + * This class provides access to device accelerometer data. + * @constructor + */ +function Accelerometer() { + /** + * The last known acceleration. + */ + this.lastAcceleration = null; +} + +/** + * Asynchronously aquires the current acceleration. + * @param {Function} successCallback The function to call when the acceleration + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the acceleration data. + * @param {AccelerationOptions} options The options for getting the accelerometer data + * such as timeout. + */ +Accelerometer.prototype.getCurrentAcceleration = function(successCallback, errorCallback, options) { + // If the acceleration is available then call success + // If the acceleration is not available then call error + + // Created for iPhone, Iphone passes back _accel obj litteral + if (typeof successCallback == "function") { + var accel = new Acceleration(_accel.x,_accel.y,_accel.z); + Accelerometer.lastAcceleration = accel; + successCallback(accel); + } +} + +/** + * Asynchronously aquires the acceleration repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the acceleration + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the acceleration data. + * @param {AccelerationOptions} options The options for getting the accelerometer data + * such as timeout. + */ + +Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallback, options) { + // TODO: add the interval id to a list so we can clear all watches + var frequency = (options != undefined)? options.frequency : 10000; + + Accel.start(frequency); + return setInterval(function() { + navigator.accelerometer.getCurrentAcceleration(successCallback, errorCallback, options); + }, frequency); +} + +/** + * Clears the specified accelerometer watch. + * @param {String} watchId The ID of the watch returned from #watchAcceleration. + */ +Accelerometer.prototype.clearWatch = function(watchId) { + Accel.stop(); + clearInterval(watchId); +} + +PhoneGap.addConstructor(function() { + if (typeof navigator.accelerometer == "undefined") navigator.accelerometer = new Accelerometer(); +}); +/** + * This class provides access to the device camera. + * @constructor + */ +function Camera() { + +} + +/** + * + * @param {Function} successCallback + * @param {Function} errorCallback + * @param {Object} options + */ +Camera.prototype.getPicture = function(successCallback, errorCallback, options) { + + this.winCallback = successCallback; + this.failCallback = errorCallback; + if (options.quality) + { + GapCam.takePicture(options.quality); + } + else + { + GapCam.takePicture(80); + } +} + +Camera.prototype.win = function(picture) +{ + this.winCallback(picture); +} + +Camera.prototype.fail = function(err) +{ + this.failCallback(err); +} + +PhoneGap.addConstructor(function() { + if (typeof navigator.camera == "undefined") navigator.camera = new Camera(); +}); +/** + * This class provides access to device Compass data. + * @constructor + */ +function Compass() { + /** + * The last known Compass position. + */ + this.lastHeading = null; + this.lastError = null; + this.callbacks = { + onHeadingChanged: [], + onError: [] + }; +}; + +/** + * 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. + * @param {PositionOptions} options The options for getting the heading data + * such as timeout. + */ +Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, options) { + if (this.lastHeading == null) { + this.start(options); + } + else + if (typeof successCallback == "function") { + successCallback(this.lastHeading); + } +}; + +/** + * 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. + * @param {HeadingOptions} options The options for getting the heading data + * such as timeout and the frequency of the watch. + */ +Compass.prototype.watchHeading= function(successCallback, errorCallback, options) { + // Invoke the appropriate callback with a new Position object every time the implementation + // determines that the position of the hosting device has changed. + + this.getCurrentHeading(successCallback, errorCallback, options); + var frequency = 100; + if (typeof(options) == 'object' && options.frequency) + frequency = options.frequency; + + var self = this; + return setInterval(function() { + self.getCurrentHeading(successCallback, errorCallback, options); + }, frequency); +}; + + +/** + * Clears the specified heading watch. + * @param {String} watchId The ID of the watch returned from #watchHeading. + */ +Compass.prototype.clearWatch = function(watchId) { + clearInterval(watchId); +}; + + +/** + * Called by the geolocation framework when the current heading is found. + * @param {HeadingOptions} position The current heading. + */ +Compass.prototype.setHeading = function(heading) { + this.lastHeading = heading; + for (var i = 0; i < this.callbacks.onHeadingChanged.length; i++) { + var f = this.callbacks.onHeadingChanged.shift(); + f(heading); + } +}; + +/** + * Called by the geolocation framework when an error occurs while looking up the current position. + * @param {String} message The text of the error message. + */ +Compass.prototype.setError = function(message) { + this.lastError = message; + for (var i = 0; i < this.callbacks.onError.length; i++) { + var f = this.callbacks.onError.shift(); + f(message); + } +}; + +PhoneGap.addConstructor(function() { + if (typeof navigator.compass == "undefined") navigator.compass = new Compass(); +}); +var Contact = function(){ + this.name = new ContactName(); + this.emails = []; + this.phones = []; +} + +var ContactName = function() +{ + this.formatted = ""; + this.familyName = ""; + this.givenName = ""; + this.additionalNames = []; + this.prefixes = []; + this.suffixes = []; +} + + +var ContactEmail = function() +{ + this.types = []; + this.address = ""; +} + +var ContactPhoneNumber = function() +{ + this.types = []; + this.number = ""; +} + + +var Contacts = function() +{ + this.records = []; +} + +Contacts.prototype.find = function(obj, win, fail) +{ + if(obj.name != null) + { + // Build up the search term that we'll use in SQL, based on the structure/contents of the contact object passed into find. + var searchTerm = ''; + if (obj.name.givenName && obj.name.givenName.length > 0) { + searchTerm = obj.name.givenName.split(' ').join('%'); + } + if (obj.name.familyName && obj.name.familyName.length > 0) { + searchTerm += obj.name.familyName.split(' ').join('%'); + } + if (!obj.name.familyName && !obj.name.givenName && obj.name.formatted) { + searchTerm = obj.name.formatted; + } + ContactHook.search(searchTerm, "", ""); + } + this.win = win; + this.fail = fail; +} + +Contacts.prototype.droidFoundContact = function(name, npa, email) +{ + var contact = new Contact(); + contact.name = new ContactName(); + contact.name.formatted = name; + contact.name.givenName = name; + var mail = new ContactEmail(); + mail.types.push("home"); + mail.address = email; + contact.emails.push(mail); + phone = new ContactPhoneNumber(); + phone.types.push("home"); + phone.number = npa; + contact.phones.push(phone); + this.records.push(contact); +} + +Contacts.prototype.droidDone = function() +{ + this.win(this.records); +} + +PhoneGap.addConstructor(function() { + if(typeof navigator.contacts == "undefined") navigator.contacts = new Contacts(); +}); +var Crypto = function() +{ +} + +Crypto.prototype.encrypt = function(seed, string, callback) +{ + GapCrypto.encrypt(seed, string); + this.encryptWin = callback; +} + +Crypto.prototype.decrypt = function(seed, string, callback) +{ + GapCrypto.decrypt(seed, string); + this.decryptWin = callback; +} + +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(); + } +}); + +/** + * 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.gap = null; + this.uuid = null; + try { + if (window.DroidGap) { + this.available = true; + this.uuid = window.DroidGap.getUuid(); + this.version = window.DroidGap.getOSVersion(); + this.gapVersion = window.DroidGap.getVersion(); + this.platform = window.DroidGap.getPlatform(); + this.name = window.DroidGap.getProductName(); + } + } catch(e) { + this.available = false; + } +} + +PhoneGap.addConstructor(function() { + navigator.device = window.device = new Device(); +}); + + + +PhoneGap.addConstructor(function() { if (typeof navigator.fileMgr == "undefined") navigator.fileMgr = new FileMgr();}); + + +/** + * This class provides iPhone read and write access to the mobile device file system. + * Based loosely on http://www.w3.org/TR/2009/WD-FileAPI-20091117/#dfn-empty + */ +function FileMgr() +{ + this.fileWriters = {}; // empty maps + this.fileReaders = {}; + + this.docsFolderPath = "../../Documents"; + this.tempFolderPath = "../../tmp"; + this.freeDiskSpace = -1; + this.getFileBasePaths(); + this.getFreeDiskSpace(); +} + +// private, called from Native Code +FileMgr.prototype._setPaths = function(docs,temp) +{ + this.docsFolderPath = docs; + this.tempFolderPath = temp; +} + +// private, called from Native Code +FileMgr.prototype._setFreeDiskSpace = function(val) +{ + this.freeDiskSpace = val; +} + + +// FileWriters add/remove +// called internally by writers +FileMgr.prototype.addFileWriter = function(filePath,fileWriter) +{ + this.fileWriters[filePath] = fileWriter; +} + +FileMgr.prototype.removeFileWriter = function(filePath) +{ + this.fileWriters[filePath] = null; +} + +// File readers add/remove +// called internally by readers +FileMgr.prototype.addFileReader = function(filePath,fileReader) +{ + this.fileReaders[filePath] = fileReader; +} + +FileMgr.prototype.removeFileReader = function(filePath) +{ + this.fileReaders[filePath] = null; +} + +/******************************************* + * + * private reader callback delegation + * called from native code + */ +FileMgr.prototype.reader_onloadstart = function(filePath,result) +{ + this.fileReaders[filePath].onloadstart(result); +} + +FileMgr.prototype.reader_onprogress = function(filePath,result) +{ + this.fileReaders[filePath].onprogress(result); +} + +FileMgr.prototype.reader_onload = function(filePath,result) +{ + this.fileReaders[filePath].result = unescape(result); + this.fileReaders[filePath].onload(this.fileReaders[filePath].result); +} + +FileMgr.prototype.reader_onerror = function(filePath,err) +{ + this.fileReaders[filePath].result = err; + this.fileReaders[filePath].onerror(err); +} + +FileMgr.prototype.reader_onloadend = function(filePath,result) +{ + this.fileReaders[filePath].onloadend(result); +} + +/******************************************* + * + * private writer callback delegation + * called from native code +*/ +FileMgr.prototype.writer_onerror = function(filePath,err) +{ + this.fileWriters[filePath].onerror(err); +} + +FileMgr.prototype.writer_oncomplete = function(filePath,result) +{ + this.fileWriters[filePath].oncomplete(result); // result contains bytes written +} + + +FileMgr.prototype.getFileBasePaths = function() +{ + //PhoneGap.exec("File.getFileBasePaths"); +} + +FileMgr.prototype.testFileExists = function(fileName, successCallback, errorCallback) +{ + var test = FileUtil.testFileExists(fileName); + test ? successCallback() : errorCallback(); +} + +FileMgr.prototype.testDirectoryExists = function(dirName, successCallback, errorCallback) +{ + this.successCallback = successCallback; + this.errorCallback = errorCallback; + var test = FileUtil.testDirectoryExists(dirName); + test ? successCallback() : errorCallback(); +} + +FileMgr.prototype.createDirectory = function(dirName, successCallback, errorCallback) +{ + this.successCallback = successCallback; + this.errorCallback = errorCallback; + var test = FileUtils.createDirectory(dirName); + test ? successCallback() : errorCallback(); +} + +FileMgr.prototype.deleteDirectory = function(dirName, successCallback, errorCallback) +{ + this.successCallback = successCallback; + this.errorCallback = errorCallback; + var test = FileUtils.deleteDirectory(dirName); + test ? successCallback() : errorCallback(); +} + +FileMgr.prototype.deleteFile = function(fileName, successCallback, errorCallback) +{ + this.successCallback = successCallback; + this.errorCallback = errorCallback; + FileUtils.deleteFile(fileName); + test ? successCallback() : errorCallback(); +} + +FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback) +{ + if(this.freeDiskSpace > 0) + { + return this.freeDiskSpace; + } + else + { + this.successCallback = successCallback; + this.errorCallback = errorCallback; + this.freeDiskSpace = FileUtils.getFreeDiskSpace(); + (this.freeDiskSpace > 0) ? successCallback() : errorCallback(); + } +} + + +// File Reader + + +function FileReader() +{ + this.fileName = ""; + this.result = null; + this.onloadstart = null; + this.onprogress = null; + this.onload = null; + this.onerror = null; + this.onloadend = null; +} + + +FileReader.prototype.abort = function() +{ + // Not Implemented +} + +FileReader.prototype.readAsText = function(file) +{ + if(this.fileName && this.fileName.length > 0) + { + navigator.fileMgr.removeFileReader(this.fileName,this); + } + this.fileName = file; + navigator.fileMgr.addFileReader(this.fileName,this); + //alert("Calling File.read : " + this.fileName); + //window.location = "gap://File.readFile/"+ file; + this.onerror = errorCallback; + this.oncomplete = successCallback; + + return FileUtil.read(fileName); +} + +FileReader.prototype.hasRead(data) +{ + +} + +// File Writer + +function FileWriter() +{ + this.fileName = ""; + this.result = null; + this.readyState = 0; // EMPTY + this.result = null; + this.onerror = null; + this.oncomplete = null; +} + +FileWriter.prototype.writeAsText = function(file,text,bAppend) +{ + if(this.fileName && this.fileName.length > 0) + { + navigator.fileMgr.removeFileWriter(this.fileName,this); + } + this.fileName = file; + if(bAppend != true) + { + bAppend = false; // for null values + } + navigator.fileMgr.addFileWriter(file,this); + this.readyState = 0; // EMPTY + var call = FileUtil.write(file, text, bAppend); + this.result = null; +} + + + + + +/** + * This class provides access to device GPS data. + * @constructor + */ +function Geolocation() { + /** + * The last known GPS position. + */ + this.lastPosition = null; + this.lastError = null; + this.callbacks = { + onLocationChanged: [], + onError: [] + }; +}; + +Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) +{ + var position = Geo.getCurrentLocation(); + this.global_success = successCallback; + this.fail = errorCallback; +} + +/** + * Asynchronously aquires the position repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the position + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the position data. + * @param {PositionOptions} options The options for getting the position data + * such as timeout and the frequency of the watch. + */ +Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) { + // Invoke the appropriate callback with a new Position object every time the implementation + // determines that the position of the hosting device has changed. + + this.getCurrentPosition(successCallback, errorCallback, options); + var frequency = 10000; + if (typeof(options) == 'object' && options.frequency) + frequency = options.frequency; + + var that = this; + return setInterval(function() { + that.getCurrentPosition(successCallback, errorCallback, options); + }, frequency); +}; + + +/** + * Clears the specified position watch. + * @param {String} watchId The ID of the watch returned from #watchPosition. + */ +Geolocation.prototype.clearWatch = function(watchId) { + clearInterval(watchId); +}; + +/** + * Called by the geolocation framework when the current location is found. + * @param {PositionOptions} position The current position. + */ +Geolocation.prototype.setLocation = function(position) { + this.lastPosition = position; + for (var i = 0; i < this.callbacks.onLocationChanged.length; i++) { + var f = this.callbacks.onLocationChanged.shift(); + f(position); + } +}; + +/** + * Called by the geolocation framework when an error occurs while looking up the current position. + * @param {String} message The text of the error message. + */ +Geolocation.prototype.setError = function(message) { + this.lastError = message; + for (var i = 0; i < this.callbacks.onError.length; i++) { + var f = this.callbacks.onError.shift(); + f(message); + } +}; + +// Run the global callback +Geolocation.prototype.gotCurrentPosition = function(lat, lng, alt, altacc, head, vel, stamp) +{ + if (lat == "undefined" || lng == "undefined") + { + this.fail(); + } + else + { + coords = new Coordinates(lat, lng, alt, altacc, head, vel); + loc = new Position(coords, stamp); + this.lastPosition = loc; + this.global_success(loc); + } +} + +/* +* This turns on the GeoLocator class, which has two listeners. +* The listeners have their own timeouts, and run independently of this process +* In this case, we return the key to the watch hash +*/ + +Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) +{ + var frequency = (options != undefined)? options.frequency : 10000; + + if (!this.listeners) + { + this.listeners = []; + } + + var key = this.listeners.push( {"success" : successCallback, "fail" : failCallback }) - 1; + + // TO-DO: Get the names of the method and pass them as strings to the Java. + return Geolocation.start(frequency, key); +} + +/* + * Retrieve and stop this listener from listening to the GPS + * + */ +Geolocation.prototype.success = function(key, lat, lng, alt, altacc, head, vel, stamp) +{ + var coords = new Coordinates(lat, lng, alt, altacc, head, vel); + var loc = new Position(coords, stamp); + this.listeners[key].success(loc); +} + +Geolocation.prototype.fail = function(key) +{ + this.listeners[key].fail(); +} + +Geolocation.prototype.clearWatch = function(watchId) +{ + Geo.stop(watchId); +} +// Taken from Jesse's geo fix (similar problem) in PhoneGap iPhone. Go figure, same browser! +function __proxyObj(origObj, proxyObj, funkList) { + for (var v in funkList) { + origObj[funkList[v]] = proxyObj[funkList[v]]; + } +} +PhoneGap.addConstructor(function() { + navigator._geo = new Geolocation(); + __proxyObj(navigator.geolocation, navigator._geo, + ["setLocation", "getCurrentPosition", "watchPosition", + "clearWatch", "setError", "start", "stop", "gotCurrentPosition"] + ); +});function KeyEvent() +{ +} + +KeyEvent.prototype.menuTrigger = function() +{ + var e = document.createEvent('Events'); + e.initEvent('menuKeyDown'); + document.dispatchEvent(e); +} + +KeyEvent.prototype.searchTrigger= function() +{ + var e = document.createEvent('Events'); + e.initEvent('searchKeyDown'); + document.dispatchEvent(e); +} + +if (document.keyEvent == null || typeof document.keyEvent == 'undefined') +{ + window.keyEvent = document.keyEvent = new KeyEvent(); +} +/** + * This class provides access to the device media, interfaces to both sound and video + * @constructor + */ +function Media(src, successCallback, errorCallback) { + this.src = src; + this.successCallback = successCallback; + this.errorCallback = errorCallback; +} + +Media.prototype.record = function() { +} + +Media.prototype.play = function() { +} + +Media.prototype.pause = function() { +} + +Media.prototype.stop = function() { +} + + +/** + * 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; + + +//if (typeof navigator.audio == "undefined") navigator.audio = new Media(src); + +/** + * This class provides access to the device media, interfaces to both sound and video + * @constructor + */ + +Media.prototype.play = function() { + DroidGap.startPlayingAudio(this.src); +} + +Media.prototype.stop = function() { + DroidGap.stopPlayingAudio(); +} + +Media.prototype.startRecord = function() { + DroidGap.startRecordingAudio(this.src); +} + +Media.prototype.stopRecordingAudio = function() { + DroidGap.stopRecordingAudio(); +} + + +/** + * 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; +}; + +/** + * + * @param {Function} successCallback + * @param {Function} errorCallback + * @param {Object} options (isIpAddress:boolean) + */ +Network.prototype.isReachable = function(hostName, successCallback, options) { +} + +/** + * Called by the geolocation framework when the reachability status has changed. + * @param {Reachibility} reachability The current reachability status. + */ +Network.prototype.updateReachability = function(reachability) { + this.lastReachability = reachability; +}; + +PhoneGap.addConstructor(function() { + if (typeof navigator.network == "undefined") navigator.network = new Network(); +}); +Network.prototype.isReachable = function(uri, win, options) +{ + var status = new NetworkStatus(); + if(NetworkManager.isReachable(uri)) + { + if (NetworkManager.isWifiActive) + status.code = 2; + else + status.code = 1; + } + else + status.code = 0; + win(status); +} +/** + * 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 {String} [title="Alert"] Title of the alert dialog (default: Alert) + * @param {String} [buttonLabel="OK"] Label of the close button (default: OK) + */ +Notification.prototype.alert = function(message, title, buttonLabel) { + // Default is to use a browser alert; this will use "index.html" as the title though + alert(message); +}; + +/** + * Start spinning the activity indicator on the statusbar + */ +Notification.prototype.activityStart = function() { +}; + +/** + * Stop spinning the activity indicator on the statusbar, if it's currently spinning + */ +Notification.prototype.activityStop = function() { +}; + +/** + * 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) { + +}; + +/** + * Causes the device to vibrate. + * @param {Integer} mills The number of milliseconds to vibrate for. + */ +Notification.prototype.vibrate = function(mills) { + +}; + +/** + * Causes the device to beep. + * @param {Integer} count The number of beeps. + * @param {Integer} volume The volume of the beep. + */ +Notification.prototype.beep = function(count, volume) { + +}; + +// TODO: of course on Blackberry and Android there notifications in the UI as well + +PhoneGap.addConstructor(function() { + if (typeof navigator.notification == "undefined") navigator.notification = new Notification(); +}); + +Notification.prototype.vibrate = function(mills) +{ + DroidGap.vibrate(mills); +} + +/* + * On the Android, we don't beep, we notify you with your + * notification! We shouldn't keep hammering on this, and should + * review what we want beep to do. + */ + +Notification.prototype.beep = function(count, volume) +{ + DroidGap.beep(count); +} +/** + * 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) { + /** + * 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; +} + +/** + * 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; +/* + * 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 + */ + +var DroidDB = function() +{ + this.txQueue = []; +} + +DroidDB.prototype.addResult = function(rawdata, tx_id) +{ + eval("var data = " + rawdata); + var tx = this.txQueue[tx_id]; + tx.resultSet.push(data); +} + +DroidDB.prototype.completeQuery = function(tx_id) +{ + var tx = this.txQueue[tx_id]; + var r = new result(); + r.rows.resultSet = tx.resultSet; + r.rows.length = tx.resultSet.length; + tx.win(r); +} + +DroidDB.prototype.fail = function(reason, tx_id) +{ + var tx = this.txQueue[tx_id]; + tx.fail(reason); +} + +var DatabaseShell = function() +{ + +} + +DatabaseShell.prototype.transaction = function(process) +{ + tx = new Tx(); + process(tx); +} + +var Tx = function() +{ + droiddb.txQueue.push(this); + this.id = droiddb.txQueue.length - 1; + this.resultSet = []; +} + +Tx.prototype.executeSql = function(query, params, win, fail) +{ + droidStorage.executeSql(query, params, this.id); + tx.win = win; + tx.fail = fail; +} + +var result = function() +{ + this.rows = new Rows(); +} + +var Rows = function() +{ + this.resultSet = []; + this.length = 0; +} + +Rows.prototype.item = function(row_id) +{ + return this.resultSet[id]; +} + +var dbSetup = function(name, version, display_name, size) +{ + droidStorage.openDatabase(name, version, display_name, size) + db_object = new DatabaseShell(); + return db_object; +} + +PhoneGap.addConstructor(function() { + if (typeof navigator.openDatabase == "undefined") + { + navigator.openDatabase = window.openDatabase = dbSetup; + window.droiddb = new DroidDB(); + } +}); +