/**
* <strong>Big Five</strong>
* <br />
* Copyright (C) 2008-2009 Dirk Holtwick. All rights reserved.
* <br />
* <<a href="http://www.big5apps.com">http://www.big5apps.com</a>>
*
* <br /><br />
* To use this API add the following line to the header of your HTML file:
*
* <pre><script type="text/javascript" src="http://www.big5apps.com/api/bigfive.js"></script></pre>
*
* To access a specific version do like this:
*
* <pre><script type="text/javascript" src="http://www.big5apps.com/api/bigfive-1.0.0.js"></script></pre>
*
* @module device
* @author Dirk Holtwick dirk.holtwick@gmail.com
* @copyright Dirk Holtwick dirk.holtwick@gmail.com
* @version 1.0.1
*/
/**
* Interface to device specific functionalities. To initialize the properties
* you should first call Device.start(callback), where
* "callback" is the function that will be called after the initialization
* has finished.
*
* @class Device
* @static
*/
Device = {
/**
* @property version
* @type String
* @default "1.0.0"
*/
version: "1.1.0",
/**
* Are we on a supported device?
*
* @private
* @property available
* @type Boolean
*/
available: false,
/**
* Name of the current device.
* On iPhone OS these values can be: "iPhone", "iPhone Simulator"
* or "iPod touch".
*
* XXX Should be "false" by default.
*
* @property model
* @type String
* @default false
*/
model: "",
gapVersion: "",
bigFiveVersion: "",
/**
* The Unique ID of the device if available.
*
* @property id
* @type String
* @default ""
*/
id: "",
name: "",
/**
* The name of the devices operation system (OS). For now this can only
* be "iPhone OS".
*
* @private
* @property os
* @type String
*/
os: null,
callback: null,
commandStack: [],
commandWorking: false,
/**
* True if running on an iPhone OS device.
*
* @property isIPhone
* @type Boolean
* @default false
*/
isIPhone: false,
/**
* True if running on an Google Android OS device.
*
* @property isIPhone
* @type Boolean
* @default false
*/
isAndroid:false,
/**
* Sets the properties of this class that are send form the device
* via "window.bigfive". Due to a bug in iPhone OS this should not
* be called directly. Use Device.start() instead.
*
* @private
*/
init: function(){
try {
Device.model = window.bigfive.device_model;
Device.version = window.bigfive.device_version;
Device.name = window.bigfive.device_name;
Device.id = window.bigfive.device_id;
Device.gapVersion = window.bigfive.version;
Device.bigFiveVersion = window.bigfive.version;
Device.available = true;
}
catch (e) {
alert("Big Five is not supported!")
}
// Device.alert("Started!")
},
/**
* If launched in a wrapper like the Big Five App from the Apple App Store
* you can leave the current view and return to the outer view (like
* the "bookmark list") calling this command.
*/
exit: function(){
Device.exec("exit")
return false
},
/**
* Sets the properties of Device class. Call this before you access the
* properties of this class. If you provided a "callback" function this
* will be called after the properties are set.
*
* @param {Object} successCallback
* Function to be called when initialization has finished.
*/
start: function(callback){
Device.callback = callback
Device.exec("init")
},
/**
* Send command to Big Five and make sure that there is not other command
* that is executed in the same moment.
*
* @private
* @param {String} command
*/
execStack: function(command){
// alert("next " + command)
if (command != null) {
Device.commandStack.push(command)
}
else {
// alert("len::" + Device.commandStack.length)
;
}
if (Device.commandStack.length > 0) {
if ((!Device.commandWorking) || (command == null)) {
Device.commandWorking = true
var next = Device.commandStack.pop()
// alert(next)
// console.info("stack", next)
window.setTimeout('document.location = "' + next + '"', 0.0001)
}
}
else {
Device.commandWorking = false
}
},
/**
* Send a command to the device. If the command has been accepted true is
* returned from this method. You should not use this method directly,
* wrappers functions exist for each functionality available.
*
* @param {String} command
* @param {Object} value
* @return {Boolean}
* @private
*/
exec: function(command, value){
/* Executes device commands without stopping the current thread. If the
command has been sent it returns true, otherwise false.
*/
if (Device.isIPhone) { // Device.available) {
// no escape! asynchronous!
Device.execStack('device:' + command + ':' + (value || ''))
return true
}
return false
},
/**
* Send a string property to the device. Don't use this directly because
* wrapper functions are available for all properties supported.
*
* @param {String} name
* @param {String} value
* @private
*/
setStr: function(name, value){
if (Device.available) {
Device.execStack('device:set:' + name + ':' + value)
return true
}
return false
},
/**
* Send a boolean property to device. Don't use this directly because
* wrapper functions are available for all properties supported.
*
* @private
* @param {String} name
* @param {Boolean} value
*/
setBool: function(name, value){
return Device.setStr(name, value ? "true" : "false")
},
/**
* Opens a system alert if it is not suported by the UIWebView (iPhone OS 2.0)
*
* @param {String} message
* @deprecated Use Device.msgbox() now to avoid confusion
*/
alert: function(message){
/* Opens a non modal (!) alert. Alerts are not supported by WebKit by default
*/
Device.exec("alert", message)
},
/**
* Opens a non blocking system alert popup
*
* @param {String} message
*/
msgbox: function(message){
/* Opens a non modal (!) alert. Alerts are not supported by WebKit by default
*/
Device.exec("alert", message)
},
/**
* Opens the URL in Safari. Be aware that this closes the
* current application you are running in!
*
* @param {String} url
*/
safari: function(url){
/* Calls an URL in Safari. That means also that Big5 will be stopped.
*/
Device.exec("safari", url)
},
/**
* Start the vibration alarm. This is only supported by iPhones (not iPod touch).
*/
vibrate: function(){
return Device.exec("vibrate")
},
/**
* Return an object with network status informations
*
* @param {Object} onsuccess
*/
getNetworkStatus: function(onsuccess){
Device.networkCallback = onsuccess
return Device.exec("network");
},
networkCallback: null,
/**
* Show navigation bar of Big Five browser application
*
* @param {Boolean} value
*/
setNavigationBar: function(value){
return Device.setBool("navigation", value)
},
/**
* Show status bar
*
* @param {Boolean} value
*/
setStatusBar: function(value){
return Device.setBool("status", value)
},
/**
* Enable rotation of the view
*
* @param {Boolean} value
*/
setRotation: function(value){
return Device.setBool("rotation", value)
},
/**
* Enable scaling of page elements by double tapping and zooming gestures.
*
* @param {Boolean} value
*/
setScale: function(value){
return Device.setBool("scale", value)
}
}
/**
* Access to the acceleration functionalities of the device.
*
* @class Device.Acceleration
* @static
*/
Device.Acceleration = {
callback: null,
accelX: 0,
accelY: 0,
accelZ: 0,
/**
* Start tracking of acceleration data. The setting of the frequency is
* optional. The default value is 40 Hz (1.0/40.0).
*
* @param {Object} successCallback
* Function that will be called if new data is available
*
* @param {Float} frequency
* Frequency provided as a friction of seconds (Hertz)
*
*/
start: function(callback, frequency){
if (callback) {
Device.Acceleration.callback = callback
if (frequency == null)
frequency = 1.0 / 40.0
Device.exec("acceleration_start", frequency)
}
else {
throw "Callback is obligatory"
}
},
/**
* Stop the tracking of acceleration data.
*/
stop: function(){
Device.exec("acceleration_stop")
}
}
/*
*
* @deprecated Console just works if you use XCode
* @class Device.Console
* @static
* @private
*/
Device.Console = {
/*
* Write value to debug log of XCode.
*
* @param {Object} value
*/
log: function(value){
device.exec("log", value)
},
/*
*
* @param {Object} value
*/
error: function(value){
device.exec("log", "ERROR! " + value)
}
}
/**
* Access to photo library and camera of device.
*
* @class Device.Image
* @static
*/
Device.Image = {
callback: null,
onerror: null,
onpreview: null,
oncancel: null,
destination: null,
counter: 1,
/**
* @private
* @param {String} command
* @param {String} destinationURL
* @param {Object} successCallback
* @param {Object} errorCallback
* @param {Object} cancelCallback
*/
_exec: function(command, destination, callback, onerror, oncancel){
Device.Image.callback = callback || Device.Image.callback
Device.Image.onerror = onerror || Device.Image.onerror
Device.Image.oncancel = oncancel || Device.Image.oncancel
Device.Image.destination = destination || Device.Image.destination
// throw "Destination needed"
Device.counter += 1
return Device.exec(command, destination)
},
/**
* Choose an image from the photo library. The data is then send to the
* "destinationURL" URL via POST in a variable named "data". If it succeeds
* "successCallback" is called. On errors or cancelled operations the corresponding
* functions are called. For now there is no way to show progress of the
* upload operation.
*
* Before the image will be scaled down and rotated. Then it will be
* converted to a JPG format with a qualitiy of 100%.
*
* @param {String} destinationURL
* The URL where the upload will be send to
*
* @param {Object} successCallback
* Callback if image upload is done.
*
* @param {Object} errorCallback
* Callback if an error occured.
*
* @param {Object} cancelCallback
* Callback if user cancelled operation.
*/
getFromPhotoLibrary: function(destination, callback, onerror, oncancel){
return Device.Image._exec("photo_from_library", destination, callback, onerror, oncancel);
},
/**
* Get image form built in camera. See getFromPhotoLibrary for more details.
*
* @param {String} destinationURL
* @param {Object} successCallback
* @param {Object} errorCallback
* @param {Object} cancelCallback
*/
getFromCamera: function(destination, callback, onerror, oncancel){
return Device.Image._exec("photo_from_camera", destination, callback, onerror, oncancel);
},
/*
* Get image form XXX. See getFromPhotoLibrary for more details.
*
* @param {String} destinationURL
* @param {Object} successCallback
* @param {Object} errorCallback
* @param {Object} cancelCallback
*/
getFromSavedPhotosAlbum: function(destination, callback, onerror, oncancel){
return Device.Image._exec("photo_from_album", destination, callback, onerror, oncancel);
},
/**
* See getFromPhotoLibrary.
*
* @param {String} destination
* @param {Object} callback
* @param {Object} onerror
* @deprecated: Worked only if called from a local page (file:///...)
*/
getFromPhotoLibraryToLocal: function(destination, callback, onerror){
return Device.Image._exec("photo_from_library_to_local", destination, callback, onerror);
},
/**
* See getFromCamera.
*
* @param {String} destination
* @param {Object} callback
* @param {Object} onerror
* @deprecated: Worked only if called from a local page (file:///...)
*/
getFromCameraToLocal: function(destination, callback, onerror){
return Device.Image._exec("photo_from_camera_to_local", destination, callback, onerror);
},
/*
* See getFromSavedPhotosAlbum.
*
* @param {Object} destination
* @param {Object} callback
* @param {Object} onerror
* @deprecated: Worked only if called from a local page (file:///...)
*/
getFromSavedPhotosAlbumToLocal: function(destination, callback, onerror){
return Device.Image._exec("photo_from_album_to_local", destination, callback, onerror);
}
}
/* Location structures */
function Coordinates(latitude, longitude){
this.latitude = latitude;
this.longitude = longitude;
this.altitude = null;
this.accuracy = null;
this.altitudeAccuracy = null;
this.heading = null;
this.speed = null;
}
function Position(latitude, longitude){
this.coords = new Coordinates(latitude, longitude);
this.timestamp = null;
}
function PositionError(){
this.code = 0;
this.message = null;
}
PositionError.UNKNOWN_ERROR = 0;
PositionError.PERMISSION_DENIED = 1;
PositionError.POSITION_UNAVAILABLE = 2;
PositionError.TIMEOUT = 3;
/* Hard coded callbacks */
__device_did_update_location = null
__device_location_error = null
/**
* Get the current geo location of the device. This tries to implement the
* W3C "Geolocation API Specification" (Editor's Draft [DATE: 24 November 2008])
* <br>
* <a href="http://dev.w3.org/geo/api/spec-source.html">http://dev.w3.org/geo/api/spec-source.html</a>
* <br><br>
* This is also accesible via <code>navigator.geolocation</code>.
*
* @alias navigator.geolocation
* @class Device.Location
* @static
*/
Device.Location = {
/* Tools to get the location of the device
*/
/*
* Position data
*/
position: {
lat: 0.0,
lon: 0.0,
oldLat: 0.0,
oldLon: 0.0
},
/* lat: 0.0,
lon: 0.0,
oldLat: 0.0,
oldLon: 0.0, */
callback: null,
onerror: null,
options: {},
watch: false,
/**
* @private
*/
init: function(){
Device.exec("location");
},
/**
* @private
* @param {Float} lat
* @param {Float} lon
* @param {Float} oldLat
* @param {Float} oldLon
*/
_set: function(lat, lon, oldLat, oldLon){
Device.Location.position.lat = lat
Device.Location.position.lon = lon
Device.Location.position.oldLat = oldLat
Device.Location.position.oldLon = oldLon
if (Device.Location.callback != null) {
Device.Location.callback(Device.Location.position)
Device.Location.callback = null;
}
},
/**
* Get the last calculated position. If there has not been any calculation
* before Device.Location.wait will be called. Result via callback.
*
* @param {Object} func
* @deprecated Switched to HTML5 API
*/
last: function(func){
/* Get the last saved location or if not available request the current
location and give the resulting latitude and longitude to the callback function.
*/
if ((Device.Location.lat != 0.0) && (Device.Location.lon != 0.0))
func(Device.Location.lat, Device.Location.lon)
else
Device.Location.wait(func)
},
/**
* Get the current position and trigger a callback if done.
*
* @param {Object} func
* @deprecated Switched to HTML5 API
*/
wait: function(func){
/* Request the current location and give the resulting latitude and
longitude to the callback function.
*/
Device.Location.callback = func
__device_did_update_location = function(newLat, newLon, oldLat, oldLon){
return Device.Location._set(newLat, newLon, oldLat, oldLon)
}
__device_location_error = function(code, msg){
if (Device.Location.onerror)
Device.Location.onerror(code, msg)
}
Device.exec("location");
},
/*
* Implementation according to HTML5
*
*/
/**
* Get current position. Options not yet supported!
*
* @param {Object} successCallback
* @param {Object} errorCallback
* @param {Object} options
*/
getCurrentPosition: function(successCallback, errorCallback, options) {
var options = options || {}
Device.Location.options = options
Device.Location.enableHighAccuracy = !!options.enableHighAccuracy
Device.Location.timeout = options.timeout
Device.Location.maximumAge = options.maximumAge
__device_did_update_location = function(newLat, newLon, oldLat, oldLon){
var position = new Position(newLat, newLon)
if (successCallback) {
successCallback(position)
}
if (Device.Location.watch) {
Device.exec("location")
}
else {
// Workaround to avoid double calls
successCallback = null
}
}
__device_location_error = function(code, msg){
var error = new PositionError()
error.code = PositionError.UNKNOWN_ERROR
error.message = msg
if (errorCallback) {
errorCallback(error)
}
if (!Device.Location.watch) {
// Workaround to avoid double calls
errorCallback = null
}
}
Device.exec("location");
},
/**
* Watch position. Options not yet supported!
*
* @param {Object} successCallback
* @param {Object} errorCallback
* @param {Object} options
*/
watchPosition: function(successCallback, errorCallback, options) {
Device.watch = false
Device.Location.getCurrentPosition(successCallback, errorCallback, options)
return 0
},
/**
* Clear watching position.
*
* @param {Object} watchId
*/
clearWatch: function(watchId) {
Device.watch = false
}
}
/*
* Callback for big5:init:
*/
function __device_init(info){
Device.init()
if (Device.callback)
Device.callback()
}
/*
* Will be called if the last command has been accepted.
*/
function __device_next_command(){
Device.execStack(null)
// return '{"eins":"1", "zwei":"2"}'
}
function __device_did_get_image(localurl){
if (Device.Image.onpreview)
return Device.Image.onpreview(localurl)
}
function __device_did_finish_image_upload(destination){
return Device.Image.callback()
}
function __device_photo_dialog_cancel(){
if (Device.Image.oncancel)
return Device.Image.oncancel("Cancel")
}
function __device_did_fail_image_upload(error){
if (Device.Image.onerror)
return Device.Image.onerror(error)
}
function __device_did_accelerate(x, y, z){
/* x = eval(x);
y = eval(y);
z = eval(z); */
if ((!isNaN(x)) && (!isNaN(y)) && (!isNaN(z))) {
Device.Acceleration.accelX = x;
Device.Acceleration.accelY = y;
Device.Acceleration.accelZ = z;
}
if (Device.Acceleration.callback) {
Device.Acceleration.callback(x, y, z);
}
}
function __device_network_status(data){
Device.networkCallback(data)
}
try {
$ // Test if it is alread used
}
catch (e) {
$ = function(id){
return document.getElementById(id)
};
}
// Iphone?
try {
Device.isIPhone = navigator.userAgent.toLowerCase().indexOf("iphone") > 0
} catch(e) {
;
}
// Map Location to navigator.geolocation
try {
if (navigator) {
if (!("geolocation" in navigator)) {
navigator.geolocation = Device.Location
}
}
}
catch (e) {
;
}
/* (function(){
}) */