mirror of
https://github.com/apache/cordova-android.git
synced 2026-01-30 00:05:28 +08:00
Compare commits
223 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3d7ce8fc3 | ||
|
|
85dab52cf7 | ||
|
|
c96c9b00b9 | ||
|
|
b059a31787 | ||
|
|
8cb71673c2 | ||
|
|
8ef93ff0e5 | ||
|
|
042c34192b | ||
|
|
ac2e92321f | ||
|
|
05eacf4792 | ||
|
|
435c903baf | ||
|
|
53de070a41 | ||
|
|
54fdcbfd46 | ||
|
|
44aa0aeb0f | ||
|
|
7d53eb8e3e | ||
|
|
7bc0d624ac | ||
|
|
a5039f021d | ||
|
|
80e66d87a9 | ||
|
|
d35e8cd44b | ||
|
|
eb3b1f91d4 | ||
|
|
8a1ab69235 | ||
|
|
66f3018767 | ||
|
|
ff7de25b62 | ||
|
|
85eb6e4997 | ||
|
|
0280d5dd82 | ||
|
|
3c90a9a23c | ||
|
|
088c342198 | ||
|
|
af18a8e1aa | ||
|
|
11a29e11e1 | ||
|
|
08c44f5c5d | ||
|
|
1c3ea54dcb | ||
|
|
a65638ab59 | ||
|
|
c15971253f | ||
|
|
a67dfdb75e | ||
|
|
9b52827744 | ||
|
|
c5b268756b | ||
|
|
afa85a74b3 | ||
|
|
517b5e0db9 | ||
|
|
327bda49a0 | ||
|
|
c978341d83 | ||
|
|
939754e1c9 | ||
|
|
d1448e9073 | ||
|
|
33bfb44f67 | ||
|
|
a89c8bf482 | ||
|
|
a67aeed571 | ||
|
|
315b5a59b3 | ||
|
|
8da5ad8eca | ||
|
|
740e50ce61 | ||
|
|
3ce0fc4897 | ||
|
|
8d1722ad67 | ||
|
|
7d41646a35 | ||
|
|
992ee0bca4 | ||
|
|
d00a9f33cd | ||
|
|
431c80782e | ||
|
|
39ec9c095d | ||
|
|
10e1808c56 | ||
|
|
9036eb8fcc | ||
|
|
4280fdf252 | ||
|
|
ca5e141b5b | ||
|
|
1d79b6617b | ||
|
|
6c3eefe6f9 | ||
|
|
2177cd0a39 | ||
|
|
6618015151 | ||
|
|
e99f75d59b | ||
|
|
ab8cfe01d0 | ||
|
|
e84c59d23c | ||
|
|
e81fc239a7 | ||
|
|
839c577243 | ||
|
|
116169a4c5 | ||
|
|
346ed60f0d | ||
|
|
bde59adc04 | ||
|
|
ffbc010d7b | ||
|
|
bdadbbc339 | ||
|
|
b94eedaf07 | ||
|
|
58ecac335b | ||
|
|
fd8bb2f671 | ||
|
|
0aacfbdd50 | ||
|
|
2cd116e4e7 | ||
|
|
673a8871df | ||
|
|
44945f9d5e | ||
|
|
887f754014 | ||
|
|
674015460f | ||
|
|
40084293c3 | ||
|
|
ed4c57e791 | ||
|
|
bf164f4161 | ||
|
|
626119ae3b | ||
|
|
e766188689 | ||
|
|
d74569ffa7 | ||
|
|
d424af03e4 | ||
|
|
f6f80537c3 | ||
|
|
908485751b | ||
|
|
b850d225f4 | ||
|
|
010c774988 | ||
|
|
969f0c87d7 | ||
|
|
b3e9794189 | ||
|
|
935295c9b8 | ||
|
|
04de2052fd | ||
|
|
60eb60b4f5 | ||
|
|
ec307fdda8 | ||
|
|
7344964c05 | ||
|
|
1fc56921aa | ||
|
|
21a34a8980 | ||
|
|
8d73b364f2 | ||
|
|
fb2c25c6c6 | ||
|
|
47ca081f36 | ||
|
|
939b70243d | ||
|
|
d44bb7a9d8 | ||
|
|
dccc29daf2 | ||
|
|
b402efd1f7 | ||
|
|
0c3a8fb9f7 | ||
|
|
64d4337d5f | ||
|
|
a9e1751812 | ||
|
|
2bc7bd6768 | ||
|
|
1711fb07d7 | ||
|
|
6f4673f590 | ||
|
|
5e858f8bc3 | ||
|
|
691b093ccd | ||
|
|
99002f9dce | ||
|
|
b07072c12b | ||
|
|
36dd964ba4 | ||
|
|
f848527c28 | ||
|
|
6aa055f46e | ||
|
|
7952668cf7 | ||
|
|
a0c761664d | ||
|
|
9fd9cf55cf | ||
|
|
3c9089b9c7 | ||
|
|
f220489543 | ||
|
|
b65f9517db | ||
|
|
1a0de5f626 | ||
|
|
3c0bef6cc1 | ||
|
|
040194157f | ||
|
|
7ebf8130e4 | ||
|
|
64310dc85c | ||
|
|
cd2e86af2f | ||
|
|
b353f3608d | ||
|
|
cda154209d | ||
|
|
e3c72fa915 | ||
|
|
9354b429f3 | ||
|
|
b1f0c037bd | ||
|
|
726f1094d9 | ||
|
|
1b8ab156df | ||
|
|
ee01b5058f | ||
|
|
03ea8a0b5a | ||
|
|
f090f9a70c | ||
|
|
b7abc2c344 | ||
|
|
53bdf2dd6b | ||
|
|
b9e1b1d280 | ||
|
|
9051b157f8 | ||
|
|
f16d9b01b7 | ||
|
|
2a9bc2ddf8 | ||
|
|
6e39c46b07 | ||
|
|
567ca94245 | ||
|
|
812a4b32b4 | ||
|
|
023df10f31 | ||
|
|
8d513e2765 | ||
|
|
1eae6786c4 | ||
|
|
73f278963b | ||
|
|
54eff557d9 | ||
|
|
a7415bcfc9 | ||
|
|
b6bd9ad5b8 | ||
|
|
f71d9deb5e | ||
|
|
115b428a9d | ||
|
|
92a1e4a2d9 | ||
|
|
2504db13d7 | ||
|
|
43c72e684c | ||
|
|
46f0bf60c4 | ||
|
|
8bad4eb7eb | ||
|
|
fbe96f891b | ||
|
|
ab8950a5af | ||
|
|
26adfb6346 | ||
|
|
43b6b6d34e | ||
|
|
04ddc68dfd | ||
|
|
42cd10cf56 | ||
|
|
5f3bc33f8e | ||
|
|
2131070ee9 | ||
|
|
b2a82975e5 | ||
|
|
ddeba91faf | ||
|
|
6e572f05e4 | ||
|
|
50b435c4d1 | ||
|
|
af5c5dc021 | ||
|
|
87fd9665fe | ||
|
|
5e9ca84b40 | ||
|
|
090ad56d0b | ||
|
|
e3ebfea064 | ||
|
|
44761f87d2 | ||
|
|
04e3ceac96 | ||
|
|
afc7e605ff | ||
|
|
1c5aa6cd00 | ||
|
|
c1a87ebaaa | ||
|
|
46babe7a48 | ||
|
|
0dc64d2aa7 | ||
|
|
1d9e522bd9 | ||
|
|
5dcac6d7fe | ||
|
|
07418a3606 | ||
|
|
0e08af98ca | ||
|
|
b8b1ad8421 | ||
|
|
4fa1f40b44 | ||
|
|
5f55ebf1d9 | ||
|
|
9798de7efa | ||
|
|
102745875c | ||
|
|
dce0d93df8 | ||
|
|
1428ac5ed5 | ||
|
|
4f1bc1401f | ||
|
|
28ff6e1150 | ||
|
|
5ffe5fa3c5 | ||
|
|
49341356d7 | ||
|
|
e8b85f6cf7 | ||
|
|
4b2398b487 | ||
|
|
10f3313ed5 | ||
|
|
46664c6494 | ||
|
|
8ce7e61ed7 | ||
|
|
912458c679 | ||
|
|
e117b95057 | ||
|
|
3a0101261d | ||
|
|
48d3bc09f3 | ||
|
|
0b3e27b3fa | ||
|
|
b66535a17d | ||
|
|
fdc78e1b08 | ||
|
|
36064c564e | ||
|
|
7102810283 | ||
|
|
ab4d4e22da | ||
|
|
80c15de606 | ||
|
|
be5cac6d0b | ||
|
|
2bb67ee4b0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ local.properties
|
||||
framework/phonegap.jar
|
||||
framework/bin
|
||||
framework/assets/www/.DS_Store
|
||||
.DS_Store
|
||||
@@ -31,7 +31,7 @@ Commands:
|
||||
|
||||
<pre>
|
||||
help ...... See this message. Type help [command name] to see specific help topics.
|
||||
gen ....... Generate an example PhoneGap application to current directory.
|
||||
gen ....... Generate the example PhoneGap application to current directory (or optionally provide an output directory as parameter).
|
||||
create .... Creates an Android compatible project from a WWW folder.
|
||||
classic ... Backwards support for droidgap script. Run "droidgap help classic" for more info.
|
||||
update .... Copy a fresh phonegap.jar and phonegap.js into a valid PhoneGap/Android project.
|
||||
@@ -41,8 +41,8 @@ Commands:
|
||||
Quickstart:
|
||||
|
||||
<pre>
|
||||
$ droidgap gen example
|
||||
$ cd example
|
||||
$ droidgap gen exampleapp
|
||||
$ cd exampleapp
|
||||
$ ant debug install && adb logcat
|
||||
</pre>
|
||||
|
||||
|
||||
12
bin/droidgap
12
bin/droidgap
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env ruby
|
||||
ROOT = File.expand_path(File.dirname(__FILE__).gsub('bin',''))
|
||||
ROOT = File.expand_path(File.dirname(__FILE__).gsub(/bin$/,''))
|
||||
require 'fileutils'
|
||||
require File.join(ROOT, "lib", "generate.rb")
|
||||
require File.join(ROOT, "lib", "classic.rb")
|
||||
@@ -60,7 +60,7 @@ if ARGV.first.nil? || ARGV.first == 'help'
|
||||
Commands:
|
||||
|
||||
help ...... See this message. Type help [command name] to see specific help topics.
|
||||
gen ....... Generate an example PhoneGap application to current directory.
|
||||
gen ....... Generate the example PhoneGap application to current directory (or optionally provide an output directory as parameter).
|
||||
create .... Creates an Android compatible project from a WWW folder.
|
||||
classic ... Backwards support for droidgap script. Run "droidgap help classic" for more info.
|
||||
update .... Copy a fresh phonegap.jar and phonegap.js into a valid PhoneGap/Android project.
|
||||
@@ -68,8 +68,8 @@ if ARGV.first.nil? || ARGV.first == 'help'
|
||||
|
||||
Quickstart:
|
||||
|
||||
$ droidgap gen example
|
||||
$ cd example
|
||||
$ droidgap gen exampleapp
|
||||
$ cd exampleapp
|
||||
$ ant debug install && adb logcat
|
||||
|
||||
EOF
|
||||
@@ -79,11 +79,13 @@ if ARGV.first.nil? || ARGV.first == 'help'
|
||||
DroidGap Generate
|
||||
-----------------
|
||||
|
||||
Generate an example PhoneGap application to path supplied or current working directory if none is supplied.
|
||||
Generate the example PhoneGap application to path supplied or current working directory if none is supplied.
|
||||
|
||||
Usage:
|
||||
|
||||
droidgap gen [path]
|
||||
|
||||
NOTE: Do *not* run "droidgap gen example" - you will end up with a recursive directory problem.
|
||||
|
||||
EOF
|
||||
|
||||
|
||||
@@ -5,141 +5,32 @@
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>PhoneGap</title>
|
||||
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
|
||||
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
var deviceInfo = function(){
|
||||
document.getElementById("platform").innerHTML = device.platform;
|
||||
document.getElementById("version").innerHTML = device.version;
|
||||
document.getElementById("uuid").innerHTML = device.uuid;
|
||||
}
|
||||
|
||||
var getLocation = function() {
|
||||
var suc = function(p){
|
||||
alert(p.coords.latitude + " " + p.coords.longitude);
|
||||
};
|
||||
var fail = function(){};
|
||||
navigator.geolocation.getCurrentPosition(suc,fail);
|
||||
}
|
||||
|
||||
var beep = function(){
|
||||
navigator.notification.beep(2);
|
||||
}
|
||||
|
||||
var vibrate = function(){
|
||||
navigator.notification.vibrate(0);
|
||||
}
|
||||
|
||||
var getContact = function(){
|
||||
var suc = function(c){ alert("Contact 4: " + c.contacts[3].name); };
|
||||
var fail = function(){};
|
||||
navigator.ContactManager.get(suc, fail);
|
||||
}
|
||||
|
||||
var watchAccel = function() {
|
||||
var suc = function(a){
|
||||
document.getElementById('x').innerHTML = roundNumber(a.x);
|
||||
document.getElementById('y').innerHTML = roundNumber(a.y);
|
||||
document.getElementById('z').innerHTML = roundNumber(a.z);
|
||||
};
|
||||
var fail = function(){};
|
||||
var opt = {};
|
||||
opt.frequency = 100;
|
||||
timer = navigator.accelerometer.watchAcceleration(suc,fail,opt);
|
||||
}
|
||||
|
||||
function roundNumber(num) {
|
||||
var dec = 3;
|
||||
var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
|
||||
return result;
|
||||
}
|
||||
|
||||
var preventBehavior = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
<script type="text/javascript" charset="utf-8" src="phonegap.0.9.5.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="main.js"></script>
|
||||
|
||||
function show_pic()
|
||||
{
|
||||
var viewport = document.getElementById('viewport');
|
||||
viewport.style.display = "";
|
||||
navigator.camera.getPicture(dump_pic, fail, { quality: 50 });
|
||||
}
|
||||
|
||||
function dump_pic(data)
|
||||
{
|
||||
var viewport = document.getElementById('viewport');
|
||||
console.log(data);
|
||||
viewport.style.display = "";
|
||||
viewport.style.position = "absolute";
|
||||
viewport.style.top = "10px";
|
||||
viewport.style.left = "10px";
|
||||
document.getElementById("test_img").src = "data:image/jpeg;base64," + data;
|
||||
}
|
||||
|
||||
function close()
|
||||
{
|
||||
var viewport = document.getElementById('viewport');
|
||||
viewport.style.position = "relative";
|
||||
viewport.style.display = "none";
|
||||
}
|
||||
|
||||
function fail(fail)
|
||||
{
|
||||
alert(fail);
|
||||
}
|
||||
|
||||
// This is just to do this.
|
||||
function readFile()
|
||||
{
|
||||
navigator.file.read('/sdcard/phonegap.txt', fail , fail);
|
||||
}
|
||||
|
||||
function writeFile()
|
||||
{
|
||||
navigator.file.write('foo.txt', "This is a test of writing to a file", fail, fail);
|
||||
}
|
||||
|
||||
function get_contacts()
|
||||
{
|
||||
var obj = new ContactFindOptions();
|
||||
obj.filter="";
|
||||
obj.multiple=true;
|
||||
obj.limit=5;
|
||||
navigator.service.contacts.find(["displayName", "phoneNumbers", "emails"], count_contacts, fail, obj);
|
||||
}
|
||||
|
||||
function count_contacts(contacts)
|
||||
{
|
||||
alert(contacts.length);
|
||||
}
|
||||
|
||||
function init(){
|
||||
document.addEventListener("touchmove", preventBehavior, false);
|
||||
document.addEventListener("deviceready", deviceInfo, true);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init();" id="stage" class="theme">
|
||||
<h1>Welcome to PhoneGap!</h1>
|
||||
<h2>this file is located at assets/index.html</h2>
|
||||
<h2>this file is located at assets/www/index.html</h2>
|
||||
<div id="info">
|
||||
<h4>Platform: <span id="platform"> </span></h4>
|
||||
<h4>Version: <span id="version"> </span></h4>
|
||||
<h4>UUID: <span id="uuid"> </span></h4>
|
||||
</div>
|
||||
<h4>Platform: <span id="platform"> </span>, Version: <span id="version"> </span></h4>
|
||||
<h4>UUID: <span id="uuid"> </span>, Name: <span id="name"> </span></h4>
|
||||
<h4>Width: <span id="width"> </span>, Height: <span id="height">
|
||||
</span>, Color Depth: <span id="colorDepth"></span></h4>
|
||||
</div>
|
||||
<dl id="accel-data">
|
||||
<dt>X:</dt><dd id="x"> </dd>
|
||||
<dt>Y:</dt><dd id="y"> </dd>
|
||||
<dt>Z:</dt><dd id="z"> </dd>
|
||||
</dl>
|
||||
<a href="#" class="btn large" onclick="watchAccel();">Watch Accelerometer</a>
|
||||
<a href="#" class="btn large" onclick="toggleAccel();">Toggle Accelerometer</a>
|
||||
<a href="#" class="btn large" onclick="getLocation();">Get Location</a>
|
||||
<a href="tel://411" class="btn large">Call 411</a>
|
||||
<a href="#" class="btn large" onclick="beep();">Beep</a>
|
||||
<a href="#" class="btn large" onclick="vibrate();">Vibrate</a>
|
||||
<a href="#" class="btn large" onclick="show_pic();">Get a Picture</a>
|
||||
<a href="#" class="btn large" onclick="get_contacts();">Get phone's contacts</a>
|
||||
<a href="#" class="btn large" onclick="get_contacts();">Get Phone's Contacts</a>
|
||||
<a href="#" class="btn large" onclick="check_network();">Check Network</a>
|
||||
<div id="viewport" class="viewport" style="display: none;">
|
||||
<img style="width:60px;height:60px" id="test_img" src="" />
|
||||
</div>
|
||||
|
||||
140
example/main.js
Normal file
140
example/main.js
Normal file
@@ -0,0 +1,140 @@
|
||||
var deviceInfo = function() {
|
||||
document.getElementById("platform").innerHTML = device.platform;
|
||||
document.getElementById("version").innerHTML = device.version;
|
||||
document.getElementById("uuid").innerHTML = device.uuid;
|
||||
document.getElementById("name").innerHTML = device.name;
|
||||
document.getElementById("width").innerHTML = screen.width;
|
||||
document.getElementById("height").innerHTML = screen.height;
|
||||
document.getElementById("colorDepth").innerHTML = screen.colorDepth;
|
||||
};
|
||||
|
||||
var getLocation = function() {
|
||||
var suc = function(p) {
|
||||
alert(p.coords.latitude + " " + p.coords.longitude);
|
||||
};
|
||||
var locFail = function() {
|
||||
};
|
||||
navigator.geolocation.getCurrentPosition(suc, locFail);
|
||||
};
|
||||
|
||||
var beep = function() {
|
||||
navigator.notification.beep(2);
|
||||
};
|
||||
|
||||
var vibrate = function() {
|
||||
navigator.notification.vibrate(0);
|
||||
};
|
||||
|
||||
function roundNumber(num) {
|
||||
var dec = 3;
|
||||
var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
|
||||
return result;
|
||||
}
|
||||
|
||||
var accelerationWatch = null;
|
||||
|
||||
function updateAcceleration(a) {
|
||||
document.getElementById('x').innerHTML = roundNumber(a.x);
|
||||
document.getElementById('y').innerHTML = roundNumber(a.y);
|
||||
document.getElementById('z').innerHTML = roundNumber(a.z);
|
||||
}
|
||||
|
||||
var toggleAccel = function() {
|
||||
if (accelerationWatch !== null) {
|
||||
navigator.accelerometer.clearWatch(accelerationWatch);
|
||||
updateAcceleration({
|
||||
x : "",
|
||||
y : "",
|
||||
z : ""
|
||||
});
|
||||
accelerationWatch = null;
|
||||
} else {
|
||||
var options = {};
|
||||
options.frequency = 1000;
|
||||
accelerationWatch = navigator.accelerometer.watchAcceleration(
|
||||
updateAcceleration, function(ex) {
|
||||
alert("accel fail (" + ex.name + ": " + ex.message + ")");
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
||||
var preventBehavior = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
function dump_pic(data) {
|
||||
var viewport = document.getElementById('viewport');
|
||||
console.log(data);
|
||||
viewport.style.display = "";
|
||||
viewport.style.position = "absolute";
|
||||
viewport.style.top = "10px";
|
||||
viewport.style.left = "10px";
|
||||
document.getElementById("test_img").src = "data:image/jpeg;base64," + data;
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
function show_pic() {
|
||||
navigator.camera.getPicture(dump_pic, fail, {
|
||||
quality : 50
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
var viewport = document.getElementById('viewport');
|
||||
viewport.style.position = "relative";
|
||||
viewport.style.display = "none";
|
||||
}
|
||||
|
||||
// This is just to do this.
|
||||
function readFile() {
|
||||
navigator.file.read('/sdcard/phonegap.txt', fail, fail);
|
||||
}
|
||||
|
||||
function writeFile() {
|
||||
navigator.file.write('foo.txt', "This is a test of writing to a file",
|
||||
fail, fail);
|
||||
}
|
||||
|
||||
function contacts_success(contacts) {
|
||||
alert(contacts.length
|
||||
+ ' contacts returned.'
|
||||
+ (contacts[2] && contacts[2].name ? (' Third contact is ' + contacts[2].name.formatted)
|
||||
: ''));
|
||||
}
|
||||
|
||||
function get_contacts() {
|
||||
var obj = new ContactFindOptions();
|
||||
obj.filter = "";
|
||||
obj.multiple = true;
|
||||
obj.limit = 5;
|
||||
navigator.service.contacts.find(
|
||||
[ "displayName", "name" ], contacts_success,
|
||||
fail, obj);
|
||||
}
|
||||
|
||||
var networkReachableCallback = function(reachability) {
|
||||
// There is no consistency on the format of reachability
|
||||
var networkState = reachability.code || reachability;
|
||||
|
||||
var currentState = {};
|
||||
currentState[NetworkStatus.NOT_REACHABLE] = 'No network connection';
|
||||
currentState[NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK] = 'Carrier data connection';
|
||||
currentState[NetworkStatus.REACHABLE_VIA_WIFI_NETWORK] = 'WiFi connection';
|
||||
|
||||
confirm("Connection type:\n" + currentState[networkState]);
|
||||
};
|
||||
|
||||
function check_network() {
|
||||
navigator.network.isReachable("www.mobiledevelopersolutions.com",
|
||||
networkReachableCallback, {});
|
||||
}
|
||||
|
||||
function init() {
|
||||
// the next line makes it impossible to see Contacts on the HTC Evo since it
|
||||
// doesn't have a scroll button
|
||||
// document.addEventListener("touchmove", preventBehavior, false);
|
||||
document.addEventListener("deviceready", deviceInfo, true);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="com.phonegap" android:versionName="1.1" android:versionCode="5">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
@@ -8,21 +8,26 @@
|
||||
android:resizeable="true"
|
||||
android:anyDensity="true"
|
||||
/>
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:debuggable="true">
|
||||
<activity android:name=".StandAlone"
|
||||
@@ -33,6 +38,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
function Acceleration(x, y, z) {
|
||||
if (!PhoneGap.hasResource("accelerometer")) {
|
||||
PhoneGap.addResource("accelerometer");
|
||||
|
||||
/** @constructor */
|
||||
var Acceleration = function(x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
@@ -17,7 +21,7 @@ function Acceleration(x, y, z) {
|
||||
* This class provides access to device accelerometer data.
|
||||
* @constructor
|
||||
*/
|
||||
function Accelerometer() {
|
||||
var Accelerometer = function() {
|
||||
|
||||
/**
|
||||
* The last known acceleration. type=Acceleration()
|
||||
@@ -42,13 +46,13 @@ Accelerometer.ERROR_MSG = ["Not running", "Starting", "", "Failed to start"];
|
||||
Accelerometer.prototype.getCurrentAcceleration = function(successCallback, errorCallback, options) {
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Accelerometer Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Accelerometer Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -68,16 +72,16 @@ Accelerometer.prototype.getCurrentAcceleration = function(successCallback, error
|
||||
Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallback, options) {
|
||||
|
||||
// Default interval (10 sec)
|
||||
var frequency = (options != undefined)? options.frequency : 10000;
|
||||
var frequency = (options !== undefined)? options.frequency : 10000;
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Accelerometer Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Accelerometer Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -108,12 +112,15 @@ Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallb
|
||||
Accelerometer.prototype.clearWatch = function(id) {
|
||||
|
||||
// Stop javascript timer & remove from timer list
|
||||
if (id && navigator.accelerometer.timers[id] != undefined) {
|
||||
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();
|
||||
if (typeof navigator.accelerometer === "undefined") {
|
||||
navigator.accelerometer = new Accelerometer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
94
framework/assets/js/app.js
Executable file
94
framework/assets/js/app.js
Executable file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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("app")) {
|
||||
PhoneGap.addResource("app");
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @constructor
|
||||
*/
|
||||
var App = function() {};
|
||||
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
App.prototype.clearCache = function() {
|
||||
PhoneGap.exec(null, null, "App", "clearCache", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url The URL to load
|
||||
* @param props Properties that can be passed in to the activity:
|
||||
* wait: int => wait msec before loading URL
|
||||
* loadingDialog: "Title,Message" => display a native loading dialog
|
||||
* hideLoadingDialogOnPage: boolean => hide loadingDialog when page loaded instead of when deviceready event occurs.
|
||||
* loadInWebView: boolean => cause all links on web page to be loaded into existing web view, instead of being loaded into new browser.
|
||||
* loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error
|
||||
* errorUrl: URL => URL to load if there's an error loading specified URL with loadUrl(). Should be a local URL such as file:///android_asset/www/error.html");
|
||||
* keepRunning: boolean => enable app to keep running in background
|
||||
*
|
||||
* Example:
|
||||
* App app = new App();
|
||||
* app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
|
||||
*/
|
||||
App.prototype.loadUrl = function(url, props) {
|
||||
PhoneGap.exec(null, null, "App", "loadUrl", [url, props]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel loadUrl that is waiting to be loaded.
|
||||
*/
|
||||
App.prototype.cancelLoadUrl = function() {
|
||||
PhoneGap.exec(null, null, "App", "cancelLoadUrl", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear web history in this web view.
|
||||
* Instead of BACK button loading the previous web page, it will exit the app.
|
||||
*/
|
||||
App.prototype.clearHistory = function() {
|
||||
PhoneGap.exec(null, null, "App", "clearHistory", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
App.prototype.addService = function(serviceType, className) {
|
||||
PhoneGap.exec(null, null, "App", "addService", [serviceType, className]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
*
|
||||
* Note: The user should not have to call this method. Instead, when the user
|
||||
* registers for the "backbutton" event, this is automatically done.
|
||||
*
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
App.prototype.overrideBackbutton = function(override) {
|
||||
PhoneGap.exec(null, null, "App", "overrideBackbutton", [override]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Exit and terminate the application.
|
||||
*/
|
||||
App.prototype.exitApp = function() {
|
||||
return PhoneGap.exec(null, null, "App", "exitApp", []);
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
navigator.app = window.app = new App();
|
||||
});
|
||||
}
|
||||
@@ -3,15 +3,18 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("camera")) {
|
||||
PhoneGap.addResource("camera");
|
||||
|
||||
/**
|
||||
* This class provides access to the device camera.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
Camera = function() {
|
||||
var Camera = function() {
|
||||
this.successCallback = null;
|
||||
this.errorCallback = null;
|
||||
this.options = null;
|
||||
@@ -59,13 +62,13 @@ Camera.prototype.PictureSourceType = Camera.PictureSourceType;
|
||||
Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Camera Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Camera Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -80,12 +83,15 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
|
||||
destinationType = this.options.destinationType;
|
||||
}
|
||||
var sourceType = Camera.PictureSourceType.CAMERA;
|
||||
if (typeof this.options.sourceType == "number") {
|
||||
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();
|
||||
if (typeof navigator.camera === "undefined") {
|
||||
navigator.camera = new Camera();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
191
framework/assets/js/capture.js
Normal file
191
framework/assets/js/capture.js
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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("capture")) {
|
||||
PhoneGap.addResource("capture");
|
||||
|
||||
/**
|
||||
* Represents a single file.
|
||||
*
|
||||
* name {DOMString} name of the file, without path information
|
||||
* fullPath {DOMString} the full path of the file, including the name
|
||||
* type {DOMString} mime type
|
||||
* lastModifiedDate {Date} last modified date
|
||||
* size {Number} size of the file in bytes
|
||||
*/
|
||||
var MediaFile = function(name, fullPath, type, lastModifiedDate, size){
|
||||
this.name = name || null;
|
||||
this.fullPath = fullPath || null;
|
||||
this.type = type || null;
|
||||
this.lastModifiedDate = lastModifiedDate || null;
|
||||
this.size = size || 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch device camera application for recording video(s).
|
||||
*
|
||||
* @param {Function} successCB
|
||||
* @param {Function} errorCB
|
||||
*/
|
||||
MediaFile.prototype.getFormatData = function(successCallback, errorCallback){
|
||||
PhoneGap.exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
|
||||
};
|
||||
|
||||
/**
|
||||
* MediaFileData encapsulates format information of a media file.
|
||||
*
|
||||
* @param {DOMString} codecs
|
||||
* @param {long} bitrate
|
||||
* @param {long} height
|
||||
* @param {long} width
|
||||
* @param {float} duration
|
||||
*/
|
||||
var MediaFileData = function(codecs, bitrate, height, width, duration){
|
||||
this.codecs = codecs || null;
|
||||
this.bitrate = bitrate || 0;
|
||||
this.height = height || 0;
|
||||
this.width = width || 0;
|
||||
this.duration = duration || 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The CaptureError interface encapsulates all errors in the Capture API.
|
||||
*/
|
||||
var CaptureError = function(){
|
||||
this.code = null;
|
||||
};
|
||||
|
||||
// Capture error codes
|
||||
CaptureError.CAPTURE_INTERNAL_ERR = 0;
|
||||
CaptureError.CAPTURE_APPLICATION_BUSY = 1;
|
||||
CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
|
||||
CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
|
||||
CaptureError.CAPTURE_NOT_SUPPORTED = 20;
|
||||
|
||||
/**
|
||||
* The Capture interface exposes an interface to the camera and microphone of the hosting device.
|
||||
*/
|
||||
var Capture = function(){
|
||||
this.supportedAudioModes = [];
|
||||
this.supportedImageModes = [];
|
||||
this.supportedVideoModes = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch audio recorder application for recording audio clip(s).
|
||||
*
|
||||
* @param {Function} successCB
|
||||
* @param {Function} errorCB
|
||||
* @param {CaptureAudioOptions} options
|
||||
*/
|
||||
Capture.prototype.captureAudio = function(successCallback, errorCallback, options){
|
||||
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureAudio", [options]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch camera application for taking image(s).
|
||||
*
|
||||
* @param {Function} successCB
|
||||
* @param {Function} errorCB
|
||||
* @param {CaptureImageOptions} options
|
||||
*/
|
||||
Capture.prototype.captureImage = function(successCallback, errorCallback, options){
|
||||
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureImage", [options]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch camera application for taking image(s).
|
||||
*
|
||||
* @param {Function} successCB
|
||||
* @param {Function} errorCB
|
||||
* @param {CaptureImageOptions} options
|
||||
*/
|
||||
Capture.prototype._castMediaFile = function(pluginResult){
|
||||
var mediaFiles = [];
|
||||
var i;
|
||||
for (i = 0; i < pluginResult.message.length; i++) {
|
||||
var mediaFile = new MediaFile();
|
||||
mediaFile.name = pluginResult.message[i].name;
|
||||
mediaFile.fullPath = pluginResult.message[i].fullPath;
|
||||
mediaFile.type = pluginResult.message[i].type;
|
||||
mediaFile.lastModifiedDate = pluginResult.message[i].lastModifiedDate;
|
||||
mediaFile.size = pluginResult.message[i].size;
|
||||
mediaFiles.push(mediaFile);
|
||||
}
|
||||
pluginResult.message = mediaFiles;
|
||||
return pluginResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch device camera application for recording video(s).
|
||||
*
|
||||
* @param {Function} successCB
|
||||
* @param {Function} errorCB
|
||||
* @param {CaptureVideoOptions} options
|
||||
*/
|
||||
Capture.prototype.captureVideo = function(successCallback, errorCallback, options){
|
||||
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureVideo", [options]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates a set of parameters that the capture device supports.
|
||||
*/
|
||||
var ConfigurationData = function(){
|
||||
// The ASCII-encoded string in lower case representing the media type.
|
||||
this.type = null;
|
||||
// The height attribute represents height of the image or video in pixels.
|
||||
// In the case of a sound clip this attribute has value 0.
|
||||
this.height = 0;
|
||||
// The width attribute represents width of the image or video in pixels.
|
||||
// In the case of a sound clip this attribute has value 0
|
||||
this.width = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates all image capture operation configuration options.
|
||||
*/
|
||||
var CaptureImageOptions = function(){
|
||||
// Upper limit of images user can take. Value must be equal or greater than 1.
|
||||
this.limit = 1;
|
||||
// The selected image mode. Must match with one of the elements in supportedImageModes array.
|
||||
this.mode = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates all video capture operation configuration options.
|
||||
*/
|
||||
var CaptureVideoOptions = function(){
|
||||
// Upper limit of videos user can record. Value must be equal or greater than 1.
|
||||
this.limit = 1;
|
||||
// Maximum duration of a single video clip in seconds.
|
||||
this.duration = 0;
|
||||
// The selected video mode. Must match with one of the elements in supportedVideoModes array.
|
||||
this.mode = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates all audio capture operation configuration options.
|
||||
*/
|
||||
var CaptureAudioOptions = function(){
|
||||
// Upper limit of sound clips user can record. Value must be equal or greater than 1.
|
||||
this.limit = 1;
|
||||
// Maximum duration of a single sound clip in seconds.
|
||||
this.duration = 0;
|
||||
// The selected audio mode. Must match with one of the elements in supportedAudioModes array.
|
||||
this.mode = null;
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function(){
|
||||
if (typeof navigator.device === "undefined") {
|
||||
navigator.device = window.device = new Device();
|
||||
}
|
||||
if (typeof navigator.device.capture === "undefined") {
|
||||
navigator.device.capture = window.device.capture = new Capture();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3,14 +3,17 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("compass")) {
|
||||
PhoneGap.addResource("compass");
|
||||
|
||||
/**
|
||||
* This class provides access to device Compass data.
|
||||
* @constructor
|
||||
*/
|
||||
function Compass() {
|
||||
var Compass = function() {
|
||||
/**
|
||||
* The last known Compass position.
|
||||
*/
|
||||
@@ -34,13 +37,13 @@ Compass.ERROR_MSG = ["Not running", "Starting", "", "Failed to start"];
|
||||
Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, options) {
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Compass Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Compass Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -60,16 +63,16 @@ Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, o
|
||||
Compass.prototype.watchHeading= function(successCallback, errorCallback, options) {
|
||||
|
||||
// Default interval (100 msec)
|
||||
var frequency = (options != undefined) ? options.frequency : 100;
|
||||
var frequency = (options !== undefined) ? options.frequency : 100;
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Compass Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Compass Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -109,5 +112,8 @@ Compass.prototype.clearWatch = function(id) {
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.compass == "undefined") navigator.compass = new Compass();
|
||||
if (typeof navigator.compass === "undefined") {
|
||||
navigator.compass = new Compass();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,39 +3,37 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("contact")) {
|
||||
PhoneGap.addResource("contact");
|
||||
|
||||
/**
|
||||
* Contains information about a single contact.
|
||||
* @constructor
|
||||
* @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 {Array.<ContactField>} phoneNumbers array of phone numbers
|
||||
* @param {Array.<ContactField>} emails array of email addresses
|
||||
* @param {Array.<ContactAddress>} addresses array of addresses
|
||||
* @param {Array.<ContactField>} ims instant messaging user ids
|
||||
* @param {Array.<ContactOrganization>} organizations
|
||||
* @param {DOMString} revision 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
|
||||
* @param {Array.<ContactField>} photos
|
||||
* @param {Array.<ContactField>} categories
|
||||
* @param {Array.<ContactField>} urls contact's web sites
|
||||
* @param {DOMString} timezone the contacts time zone
|
||||
*/
|
||||
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) {
|
||||
var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
|
||||
ims, organizations, revision, birthday, gender, note, photos, categories, urls, timezone) {
|
||||
this.id = id || null;
|
||||
this.rawId = null;
|
||||
this.displayName = displayName || null;
|
||||
this.name = name || null; // ContactName
|
||||
this.nickname = nickname || null;
|
||||
@@ -44,35 +42,51 @@ var Contact = function(id, displayName, name, nickname, phoneNumbers, emails, ad
|
||||
this.addresses = addresses || null; // ContactAddress[]
|
||||
this.ims = ims || null; // ContactField[]
|
||||
this.organizations = organizations || null; // ContactOrganization[]
|
||||
this.published = published || null;
|
||||
this.updated = updated || null;
|
||||
this.revision = revision || 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.categories = categories || null; // ContactField[]
|
||||
this.urls = urls || null; // ContactField[]
|
||||
this.accounts = accounts || null; // ContactAccount[]
|
||||
this.utcOffset = utcOffset || null;
|
||||
this.connected = connected || null;
|
||||
this.timezone = timezone || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* ContactError.
|
||||
* An error code assigned by an implementation when an error has occurreds
|
||||
* @constructor
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Removes contact from device storage.
|
||||
* @param successCB success callback
|
||||
* @param errorCB error callback
|
||||
*/
|
||||
Contact.prototype.remove = function(successCB, errorCB) {
|
||||
if (this.id == null) {
|
||||
if (this.id === null) {
|
||||
var errorObj = new ContactError();
|
||||
errorObj.code = ContactError.NOT_FOUND_ERROR;
|
||||
errorCB(errorObj);
|
||||
}
|
||||
|
||||
PhoneGap.exec(successCB, errorCB, "Contacts", "remove", [this.id]);
|
||||
else {
|
||||
PhoneGap.exec(successCB, errorCB, "Contacts", "remove", [this.id]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -82,7 +96,50 @@ Contact.prototype.remove = function(successCB, errorCB) {
|
||||
*/
|
||||
Contact.prototype.clone = function() {
|
||||
var clonedContact = PhoneGap.clone(this);
|
||||
var i;
|
||||
clonedContact.id = null;
|
||||
clonedContact.rawId = null;
|
||||
// Loop through and clear out any id's in phones, emails, etc.
|
||||
if (clonedContact.phoneNumbers) {
|
||||
for (i = 0; i < clonedContact.phoneNumbers.length; i++) {
|
||||
clonedContact.phoneNumbers[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.emails) {
|
||||
for (i = 0; i < clonedContact.emails.length; i++) {
|
||||
clonedContact.emails[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.addresses) {
|
||||
for (i = 0; i < clonedContact.addresses.length; i++) {
|
||||
clonedContact.addresses[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.ims) {
|
||||
for (i = 0; i < clonedContact.ims.length; i++) {
|
||||
clonedContact.ims[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.organizations) {
|
||||
for (i = 0; i < clonedContact.organizations.length; i++) {
|
||||
clonedContact.organizations[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.tags) {
|
||||
for (i = 0; i < clonedContact.tags.length; i++) {
|
||||
clonedContact.tags[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.photos) {
|
||||
for (i = 0; i < clonedContact.photos.length; i++) {
|
||||
clonedContact.photos[i].id = null;
|
||||
}
|
||||
}
|
||||
if (clonedContact.urls) {
|
||||
for (i = 0; i < clonedContact.urls.length; i++) {
|
||||
clonedContact.urls[i].id = null;
|
||||
}
|
||||
}
|
||||
return clonedContact;
|
||||
};
|
||||
|
||||
@@ -92,10 +149,12 @@ Contact.prototype.clone = function() {
|
||||
* @param errorCB error callback
|
||||
*/
|
||||
Contact.prototype.save = function(successCB, errorCB) {
|
||||
PhoneGap.exec(successCB, errorCB, "Contacts", "save", [this]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Contact name.
|
||||
* @constructor
|
||||
* @param formatted
|
||||
* @param familyName
|
||||
* @param givenName
|
||||
@@ -114,18 +173,23 @@ var ContactName = function(formatted, familyName, givenName, middle, prefix, suf
|
||||
|
||||
/**
|
||||
* Generic contact field.
|
||||
* @constructor
|
||||
* @param {DOMString} id unique identifier, should only be set by native code
|
||||
* @param type
|
||||
* @param value
|
||||
* @param primary
|
||||
* @param pref
|
||||
*/
|
||||
var ContactField = function(type, value, primary) {
|
||||
var ContactField = function(type, value, pref) {
|
||||
this.id = null;
|
||||
this.type = type || null;
|
||||
this.value = value || null;
|
||||
this.primary = primary || null;
|
||||
this.pref = pref || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contact address.
|
||||
* @constructor
|
||||
* @param {DOMString} id unique identifier, should only be set by native code
|
||||
* @param formatted
|
||||
* @param streetAddress
|
||||
* @param locality
|
||||
@@ -134,6 +198,7 @@ var ContactField = function(type, value, primary) {
|
||||
* @param country
|
||||
*/
|
||||
var ContactAddress = function(formatted, streetAddress, locality, region, postalCode, country) {
|
||||
this.id = null;
|
||||
this.formatted = formatted || null;
|
||||
this.streetAddress = streetAddress || null;
|
||||
this.locality = locality || null;
|
||||
@@ -144,6 +209,8 @@ var ContactAddress = function(formatted, streetAddress, locality, region, postal
|
||||
|
||||
/**
|
||||
* Contact organization.
|
||||
* @constructor
|
||||
* @param {DOMString} id unique identifier, should only be set by native code
|
||||
* @param name
|
||||
* @param dept
|
||||
* @param title
|
||||
@@ -152,35 +219,21 @@ var ContactAddress = function(formatted, streetAddress, locality, region, postal
|
||||
* @param location
|
||||
* @param desc
|
||||
*/
|
||||
var ContactOrganization = function(name, dept, title, startDate, endDate, location, desc) {
|
||||
var ContactOrganization = function(name, dept, title) {
|
||||
this.id = null;
|
||||
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.
|
||||
* @constructor
|
||||
*/
|
||||
var Contacts = function() {
|
||||
this.inProgress = false;
|
||||
this.records = new Array();
|
||||
}
|
||||
this.records = [];
|
||||
};
|
||||
/**
|
||||
* Returns an array of Contacts matching the search criteria.
|
||||
* @param fields that should be searched
|
||||
@@ -201,53 +254,56 @@ Contacts.prototype.find = function(fields, successCB, errorCB, options) {
|
||||
* @returns new Contact object
|
||||
*/
|
||||
Contacts.prototype.create = function(properties) {
|
||||
var contact = new Contact();
|
||||
var i;
|
||||
var contact = new Contact();
|
||||
for (i in properties) {
|
||||
if (contact[i]!='undefined') {
|
||||
contact[i]=properties[i];
|
||||
if (contact[i] !== 'undefined') {
|
||||
contact[i] = properties[i];
|
||||
}
|
||||
}
|
||||
return contact;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function returns and array of contacts. It is required as we need to convert raw
|
||||
* JSON objects into concrete Contact objects. Currently this method is called after
|
||||
* navigator.service.contacts.find but before the find methods success call back.
|
||||
*
|
||||
* @param jsonArray an array of JSON Objects that need to be converted to Contact objects.
|
||||
* @returns an array of Contact objects
|
||||
*/
|
||||
Contacts.prototype.cast = function(pluginResult) {
|
||||
var contacts = [];
|
||||
var i;
|
||||
for (i=0; i<pluginResult.message.length; i++) {
|
||||
contacts.push(navigator.service.contacts.create(pluginResult.message[i]));
|
||||
}
|
||||
pluginResult.message = contacts;
|
||||
return pluginResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* ContactFindOptions.
|
||||
* @constructor
|
||||
* @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) {
|
||||
var ContactFindOptions = function(filter, multiple, updatedSince) {
|
||||
this.filter = filter || '';
|
||||
this.multiple = multiple || false;
|
||||
this.limit = limit || 1;
|
||||
this.multiple = multiple || true;
|
||||
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();
|
||||
if(typeof navigator.service === "undefined") {
|
||||
navigator.service = {};
|
||||
}
|
||||
if(typeof navigator.service.contacts === "undefined") {
|
||||
navigator.service.contacts = new Contacts();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,11 +3,17 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
// TODO: Needs to be commented
|
||||
|
||||
if (!PhoneGap.hasResource("crypto")) {
|
||||
PhoneGap.addResource("crypto");
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var Crypto = function() {
|
||||
};
|
||||
|
||||
@@ -30,6 +36,8 @@ Crypto.prototype.getPlainString = function(string) {
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.Crypto == "undefined") navigator.Crypto = new Crypto();
|
||||
if (typeof navigator.Crypto === "undefined") {
|
||||
navigator.Crypto = new Crypto();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("device")) {
|
||||
PhoneGap.addResource("device");
|
||||
|
||||
/**
|
||||
* This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
|
||||
* phone, etc.
|
||||
* @constructor
|
||||
*/
|
||||
function Device() {
|
||||
var Device = function() {
|
||||
this.available = PhoneGap.available;
|
||||
this.platform = null;
|
||||
this.version = null;
|
||||
@@ -25,6 +28,7 @@ function Device() {
|
||||
me.available = true;
|
||||
me.platform = info.platform;
|
||||
me.version = info.version;
|
||||
me.name = info.name;
|
||||
me.uuid = info.uuid;
|
||||
me.phonegap = info.phonegap;
|
||||
PhoneGap.onPhoneGapInfoReady.fire();
|
||||
@@ -34,7 +38,7 @@ function Device() {
|
||||
console.log("Error initializing PhoneGap: " + e);
|
||||
alert("Error initializing PhoneGap: "+e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get device info
|
||||
@@ -45,13 +49,13 @@ function Device() {
|
||||
Device.prototype.getInfo = function(successCallback, errorCallback) {
|
||||
|
||||
// successCallback required
|
||||
if (typeof successCallback != "function") {
|
||||
if (typeof successCallback !== "function") {
|
||||
console.log("Device Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Device Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -61,32 +65,41 @@ Device.prototype.getInfo = function(successCallback, errorCallback) {
|
||||
};
|
||||
|
||||
/*
|
||||
* DEPRECATED
|
||||
* This is only for Android.
|
||||
*
|
||||
* You must explicitly override the back button.
|
||||
*/
|
||||
Device.prototype.overrideBackButton = function() {
|
||||
BackButton.override();
|
||||
}
|
||||
console.log("Device.overrideBackButton() is deprecated. Use App.overrideBackbutton(true).");
|
||||
navigator.app.overrideBackbutton(true);
|
||||
};
|
||||
|
||||
/*
|
||||
* DEPRECATED
|
||||
* This is only for Android.
|
||||
*
|
||||
* This resets the back button to the default behaviour
|
||||
*/
|
||||
Device.prototype.resetBackButton = function() {
|
||||
BackButton.reset();
|
||||
}
|
||||
console.log("Device.resetBackButton() is deprecated. Use App.overrideBackbutton(false).");
|
||||
navigator.app.overrideBackbutton(false);
|
||||
};
|
||||
|
||||
/*
|
||||
* DEPRECATED
|
||||
* This is only for Android.
|
||||
*
|
||||
* This terminates the activity!
|
||||
*/
|
||||
Device.prototype.exitApp = function() {
|
||||
BackButton.exitApp();
|
||||
}
|
||||
console.log("Device.exitApp() is deprecated. Use App.exitApp().");
|
||||
navigator.app.exitApp();
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
navigator.device = window.device = new Device();
|
||||
if (typeof navigator.device === "undefined") {
|
||||
navigator.device = window.device = new Device();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
85
framework/assets/js/filetransfer.js
Normal file
85
framework/assets/js/filetransfer.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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("filetransfer")) {
|
||||
PhoneGap.addResource("filetransfer");
|
||||
|
||||
/**
|
||||
* FileTransfer uploads a file to a remote server.
|
||||
* @constructor
|
||||
*/
|
||||
var FileTransfer = function() {};
|
||||
|
||||
/**
|
||||
* FileUploadResult
|
||||
* @constructor
|
||||
*/
|
||||
var FileUploadResult = function() {
|
||||
this.bytesSent = 0;
|
||||
this.responseCode = null;
|
||||
this.response = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* FileTransferError
|
||||
* @constructor
|
||||
*/
|
||||
var FileTransferError = function() {
|
||||
this.code = null;
|
||||
};
|
||||
|
||||
FileTransferError.FILE_NOT_FOUND_ERR = 1;
|
||||
FileTransferError.INVALID_URL_ERR = 2;
|
||||
FileTransferError.CONNECTION_ERR = 3;
|
||||
|
||||
/**
|
||||
* Given an absolute file path, uploads a file on the device to a remote server
|
||||
* using a multipart HTTP request.
|
||||
* @param filePath {String} Full path of the file on the device
|
||||
* @param server {String} URL of the server to receive the file
|
||||
* @param successCallback (Function} Callback to be invoked when upload has completed
|
||||
* @param errorCallback {Function} Callback to be invoked upon error
|
||||
* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
|
||||
*/
|
||||
FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, debug) {
|
||||
|
||||
// check for options
|
||||
var fileKey = null;
|
||||
var fileName = null;
|
||||
var mimeType = null;
|
||||
var params = null;
|
||||
if (options) {
|
||||
fileKey = options.fileKey;
|
||||
fileName = options.fileName;
|
||||
mimeType = options.mimeType;
|
||||
if (options.params) {
|
||||
params = options.params;
|
||||
}
|
||||
else {
|
||||
params = {};
|
||||
}
|
||||
}
|
||||
|
||||
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to customize the HTTP request used to upload files.
|
||||
* @constructor
|
||||
* @param fileKey {String} Name of file request parameter.
|
||||
* @param fileName {String} Filename to be used by the server. Defaults to image.jpg.
|
||||
* @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg.
|
||||
* @param params {Object} Object with key: value params to send to the server.
|
||||
*/
|
||||
var FileUploadOptions = function(fileKey, fileName, mimeType, params) {
|
||||
this.fileKey = fileKey || null;
|
||||
this.fileName = fileName || null;
|
||||
this.mimeType = mimeType || null;
|
||||
this.params = params || null;
|
||||
};
|
||||
}
|
||||
@@ -3,14 +3,17 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("geolocation")) {
|
||||
PhoneGap.addResource("geolocation");
|
||||
|
||||
/**
|
||||
* This class provides access to device GPS data.
|
||||
* @constructor
|
||||
*/
|
||||
function Geolocation() {
|
||||
var Geolocation = function() {
|
||||
|
||||
// The last known GPS position.
|
||||
this.lastPosition = null;
|
||||
@@ -22,10 +25,11 @@ function Geolocation() {
|
||||
/**
|
||||
* Position error object
|
||||
*
|
||||
* @constructor
|
||||
* @param code
|
||||
* @param message
|
||||
*/
|
||||
function PositionError(code, message) {
|
||||
var PositionError = function(code, message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
};
|
||||
@@ -42,7 +46,7 @@ PositionError.TIMEOUT = 3;
|
||||
* @param {PositionOptions} options The options for getting the position data. (OPTIONAL)
|
||||
*/
|
||||
Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) {
|
||||
if (navigator._geo.listeners["global"]) {
|
||||
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."));
|
||||
@@ -53,20 +57,20 @@ Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallba
|
||||
var maximumAge = 10000;
|
||||
var enableHighAccuracy = false;
|
||||
var timeout = 10000;
|
||||
if (typeof options != "undefined") {
|
||||
if (typeof options.maximumAge != "undefined") {
|
||||
if (typeof options !== "undefined") {
|
||||
if (typeof options.maximumAge !== "undefined") {
|
||||
maximumAge = options.maximumAge;
|
||||
}
|
||||
if (typeof options.enableHighAccuracy != "undefined") {
|
||||
if (typeof options.enableHighAccuracy !== "undefined") {
|
||||
enableHighAccuracy = options.enableHighAccuracy;
|
||||
}
|
||||
if (typeof options.timeout != "undefined") {
|
||||
if (typeof options.timeout !== "undefined") {
|
||||
timeout = options.timeout;
|
||||
}
|
||||
}
|
||||
navigator._geo.listeners["global"] = {"success" : successCallback, "fail" : errorCallback };
|
||||
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,
|
||||
@@ -81,17 +85,17 @@ Geolocation.prototype.watchPosition = function(successCallback, errorCallback, o
|
||||
var maximumAge = 10000;
|
||||
var enableHighAccuracy = false;
|
||||
var timeout = 10000;
|
||||
if (typeof options != "undefined") {
|
||||
if (typeof options.frequency != "undefined") {
|
||||
if (typeof options !== "undefined") {
|
||||
if (typeof options.frequency !== "undefined") {
|
||||
maximumAge = options.frequency;
|
||||
}
|
||||
if (typeof options.maximumAge != "undefined") {
|
||||
if (typeof options.maximumAge !== "undefined") {
|
||||
maximumAge = options.maximumAge;
|
||||
}
|
||||
if (typeof options.enableHighAccuracy != "undefined") {
|
||||
if (typeof options.enableHighAccuracy !== "undefined") {
|
||||
enableHighAccuracy = options.enableHighAccuracy;
|
||||
}
|
||||
if (typeof options.timeout != "undefined") {
|
||||
if (typeof options.timeout !== "undefined") {
|
||||
timeout = options.timeout;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +122,7 @@ Geolocation.prototype.success = function(id, lat, lng, alt, altacc, head, vel, s
|
||||
var coords = new Coordinates(lat, lng, alt, altacc, head, vel);
|
||||
var loc = new Position(coords, stamp);
|
||||
try {
|
||||
if (lat == "undefined" || lng == "undefined") {
|
||||
if (lat === "undefined" || lng === "undefined") {
|
||||
navigator._geo.listeners[id].fail(new PositionError(PositionError.POSITION_UNAVAILABLE, "Lat/Lng are undefined."));
|
||||
}
|
||||
else {
|
||||
@@ -130,8 +134,8 @@ Geolocation.prototype.success = function(id, lat, lng, alt, altacc, head, vel, s
|
||||
console.log("Geolocation Error: Error calling success callback function.");
|
||||
}
|
||||
|
||||
if (id == "global") {
|
||||
delete navigator._geo.listeners["global"];
|
||||
if (id === "global") {
|
||||
delete navigator._geo.listeners.global;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -186,9 +190,9 @@ PhoneGap.addConstructor(function() {
|
||||
navigator._geo = new Geolocation();
|
||||
|
||||
// No native geolocation object for Android 1.x, so use PhoneGap geolocation
|
||||
if (typeof navigator.geolocation == 'undefined') {
|
||||
if (typeof navigator.geolocation === 'undefined') {
|
||||
navigator.geolocation = navigator._geo;
|
||||
Geolocation.usingPhoneGap = true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,3 @@
|
||||
* 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
|
||||
}
|
||||
});
|
||||
@@ -1,23 +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
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -3,66 +3,16 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!PhoneGap.hasResource("media")) {
|
||||
PhoneGap.addResource("media");
|
||||
|
||||
/**
|
||||
* This class provides access to the device media, interfaces to both sound and video
|
||||
*
|
||||
* @constructor
|
||||
* @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
|
||||
@@ -73,28 +23,28 @@ PhoneGap.Media.onStatus = function(id, msg, value) {
|
||||
* @param positionCallback The callback to be called when media position has changed.
|
||||
* positionCallback(long position) - OPTIONAL
|
||||
*/
|
||||
Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
|
||||
var Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
|
||||
|
||||
// successCallback optional
|
||||
if (successCallback && (typeof successCallback != "function")) {
|
||||
if (successCallback && (typeof successCallback !== "function")) {
|
||||
console.log("Media Error: successCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// errorCallback optional
|
||||
if (errorCallback && (typeof errorCallback != "function")) {
|
||||
if (errorCallback && (typeof errorCallback !== "function")) {
|
||||
console.log("Media Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// statusCallback optional
|
||||
if (statusCallback && (typeof statusCallback != "function")) {
|
||||
if (statusCallback && (typeof statusCallback !== "function")) {
|
||||
console.log("Media Error: statusCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// statusCallback optional
|
||||
if (positionCallback && (typeof positionCallback != "function")) {
|
||||
if (positionCallback && (typeof positionCallback !== "function")) {
|
||||
console.log("Media Error: positionCallback is not a function");
|
||||
return;
|
||||
}
|
||||
@@ -128,8 +78,8 @@ Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
|
||||
* This class contains information about any Media errors.
|
||||
* @constructor
|
||||
*/
|
||||
function MediaError() {
|
||||
this.code = null,
|
||||
var MediaError = function() {
|
||||
this.code = null;
|
||||
this.message = "";
|
||||
};
|
||||
|
||||
@@ -152,6 +102,13 @@ Media.prototype.stop = function() {
|
||||
return PhoneGap.exec(null, null, "Media", "stopPlayingAudio", [this.id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Seek or jump to a new time in the track..
|
||||
*/
|
||||
Media.prototype.seekTo = function(milliseconds) {
|
||||
PhoneGap.exec(null, null, "Media", "seekToAudio", [this.id, milliseconds]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause playing audio file.
|
||||
*/
|
||||
@@ -171,8 +128,6 @@ Media.prototype.getDuration = function() {
|
||||
|
||||
/**
|
||||
* Get position of audio.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Media.prototype.getCurrentPosition = function(success, fail) {
|
||||
PhoneGap.exec(success, fail, "Media", "getCurrentPositionAudio", [this.id]);
|
||||
@@ -192,3 +147,65 @@ Media.prototype.stopRecord = function() {
|
||||
PhoneGap.exec(null, null, "Media", "stopRecordingAudio", [this.id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Release the resources.
|
||||
*/
|
||||
Media.prototype.release = function() {
|
||||
PhoneGap.exec(null, null, "Media", "release", [this.id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* List of media objects.
|
||||
* PRIVATE
|
||||
*/
|
||||
PhoneGap.mediaObjects = {};
|
||||
|
||||
/**
|
||||
* Object that receives native callbacks.
|
||||
* PRIVATE
|
||||
* @constructor
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("network")) {
|
||||
PhoneGap.addResource("network");
|
||||
|
||||
/**
|
||||
* This class contains information about any NetworkStatus.
|
||||
* @constructor
|
||||
*/
|
||||
function NetworkStatus() {
|
||||
var NetworkStatus = function() {
|
||||
//this.code = null;
|
||||
//this.message = "";
|
||||
};
|
||||
@@ -23,7 +26,7 @@ NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
|
||||
* This class provides access to device Network data (reachability).
|
||||
* @constructor
|
||||
*/
|
||||
function Network() {
|
||||
var Network = function() {
|
||||
/**
|
||||
* The last known Network status.
|
||||
* { hostName: string, ipAddress: string,
|
||||
@@ -56,7 +59,74 @@ Network.prototype.isReachable = function(uri, callback, options) {
|
||||
PhoneGap.exec(callback, null, "Network Status", "isReachable", [uri, isIpAddress]);
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.network == "undefined") navigator.network = new Network();
|
||||
});
|
||||
/**
|
||||
* This class contains information about the current network Connection.
|
||||
* @constructor
|
||||
*/
|
||||
var Connection = function() {
|
||||
this.type = null;
|
||||
this._firstRun = true;
|
||||
this._timer = null;
|
||||
this.timeout = 500;
|
||||
|
||||
var me = this;
|
||||
this.getInfo(
|
||||
function(type) {
|
||||
// Need to send events if we are on or offline
|
||||
if (type == "none") {
|
||||
// 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');
|
||||
me._timer = null;
|
||||
}, me.timeout);
|
||||
} else {
|
||||
// If there is a current offline event pending clear it
|
||||
if (me._timer != null) {
|
||||
clearTimeout(me._timer);
|
||||
me._timer = null;
|
||||
}
|
||||
me.type = type;
|
||||
PhoneGap.fireEvent('online');
|
||||
}
|
||||
|
||||
// should only fire this once
|
||||
if (me._firstRun) {
|
||||
me._firstRun = false;
|
||||
PhoneGap.onPhoneGapConnectionReady.fire();
|
||||
}
|
||||
},
|
||||
function(e) {
|
||||
console.log("Error initializing Network Connection: " + e);
|
||||
});
|
||||
};
|
||||
|
||||
Connection.UNKNOWN = "unknown";
|
||||
Connection.ETHERNET = "ethernet";
|
||||
Connection.WIFI = "wifi";
|
||||
Connection.CELL_2G = "2g";
|
||||
Connection.CELL_3G = "3g";
|
||||
Connection.CELL_4G = "4g";
|
||||
Connection.NONE = "none";
|
||||
|
||||
/**
|
||||
* Get connection info
|
||||
*
|
||||
* @param {Function} successCallback The function to call when the Connection data is available
|
||||
* @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL)
|
||||
*/
|
||||
Connection.prototype.getInfo = function(successCallback, errorCallback) {
|
||||
// Get info
|
||||
PhoneGap.exec(successCallback, errorCallback, "Network Status", "getConnectionInfo", []);
|
||||
};
|
||||
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.network === "undefined") {
|
||||
navigator.network = new Network();
|
||||
}
|
||||
if (typeof navigator.network.connection === "undefined") {
|
||||
navigator.network.connection = new Connection();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,14 +3,18 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("notification")) {
|
||||
PhoneGap.addResource("notification");
|
||||
|
||||
/**
|
||||
* This class provides access to notifications on the device.
|
||||
* @constructor
|
||||
*/
|
||||
function Notification() {
|
||||
}
|
||||
var Notification = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a native alert dialog, with a customizable title and button text.
|
||||
@@ -111,6 +115,8 @@ Notification.prototype.beep = function(count) {
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.notification == "undefined") navigator.notification = new Notification();
|
||||
if (typeof navigator.notification === "undefined") {
|
||||
navigator.notification = new Notification();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* 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
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (typeof PhoneGap === "undefined") {
|
||||
|
||||
/**
|
||||
* The order of events during page load and PhoneGap startup is as follows:
|
||||
@@ -18,6 +19,8 @@
|
||||
* 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
|
||||
* onPause User event fired to indicate a pause lifecycle event
|
||||
* onDestroy Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
|
||||
*
|
||||
* The only PhoneGap events that user code should register for are:
|
||||
* onDeviceReady
|
||||
@@ -26,10 +29,12 @@
|
||||
* Listeners can be registered as:
|
||||
* document.addEventListener("deviceready", myDeviceReadyListener, false);
|
||||
* document.addEventListener("resume", myResumeListener, false);
|
||||
* document.addEventListener("pause", myPauseListener, false);
|
||||
*/
|
||||
|
||||
if (typeof(DeviceInfo) != 'object')
|
||||
DeviceInfo = {};
|
||||
if (typeof(DeviceInfo) !== 'object') {
|
||||
var DeviceInfo = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents the PhoneGap API itself, and provides a global namespace for accessing
|
||||
@@ -44,11 +49,36 @@ var PhoneGap = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* List of resource files loaded by PhoneGap.
|
||||
* This is used to ensure JS and other files are loaded only once.
|
||||
*/
|
||||
PhoneGap.resources = {base: true};
|
||||
|
||||
/**
|
||||
* Determine if resource has been loaded by PhoneGap
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
PhoneGap.hasResource = function(name) {
|
||||
return PhoneGap.resources[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a resource to list of loaded resources by PhoneGap
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
PhoneGap.addResource = function(name) {
|
||||
PhoneGap.resources[name] = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom pub-sub channel that can have functions subscribed to it
|
||||
* @constructor
|
||||
*/
|
||||
PhoneGap.Channel = function(type)
|
||||
PhoneGap.Channel = function (type)
|
||||
{
|
||||
this.type = type;
|
||||
this.handlers = {};
|
||||
@@ -58,7 +88,7 @@ PhoneGap.Channel = function(type)
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribes the given function to the channel. Any time that
|
||||
* 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.
|
||||
@@ -66,10 +96,10 @@ PhoneGap.Channel = function(type)
|
||||
*/
|
||||
PhoneGap.Channel.prototype.subscribe = function(f, c, g) {
|
||||
// need a function to call
|
||||
if (f == null) { return; }
|
||||
if (f === null) { return; }
|
||||
|
||||
var func = f;
|
||||
if (typeof c == "object" && f instanceof Function) { func = PhoneGap.close(c, f); }
|
||||
if (typeof c === "object" && typeof f === "function") { func = PhoneGap.close(c, f); }
|
||||
|
||||
g = g || func.observer_guid || f.observer_guid || this.guid++;
|
||||
func.observer_guid = g;
|
||||
@@ -88,9 +118,9 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
|
||||
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); }
|
||||
if (typeof c === "object" && typeof f === "function") { f = PhoneGap.close(c, f); }
|
||||
f.apply(this, this.fireArgs);
|
||||
} else {
|
||||
g = this.subscribe(m);
|
||||
@@ -98,26 +128,29 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
|
||||
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; }
|
||||
if (typeof g === "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;
|
||||
var item, handler, rv;
|
||||
for (item in this.handlers) {
|
||||
if (this.handlers.hasOwnProperty(item)) {
|
||||
handler = this.handlers[item];
|
||||
if (typeof handler === "function") {
|
||||
rv = (handler.apply(this, arguments) === false);
|
||||
fail = fail || rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.fired = true;
|
||||
@@ -134,18 +167,29 @@ PhoneGap.Channel.prototype.fire = function(e) {
|
||||
PhoneGap.Channel.join = function(h, c) {
|
||||
var i = c.length;
|
||||
var f = function() {
|
||||
if (!(--i)) h();
|
||||
if (!(--i)) {
|
||||
h();
|
||||
}
|
||||
};
|
||||
var len = i;
|
||||
var j;
|
||||
for (j=0; j<len; j++) {
|
||||
if (!c[j].fired) {
|
||||
c[j].subscribeOnce(f);
|
||||
}
|
||||
else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
for (var j=0; j<i; j++) {
|
||||
(!c[j].fired?c[j].subscribeOnce(f):i--);
|
||||
if (!i) {
|
||||
h();
|
||||
}
|
||||
if (!i) h();
|
||||
};
|
||||
|
||||
/**
|
||||
* Boolean flag indicating if the PhoneGap API is available and initialized.
|
||||
*/ // TODO: Remove this, it is unused here ... -jm
|
||||
PhoneGap.available = DeviceInfo.uuid != undefined;
|
||||
PhoneGap.available = DeviceInfo.uuid !== undefined;
|
||||
|
||||
/**
|
||||
* Add an initialization function to a queue that ensures it will run and initialize
|
||||
@@ -157,30 +201,36 @@ PhoneGap.addConstructor = function(func) {
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
if (typeof(debug['log']) == 'function') {
|
||||
debug.log("Failed to run constructor: " + debug.processMessage(e));
|
||||
} else {
|
||||
alert("Failed to run constructor: " + e.message);
|
||||
}
|
||||
console.log("Failed to run constructor: " + e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a plugin object to window.plugins
|
||||
* Plugins object
|
||||
*/
|
||||
PhoneGap.addPlugin = function(name, obj) {
|
||||
if ( !window.plugins ) {
|
||||
window.plugins = {};
|
||||
}
|
||||
|
||||
if ( !window.plugins[name] ) {
|
||||
window.plugins[name] = obj;
|
||||
}
|
||||
if (!window.plugins) {
|
||||
window.plugins = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* onDOMContentLoaded channel is fired when the DOM content
|
||||
* Adds a plugin object to window.plugins.
|
||||
* The plugin is accessed using window.plugins.<name>
|
||||
*
|
||||
* @param name The plugin name
|
||||
* @param obj The plugin object
|
||||
*/
|
||||
PhoneGap.addPlugin = function(name, obj) {
|
||||
if (!window.plugins[name]) {
|
||||
window.plugins[name] = obj;
|
||||
}
|
||||
else {
|
||||
console.log("Error: Plugin "+name+" already exists.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* onDOMContentLoaded channel is fired when the DOM content
|
||||
* of the page has been parsed.
|
||||
*/
|
||||
PhoneGap.onDOMContentLoaded = new PhoneGap.Channel('onDOMContentLoaded');
|
||||
@@ -208,6 +258,12 @@ PhoneGap.onPhoneGapReady = new PhoneGap.Channel('onPhoneGapReady');
|
||||
*/
|
||||
PhoneGap.onPhoneGapInfoReady = new PhoneGap.Channel('onPhoneGapInfoReady');
|
||||
|
||||
/**
|
||||
* onPhoneGapConnectionReady channel is fired when the PhoneGap connection properties
|
||||
* has been set.
|
||||
*/
|
||||
PhoneGap.onPhoneGapConnectionReady = new PhoneGap.Channel('onPhoneGapConnectionReady');
|
||||
|
||||
/**
|
||||
* onResume channel is fired when the PhoneGap native code
|
||||
* resumes.
|
||||
@@ -220,8 +276,19 @@ PhoneGap.onResume = new PhoneGap.Channel('onResume');
|
||||
*/
|
||||
PhoneGap.onPause = new PhoneGap.Channel('onPause');
|
||||
|
||||
/**
|
||||
* onDestroy channel is fired when the PhoneGap native code
|
||||
* is destroyed. It is used internally.
|
||||
* Window.onunload should be used by the user.
|
||||
*/
|
||||
PhoneGap.onDestroy = new PhoneGap.Channel('onDestroy');
|
||||
PhoneGap.onDestroy.subscribeOnce(function() {
|
||||
PhoneGap.shuttingDown = true;
|
||||
});
|
||||
PhoneGap.shuttingDown = false;
|
||||
|
||||
// _nativeReady is global variable that the native side can set
|
||||
// to signify that the native code is ready. It is a global since
|
||||
// to signify that the native code is ready. It is a global since
|
||||
// it may be called before any PhoneGap JS is ready.
|
||||
if (typeof _nativeReady !== 'undefined') { PhoneGap.onNativeReady.fire(); }
|
||||
|
||||
@@ -232,6 +299,39 @@ if (typeof _nativeReady !== 'undefined') { PhoneGap.onNativeReady.fire(); }
|
||||
PhoneGap.onDeviceReady = new PhoneGap.Channel('onDeviceReady');
|
||||
|
||||
|
||||
// Array of channels that must fire before "deviceready" is fired
|
||||
PhoneGap.deviceReadyChannelsArray = [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady, PhoneGap.onPhoneGapConnectionReady];
|
||||
|
||||
// Hashtable of user defined channels that must also fire before "deviceready" is fired
|
||||
PhoneGap.deviceReadyChannelsMap = {};
|
||||
|
||||
/**
|
||||
* Indicate that a feature needs to be initialized before it is ready to be used.
|
||||
* This holds up PhoneGap's "deviceready" event until the feature has been initialized
|
||||
* and PhoneGap.initComplete(feature) is called.
|
||||
*
|
||||
* @param feature {String} The unique feature name
|
||||
*/
|
||||
PhoneGap.waitForInitialization = function(feature) {
|
||||
if (feature) {
|
||||
var channel = new PhoneGap.Channel(feature);
|
||||
PhoneGap.deviceReadyChannelsMap[feature] = channel;
|
||||
PhoneGap.deviceReadyChannelsArray.push(channel);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicate that initialization code has completed and the feature is ready to be used.
|
||||
*
|
||||
* @param feature {String} The unique feature name
|
||||
*/
|
||||
PhoneGap.initializationComplete = function(feature) {
|
||||
var channel = PhoneGap.deviceReadyChannelsMap[feature];
|
||||
if (channel) {
|
||||
channel.fire();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create all PhoneGap objects once page has fully loaded and native side is ready.
|
||||
*/
|
||||
@@ -239,11 +339,20 @@ PhoneGap.Channel.join(function() {
|
||||
|
||||
// Start listening for XHR callbacks
|
||||
setTimeout(function() {
|
||||
if (CallbackServer.usePolling()) {
|
||||
if (PhoneGap.UsePolling) {
|
||||
PhoneGap.JSCallbackPolling();
|
||||
}
|
||||
else {
|
||||
PhoneGap.JSCallback();
|
||||
var polling = prompt("usePolling", "gap_callbackServer:");
|
||||
PhoneGap.UsePolling = polling;
|
||||
if (polling == "true") {
|
||||
PhoneGap.UsePolling = true;
|
||||
PhoneGap.JSCallbackPolling();
|
||||
}
|
||||
else {
|
||||
PhoneGap.UsePolling = false;
|
||||
PhoneGap.JSCallback();
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
|
||||
@@ -253,22 +362,21 @@ PhoneGap.Channel.join(function() {
|
||||
// Fire event to notify that all objects are created
|
||||
PhoneGap.onPhoneGapReady.fire();
|
||||
|
||||
// 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() {
|
||||
|
||||
// Turn off app loading dialog
|
||||
navigator.notification.activityStop();
|
||||
|
||||
PhoneGap.onDeviceReady.fire();
|
||||
|
||||
// Fire the onresume event, since first one happens before JavaScript is loaded
|
||||
PhoneGap.onResume.fire();
|
||||
}, PhoneGap.deviceReadyChannelsArray);
|
||||
|
||||
}, [ PhoneGap.onDOMContentLoaded, PhoneGap.onNativeReady ]);
|
||||
|
||||
/**
|
||||
* Fire onDeviceReady event once all constructors have run and PhoneGap info has been
|
||||
* received from native side.
|
||||
*/
|
||||
PhoneGap.Channel.join(function() {
|
||||
// Turn off app loading dialog
|
||||
navigator.notification.activityStop();
|
||||
|
||||
PhoneGap.onDeviceReady.fire();
|
||||
|
||||
// Fire the onresume event, since first one happens before JavaScript is loaded
|
||||
PhoneGap.onResume.fire();
|
||||
}, [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady]);
|
||||
|
||||
// Listen for DOMContentLoaded and notify our channel subscribers
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
PhoneGap.onDOMContentLoaded.fire();
|
||||
@@ -279,15 +387,48 @@ PhoneGap.m_document_addEventListener = document.addEventListener;
|
||||
|
||||
document.addEventListener = function(evt, handler, capture) {
|
||||
var e = evt.toLowerCase();
|
||||
if (e == 'deviceready') {
|
||||
if (e === 'deviceready') {
|
||||
PhoneGap.onDeviceReady.subscribeOnce(handler);
|
||||
} else if (e == 'resume') {
|
||||
} else if (e === 'resume') {
|
||||
PhoneGap.onResume.subscribe(handler);
|
||||
} else if (e == 'pause') {
|
||||
if (PhoneGap.onDeviceReady.fired) {
|
||||
PhoneGap.onResume.fire();
|
||||
}
|
||||
} else if (e === 'pause') {
|
||||
PhoneGap.onPause.subscribe(handler);
|
||||
} else {
|
||||
PhoneGap.m_document_addEventListener.call(document, evt, handler);
|
||||
}
|
||||
else {
|
||||
// If subscribing to Android backbutton
|
||||
if (e === 'backbutton') {
|
||||
PhoneGap.exec(null, null, "App", "overrideBackbutton", [true]);
|
||||
}
|
||||
|
||||
PhoneGap.m_document_addEventListener.call(document, 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;
|
||||
|
||||
document.removeEventListener = function(evt, handler, capture) {
|
||||
var e = evt.toLowerCase();
|
||||
|
||||
// If unsubscribing to Android backbutton
|
||||
if (e === 'backbutton') {
|
||||
PhoneGap.exec(null, null, "App", "overrideBackbutton", [false]);
|
||||
}
|
||||
|
||||
PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to fire event from native code
|
||||
*/
|
||||
PhoneGap.fireEvent = function(type) {
|
||||
var e = document.createEvent('Events');
|
||||
e.initEvent(type);
|
||||
document.dispatchEvent(e);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -295,51 +436,56 @@ document.addEventListener = function(evt, handler, capture) {
|
||||
* The restriction on ours is that it must be an array of simple types.
|
||||
*
|
||||
* @param args
|
||||
* @return
|
||||
* @return {String}
|
||||
*/
|
||||
PhoneGap.stringify = function(args) {
|
||||
if (typeof JSON == "undefined") {
|
||||
if (typeof JSON === "undefined") {
|
||||
var s = "[";
|
||||
for (var i=0; i<args.length; i++) {
|
||||
if (i > 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 + '"';
|
||||
var i, type, start, name, nameType, a;
|
||||
for (i = 0; i < args.length; i++) {
|
||||
if (args[i] !== null) {
|
||||
if (i > 0) {
|
||||
s = s + ",";
|
||||
}
|
||||
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) {
|
||||
start = true;
|
||||
s = s + '{';
|
||||
for (name in args[i]) {
|
||||
if (args[i][name] !== null) {
|
||||
if (!start) {
|
||||
s = s + ',';
|
||||
}
|
||||
s = s + '"' + name + '":';
|
||||
nameType = typeof args[i][name];
|
||||
if ((nameType === "number") || (nameType === "boolean")) {
|
||||
s = s + args[i][name];
|
||||
} else if ((typeof args[i][name]) === 'function') {
|
||||
// don't copy the functions
|
||||
s = s + '""';
|
||||
} else if (args[i][name] instanceof Object) {
|
||||
s = s + PhoneGap.stringify(args[i][name]);
|
||||
} else {
|
||||
s = s + '"' + args[i][name] + '"';
|
||||
}
|
||||
start = false;
|
||||
}
|
||||
}
|
||||
s = s + '}';
|
||||
} else {
|
||||
a = args[i].replace(/\\/g, '\\\\');
|
||||
a = a.replace(/"/g, '\\"');
|
||||
s = s + '"' + a + '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
s = s + "]";
|
||||
return s;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return JSON.stringify(args);
|
||||
}
|
||||
};
|
||||
@@ -348,36 +494,41 @@ PhoneGap.stringify = function(args) {
|
||||
* Does a deep clone of the object.
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
* @return {Object}
|
||||
*/
|
||||
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;
|
||||
var i, retVal;
|
||||
if(!obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(obj instanceof Array){
|
||||
retVal = [];
|
||||
for(i = 0; i < obj.length; ++i){
|
||||
retVal.push(PhoneGap.clone(obj[i]));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
if (typeof obj === "function") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(!(obj instanceof Object)){
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj instanceof Date) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
retVal = {};
|
||||
for(i in obj){
|
||||
if(!(i in retVal) || retVal[i] !== obj[i]) {
|
||||
retVal[i] = PhoneGap.clone(obj[i]);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
};
|
||||
|
||||
PhoneGap.callbackId = 0;
|
||||
@@ -397,7 +548,7 @@ PhoneGap.callbackStatus = {
|
||||
|
||||
|
||||
/**
|
||||
* Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
|
||||
* 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 ""
|
||||
@@ -408,7 +559,7 @@ PhoneGap.callbackStatus = {
|
||||
* @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
|
||||
* @param {Array.<String>} [args] Zero or more arguments to pass to the method
|
||||
*/
|
||||
PhoneGap.exec = function(success, fail, service, action, args) {
|
||||
try {
|
||||
@@ -416,24 +567,23 @@ PhoneGap.exec = function(success, fail, service, action, args) {
|
||||
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);
|
||||
|
||||
|
||||
var r = prompt(PhoneGap.stringify(args), "gap:"+PhoneGap.stringify([service, action, callbackId, 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 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);
|
||||
} catch (e) {
|
||||
console.log("Error in success callback: " + callbackId + " = " + e);
|
||||
}
|
||||
|
||||
// Clear callback if not expecting any more results
|
||||
@@ -445,8 +595,8 @@ PhoneGap.exec = function(success, fail, service, action, args) {
|
||||
}
|
||||
|
||||
// If no result
|
||||
else if (v.status == PhoneGap.callbackStatus.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];
|
||||
@@ -455,15 +605,15 @@ PhoneGap.exec = function(success, fail, service, action, args) {
|
||||
|
||||
// If error, then display error
|
||||
else {
|
||||
console.log("Error: Status="+r.status+" Message="+v.message);
|
||||
console.log("Error: Status="+v.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);
|
||||
catch (e1) {
|
||||
console.log("Error in error callback: "+callbackId+" = "+e1);
|
||||
}
|
||||
|
||||
// Clear callback if not expecting any more results
|
||||
@@ -474,8 +624,8 @@ PhoneGap.exec = function(success, fail, service, action, args) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error: "+e);
|
||||
} catch (e2) {
|
||||
console.log("Error: "+e2);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -489,7 +639,7 @@ PhoneGap.callbackSuccess = function(callbackId, args) {
|
||||
if (PhoneGap.callbacks[callbackId]) {
|
||||
|
||||
// If result is to be sent to callback
|
||||
if (args.status == PhoneGap.callbackStatus.OK) {
|
||||
if (args.status === PhoneGap.callbackStatus.OK) {
|
||||
try {
|
||||
if (PhoneGap.callbacks[callbackId].success) {
|
||||
PhoneGap.callbacks[callbackId].success(args.message);
|
||||
@@ -499,7 +649,7 @@ PhoneGap.callbackSuccess = function(callbackId, args) {
|
||||
console.log("Error in success callback: "+callbackId+" = "+e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clear callback if not expecting any more results
|
||||
if (!args.keepCallback) {
|
||||
delete PhoneGap.callbacks[callbackId];
|
||||
@@ -523,7 +673,7 @@ PhoneGap.callbackError = function(callbackId, args) {
|
||||
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];
|
||||
@@ -541,71 +691,94 @@ PhoneGap.callbackError = function(callbackId, args) {
|
||||
*/
|
||||
// TODO: Is this used?
|
||||
PhoneGap.run_command = function() {
|
||||
if (!PhoneGap.available || !PhoneGap.queue.ready)
|
||||
if (!PhoneGap.available || !PhoneGap.queue.ready) {
|
||||
return;
|
||||
|
||||
}
|
||||
PhoneGap.queue.ready = false;
|
||||
|
||||
var args = PhoneGap.queue.commands.shift();
|
||||
if (PhoneGap.queue.commands.length == 0) {
|
||||
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 i;
|
||||
for (i = 1; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (arg == undefined || arg == null)
|
||||
if (arg === undefined || arg === null) {
|
||||
arg = '';
|
||||
if (typeof(arg) == 'object')
|
||||
}
|
||||
if (typeof(arg) === 'object') {
|
||||
dict = arg;
|
||||
else
|
||||
} else {
|
||||
uri.push(encodeURIComponent(arg));
|
||||
}
|
||||
}
|
||||
var url = "gap://" + args[0] + "/" + uri.join("/");
|
||||
if (dict != null) {
|
||||
if (dict !== null) {
|
||||
var name;
|
||||
var query_args = [];
|
||||
for (var name in dict) {
|
||||
if (typeof(name) != 'string')
|
||||
continue;
|
||||
query_args.push(encodeURIComponent(name) + "=" + encodeURIComponent(dict[name]));
|
||||
for (name in dict) {
|
||||
if (dict.hasOwnProperty(name) && (typeof (name) === 'string')) {
|
||||
query_args.push(encodeURIComponent(name) + "=" + encodeURIComponent(dict[name]));
|
||||
}
|
||||
}
|
||||
if (query_args.length > 0)
|
||||
if (query_args.length > 0) {
|
||||
url += "?" + query_args.join("&");
|
||||
}
|
||||
}
|
||||
document.location = url;
|
||||
|
||||
};
|
||||
|
||||
PhoneGap.JSCallbackPort = CallbackServer.getPort();
|
||||
PhoneGap.JSCallbackToken = CallbackServer.getToken();
|
||||
PhoneGap.JSCallbackPort = null;
|
||||
PhoneGap.JSCallbackToken = null;
|
||||
|
||||
/**
|
||||
* This is only for Android.
|
||||
*
|
||||
* Internal function that uses XHR to call into PhoneGap Java code and retrieve
|
||||
* 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() {
|
||||
|
||||
// Exit if shutting down app
|
||||
if (PhoneGap.shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If polling flag was changed, start using polling from now on
|
||||
if (PhoneGap.UsePolling) {
|
||||
PhoneGap.JSCallbackPolling();
|
||||
return;
|
||||
}
|
||||
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
|
||||
// Callback function when XMLHttpRequest is ready
|
||||
xmlhttp.onreadystatechange=function(){
|
||||
if(xmlhttp.readyState == 4){
|
||||
if(xmlhttp.readyState === 4){
|
||||
|
||||
// Exit if shutting down app
|
||||
if (PhoneGap.shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If callback has JavaScript statement to execute
|
||||
if (xmlhttp.status == 200) {
|
||||
if (xmlhttp.status === 200) {
|
||||
|
||||
var msg = xmlhttp.responseText;
|
||||
// Need to url decode the response
|
||||
var msg = decodeURIComponent(xmlhttp.responseText);
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var t = eval(msg);
|
||||
}
|
||||
catch (e) {
|
||||
// If we're getting an error here, seeing the message will help in debugging
|
||||
console.log("Message from Server: " + msg);
|
||||
console.log("JSCallback: Message from Server: " + msg);
|
||||
console.log("JSCallback Error: "+e);
|
||||
}
|
||||
}, 1);
|
||||
@@ -613,19 +786,40 @@ PhoneGap.JSCallback = function() {
|
||||
}
|
||||
|
||||
// If callback ping (used to keep XHR request from timing out)
|
||||
else if (xmlhttp.status == 404) {
|
||||
else if (xmlhttp.status === 404) {
|
||||
setTimeout(PhoneGap.JSCallback, 10);
|
||||
}
|
||||
|
||||
// If error, restart callback server
|
||||
// If security error
|
||||
else if (xmlhttp.status === 403) {
|
||||
console.log("JSCallback Error: Invalid token. Stopping callbacks.");
|
||||
}
|
||||
|
||||
// If server is stopping
|
||||
else if (xmlhttp.status === 503) {
|
||||
console.log("JSCallback Error: Service unavailable. Stopping callbacks.");
|
||||
}
|
||||
|
||||
// If request wasn't GET
|
||||
else if (xmlhttp.status === 400) {
|
||||
console.log("JSCallback Error: Bad request. Stopping callbacks.");
|
||||
}
|
||||
|
||||
// If error, revert to polling
|
||||
else {
|
||||
console.log("JSCallback Error: Request failed.");
|
||||
CallbackServer.restartServer();
|
||||
setTimeout(PhoneGap.JSCallback, 100);
|
||||
PhoneGap.UsePolling = true;
|
||||
PhoneGap.JSCallbackPolling();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (PhoneGap.JSCallbackPort === null) {
|
||||
PhoneGap.JSCallbackPort = prompt("getPort", "gap_callbackServer:");
|
||||
}
|
||||
if (PhoneGap.JSCallbackToken === null) {
|
||||
PhoneGap.JSCallbackToken = prompt("getToken", "gap_callbackServer:");
|
||||
}
|
||||
xmlhttp.open("GET", "http://127.0.0.1:"+PhoneGap.JSCallbackPort+"/"+PhoneGap.JSCallbackToken , true);
|
||||
xmlhttp.send();
|
||||
};
|
||||
@@ -636,21 +830,39 @@ PhoneGap.JSCallback = function() {
|
||||
*/
|
||||
PhoneGap.JSCallbackPollingPeriod = 50;
|
||||
|
||||
/**
|
||||
* Flag that can be set by the user to force polling to be used or force XHR to be used.
|
||||
*/
|
||||
PhoneGap.UsePolling = false; // T=use polling, F=use XHR
|
||||
|
||||
/**
|
||||
* This is only for Android.
|
||||
*
|
||||
* Internal function that uses polling to call into PhoneGap Java code and retrieve
|
||||
* 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();
|
||||
|
||||
// Exit if shutting down app
|
||||
if (PhoneGap.shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If polling flag was changed, stop using polling from now on
|
||||
if (!PhoneGap.UsePolling) {
|
||||
PhoneGap.JSCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = prompt("", "gap_poll:");
|
||||
if (msg) {
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var t = eval(""+msg);
|
||||
}
|
||||
catch (e) {
|
||||
console.log("JSCallbackPolling: Message from Server: " + msg);
|
||||
console.log("JSCallbackPolling Error: "+e);
|
||||
}
|
||||
}, 1);
|
||||
@@ -664,7 +876,7 @@ PhoneGap.JSCallbackPolling = function() {
|
||||
/**
|
||||
* Create a UUID
|
||||
*
|
||||
* @return
|
||||
* @return {String}
|
||||
*/
|
||||
PhoneGap.createUUID = function() {
|
||||
return PhoneGap.UUIDcreatePart(4) + '-' +
|
||||
@@ -676,9 +888,10 @@ PhoneGap.createUUID = function() {
|
||||
|
||||
PhoneGap.UUIDcreatePart = function(length) {
|
||||
var uuidpart = "";
|
||||
for (var i=0; i<length; i++) {
|
||||
var uuidchar = parseInt((Math.random() * 256)).toString(16);
|
||||
if (uuidchar.length == 1) {
|
||||
var i, uuidchar;
|
||||
for (i=0; i<length; i++) {
|
||||
uuidchar = parseInt((Math.random() * 256),0).toString(16);
|
||||
if (uuidchar.length === 1) {
|
||||
uuidchar = "0" + uuidchar;
|
||||
}
|
||||
uuidpart += uuidchar;
|
||||
@@ -690,11 +903,45 @@ PhoneGap.close = function(context, func, params) {
|
||||
if (typeof params === 'undefined') {
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function() {
|
||||
return func.apply(context, params);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a JavaScript file after page has loaded.
|
||||
*
|
||||
* @param {String} jsfile The url of the JavaScript file to load.
|
||||
* @param {Function} successCallback The callback to call when the file has been loaded.
|
||||
*/
|
||||
PhoneGap.includeJavascript = function(jsfile, successCallback) {
|
||||
var id = document.getElementsByTagName("head")[0];
|
||||
var el = document.createElement('script');
|
||||
el.type = 'text/javascript';
|
||||
if (typeof successCallback === 'function') {
|
||||
el.onload = successCallback;
|
||||
}
|
||||
el.src = jsfile;
|
||||
id.appendChild(el);
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is provided to bridge the gap between the way plugins were setup in 0.9.3 and 0.9.4.
|
||||
* Users should be calling navigator.add.addService() instead of PluginManager.addService().
|
||||
* @class
|
||||
* @deprecated
|
||||
*/
|
||||
var PluginManager = {
|
||||
addService: function(serviceType, className) {
|
||||
try {
|
||||
navigator.app.addService(serviceType, className);
|
||||
} catch (e) {
|
||||
console.log("Error adding service "+serviceType+": "+e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("position")) {
|
||||
PhoneGap.addResource("position");
|
||||
|
||||
/**
|
||||
* This class contains position information.
|
||||
* @param {Object} lat
|
||||
@@ -17,12 +20,13 @@
|
||||
* @param {Object} vel
|
||||
* @constructor
|
||||
*/
|
||||
function Position(coords, timestamp) {
|
||||
var Position = function(coords, timestamp) {
|
||||
this.coords = coords;
|
||||
this.timestamp = (timestamp != 'undefined') ? timestamp : new Date().getTime();
|
||||
}
|
||||
this.timestamp = (timestamp !== 'undefined') ? timestamp : new Date().getTime();
|
||||
};
|
||||
|
||||
function Coordinates(lat, lng, alt, acc, head, vel, altacc) {
|
||||
/** @constructor */
|
||||
var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
|
||||
/**
|
||||
* The latitude of the position.
|
||||
*/
|
||||
@@ -50,14 +54,14 @@ function Coordinates(lat, lng, alt, acc, head, vel, altacc) {
|
||||
/**
|
||||
* The altitude accuracy of the position.
|
||||
*/
|
||||
this.altitudeAccuracy = (altacc != 'undefined') ? altacc : null;
|
||||
}
|
||||
this.altitudeAccuracy = (altacc !== 'undefined') ? altacc : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class specifies the options for requesting position data.
|
||||
* @constructor
|
||||
*/
|
||||
function PositionOptions() {
|
||||
var PositionOptions = function() {
|
||||
/**
|
||||
* Specifies the desired position accuracy.
|
||||
*/
|
||||
@@ -67,18 +71,19 @@ function PositionOptions() {
|
||||
* is called.
|
||||
*/
|
||||
this.timeout = 10000;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class contains information about any GSP errors.
|
||||
* @constructor
|
||||
*/
|
||||
function PositionError() {
|
||||
var PositionError = function() {
|
||||
this.code = null;
|
||||
this.message = "";
|
||||
}
|
||||
};
|
||||
|
||||
PositionError.UNKNOWN_ERROR = 0;
|
||||
PositionError.PERMISSION_DENIED = 1;
|
||||
PositionError.POSITION_UNAVAILABLE = 2;
|
||||
PositionError.TIMEOUT = 3;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -12,29 +12,45 @@
|
||||
* most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
|
||||
*/
|
||||
|
||||
if (!PhoneGap.hasResource("storage")) {
|
||||
PhoneGap.addResource("storage");
|
||||
|
||||
/**
|
||||
* Storage object that is called by native code when performing queries.
|
||||
* SQL result set object
|
||||
* PRIVATE METHOD
|
||||
* @constructor
|
||||
*/
|
||||
var DroidDB = function() {
|
||||
this.queryQueue = {};
|
||||
var DroidDB_Rows = function() {
|
||||
this.resultSet = []; // results array
|
||||
this.length = 0; // number of rows
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback from native code when result from a query is available.
|
||||
* PRIVATE METHOD
|
||||
* Get item from SQL result set
|
||||
*
|
||||
* @param rawdata JSON string of the row data
|
||||
* @param id Query id
|
||||
* @param row The row number to return
|
||||
* @return The row object
|
||||
*/
|
||||
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);
|
||||
}
|
||||
DroidDB_Rows.prototype.item = function(row) {
|
||||
return this.resultSet[row];
|
||||
};
|
||||
|
||||
/**
|
||||
* SQL result set that is returned to user.
|
||||
* PRIVATE METHOD
|
||||
* @constructor
|
||||
*/
|
||||
var DroidDB_Result = function() {
|
||||
this.rows = new DroidDB_Rows();
|
||||
};
|
||||
|
||||
/**
|
||||
* Storage object that is called by native code when performing queries.
|
||||
* PRIVATE METHOD
|
||||
* @constructor
|
||||
*/
|
||||
var DroidDB = function() {
|
||||
this.queryQueue = {};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -43,7 +59,7 @@ DroidDB.prototype.addResult = function(rawdata, id) {
|
||||
*
|
||||
* @param id Query id
|
||||
*/
|
||||
DroidDB.prototype.completeQuery = function(id) {
|
||||
DroidDB.prototype.completeQuery = function(id, data) {
|
||||
var query = this.queryQueue[id];
|
||||
if (query) {
|
||||
try {
|
||||
@@ -59,10 +75,10 @@ DroidDB.prototype.completeQuery = function(id) {
|
||||
|
||||
// Save query results
|
||||
var r = new DroidDB_Result();
|
||||
r.rows.resultSet = query.resultSet;
|
||||
r.rows.length = query.resultSet.length;
|
||||
r.rows.resultSet = data;
|
||||
r.rows.length = data.length;
|
||||
try {
|
||||
if (typeof query.successCallback == 'function') {
|
||||
if (typeof query.successCallback === 'function') {
|
||||
query.successCallback(query.tx, r);
|
||||
}
|
||||
} catch (ex) {
|
||||
@@ -100,7 +116,7 @@ DroidDB.prototype.fail = function(reason, id) {
|
||||
tx.queryList = {};
|
||||
|
||||
try {
|
||||
if (typeof query.errorCallback == 'function') {
|
||||
if (typeof query.errorCallback === 'function') {
|
||||
query.errorCallback(query.tx, reason);
|
||||
}
|
||||
} catch (ex) {
|
||||
@@ -116,38 +132,40 @@ DroidDB.prototype.fail = function(reason, id) {
|
||||
}
|
||||
};
|
||||
|
||||
var DatabaseShell = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a transaction.
|
||||
* Does not support rollback in event of failure.
|
||||
* SQL query object
|
||||
* PRIVATE METHOD
|
||||
*
|
||||
* @param process {Function} The transaction function
|
||||
* @param successCallback {Function}
|
||||
* @param errorCallback {Function}
|
||||
* @constructor
|
||||
* @param tx The transaction object that this query belongs to
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Transaction object
|
||||
* PRIVATE METHOD
|
||||
* @constructor
|
||||
*/
|
||||
var DroidDB_Tx = function() {
|
||||
|
||||
@@ -174,10 +192,13 @@ DroidDB_Tx.prototype.queryComplete = function(id) {
|
||||
// If no more outstanding queries, then fire transaction success
|
||||
if (this.successCallback) {
|
||||
var count = 0;
|
||||
for (var i in this.queryList) {
|
||||
count++;
|
||||
var i;
|
||||
for (i in this.queryList) {
|
||||
if (this.queryList.hasOwnProperty(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
if (count === 0) {
|
||||
try {
|
||||
this.successCallback();
|
||||
} catch(e) {
|
||||
@@ -210,35 +231,6 @@ DroidDB_Tx.prototype.queryFailed = function(id, reason) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@@ -250,7 +242,7 @@ var DroidDB_Query = function(tx) {
|
||||
DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) {
|
||||
|
||||
// Init params array
|
||||
if (typeof params == 'undefined') {
|
||||
if (typeof params === 'undefined') {
|
||||
params = [];
|
||||
}
|
||||
|
||||
@@ -266,31 +258,33 @@ DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCa
|
||||
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();
|
||||
var DatabaseShell = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Start a transaction.
|
||||
* Does not support rollback in event of failure.
|
||||
*
|
||||
* @param row The row number to return
|
||||
* @return The row object
|
||||
* @param process {Function} The transaction function
|
||||
* @param successCallback {Function}
|
||||
* @param errorCallback {Function}
|
||||
*/
|
||||
DroidDB_Rows.prototype.item = function(row) {
|
||||
return this.resultSet[row];
|
||||
DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -302,15 +296,133 @@ DroidDB_Rows.prototype.item = function(row) {
|
||||
* @param size Database size in bytes
|
||||
* @return Database object
|
||||
*/
|
||||
DroidDB_openDatabase = function(name, version, display_name, size) {
|
||||
var 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
|
||||
* TODO: Do similar for sessionStorage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var CupcakeLocalStorage = function() {
|
||||
try {
|
||||
|
||||
this.db = openDatabase('localStorage', '1.0', 'localStorage', 2621440);
|
||||
var storage = {};
|
||||
this.length = 0;
|
||||
function setLength (length) {
|
||||
this.length = length;
|
||||
localStorage.length = length;
|
||||
}
|
||||
this.db.transaction(
|
||||
function (transaction) {
|
||||
var i;
|
||||
transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
|
||||
transaction.executeSql('SELECT * FROM storage', [], function(tx, result) {
|
||||
for(var i = 0; i < result.rows.length; i++) {
|
||||
storage[result.rows.item(i)['id']] = result.rows.item(i)['body'];
|
||||
}
|
||||
setLength(result.rows.length);
|
||||
PhoneGap.initializationComplete("cupcakeStorage");
|
||||
});
|
||||
|
||||
},
|
||||
function (err) {
|
||||
alert(err.message);
|
||||
}
|
||||
);
|
||||
this.setItem = function(key, val) {
|
||||
if (typeof(storage[key])=='undefined') {
|
||||
this.length++;
|
||||
}
|
||||
storage[key] = val;
|
||||
this.db.transaction(
|
||||
function (transaction) {
|
||||
transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
|
||||
transaction.executeSql('REPLACE INTO storage (id, body) values(?,?)', [key,val]);
|
||||
}
|
||||
);
|
||||
};
|
||||
this.getItem = function(key) {
|
||||
return storage[key];
|
||||
};
|
||||
this.removeItem = function(key) {
|
||||
delete storage[key];
|
||||
this.length--;
|
||||
this.db.transaction(
|
||||
function (transaction) {
|
||||
transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
|
||||
transaction.executeSql('DELETE FROM storage where id=?', [key]);
|
||||
}
|
||||
);
|
||||
};
|
||||
this.clear = function() {
|
||||
storage = {};
|
||||
this.length = 0;
|
||||
this.db.transaction(
|
||||
function (transaction) {
|
||||
transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
|
||||
transaction.executeSql('DELETE FROM storage', []);
|
||||
}
|
||||
);
|
||||
};
|
||||
this.key = function(index) {
|
||||
var i = 0;
|
||||
for (var j in storage) {
|
||||
if (i==index) {
|
||||
return j;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
} catch(e) {
|
||||
alert("Database error "+e+".");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof window.openDatabase == "undefined") {
|
||||
var setupDroidDB = function() {
|
||||
navigator.openDatabase = window.openDatabase = DroidDB_openDatabase;
|
||||
window.droiddb = new DroidDB();
|
||||
}
|
||||
if (typeof window.openDatabase === "undefined") {
|
||||
setupDroidDB();
|
||||
} else {
|
||||
window.openDatabase_orig = window.openDatabase;
|
||||
window.openDatabase = function(name, version, desc, size){
|
||||
// Some versions of Android will throw a SECURITY_ERR so we need
|
||||
// to catch the exception and seutp our own DB handling.
|
||||
var db = null;
|
||||
try {
|
||||
db = window.openDatabase_orig(name, version, desc, size);
|
||||
}
|
||||
catch (ex) {
|
||||
db = null;
|
||||
}
|
||||
|
||||
if (db == null) {
|
||||
setupDroidDB();
|
||||
return DroidDB_openDatabase(name, version, desc, size);
|
||||
}
|
||||
else {
|
||||
return db;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window.localStorage === "undefined") {
|
||||
navigator.localStorage = window.localStorage = new CupcakeLocalStorage();
|
||||
PhoneGap.waitForInitialization("cupcakeStorage");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
9
framework/assets/www/index.html
Normal file
9
framework/assets/www/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="phonegap.0.9.5.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
73
framework/build.xml
Normal file → Executable file
73
framework/build.xml
Normal file → Executable file
@@ -1,6 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="PhoneGap" default="help">
|
||||
|
||||
<!-- LOAD VERSION -->
|
||||
<loadfile property="version" srcFile="../VERSION">
|
||||
<filterchain>
|
||||
<striplinebreaks/>
|
||||
</filterchain>
|
||||
</loadfile>
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked in in Version
|
||||
Control Systems. -->
|
||||
@@ -73,7 +80,7 @@
|
||||
<include name="lint.js" />
|
||||
</fileset>
|
||||
<fileset dir="assets/www">
|
||||
<include name="phonegap.js" />
|
||||
<include name="phonegap.${version}.js" />
|
||||
</fileset>
|
||||
</concat>
|
||||
|
||||
@@ -95,16 +102,72 @@
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="build-javascript">
|
||||
<delete file="assets/www/phonegap.js"/>
|
||||
<concat destfile="assets/www/phonegap.js">
|
||||
<!-- Combine JavaScript files into one phonegap.js file.
|
||||
This task does not create a compressed JavaScript file. -->
|
||||
<target name="build-uncompressed-javascript">
|
||||
|
||||
<!-- Clean up existing files -->
|
||||
<delete file="assets/www/phonegap.${version}.min.js"/>
|
||||
<delete file="assets/www/phonegap-tmp.js"/>
|
||||
<delete file="assets/www/phonegap.${version}.js"/>
|
||||
|
||||
<!-- Create uncompressed JS file -->
|
||||
<concat destfile="assets/www/phonegap.${version}.js">
|
||||
<fileset dir="assets/js" includes="phonegap.js.base" />
|
||||
<fileset dir="assets/js" includes="*.js" />
|
||||
</concat>
|
||||
|
||||
<!-- update project files to reference phonegap-x.x.x.js -->
|
||||
<replaceregexp match="phonegap(.*)\.js" replace="phonegap.${version}.js" byline="true">
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../example/index.html" />
|
||||
</replaceregexp>
|
||||
</target>
|
||||
|
||||
<!-- Combine JavaScript files into one phonegap-uncompressed.js file.
|
||||
Compress this file using yuicompressor to create phonegap.js. -->
|
||||
<target name="build-javascript">
|
||||
|
||||
<!-- Clean up existing files -->
|
||||
<delete file="assets/www/phonegap_${version}.min.js"/>
|
||||
<delete file="assets/www/phonegap-tmp.js"/>
|
||||
<delete file="assets/www/phonegap_${version}.js"/>
|
||||
|
||||
<!-- Create uncompressed JS file -->
|
||||
<concat destfile="assets/www/phonegap.${version}.js">
|
||||
<fileset dir="assets/js" includes="phonegap.js.base" />
|
||||
<fileset dir="assets/js" includes="*.js" />
|
||||
</concat>
|
||||
|
||||
<!-- Compress JS file -->
|
||||
<java jar="${basedir}/../util/yuicompressor/yuicompressor-2.4.2.jar" fork="true" failonerror="true">
|
||||
<arg line="--nomunge -o assets/www/phonegap-tmp.js assets/www/phonegap.${version}.js"/>
|
||||
</java>
|
||||
<concat destfile="assets/www/phonegap.${version}.min.js">
|
||||
<fileset dir="assets/js" includes="header.txt" />
|
||||
<fileset dir="assets/www" includes="phonegap-tmp.js" />
|
||||
</concat>
|
||||
|
||||
<!-- update project files to reference phonegap-x.x.x.min.js -->
|
||||
<replaceregexp match="phonegap(.*)\.js" replace="phonegap.${version}.min.js" byline="true">
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../example/index.html" />
|
||||
</replaceregexp>
|
||||
|
||||
<!-- Delete temp file -->
|
||||
<delete file="assets/www/phonegap-tmp.js"/>
|
||||
</target>
|
||||
|
||||
<!-- Build PhoneGap jar file that includes all native code, and PhoneGap JS file
|
||||
that includes all JavaScript code.
|
||||
|
||||
The default is to compress the JavaScript code using yuicompressor.
|
||||
|
||||
If you want uncompressed JavaScript, change
|
||||
"build-javascript" => "build-uncompressed-javascript".
|
||||
-->
|
||||
<target name="jar" depends="build-javascript, compile">
|
||||
<jar jarfile="phonegap.jar" basedir="bin/classes" excludes="**/R*.class" />
|
||||
<jar jarfile="phonegap.${version}.jar" basedir="bin/classes" excludes="com/phonegap/R.class,com/phonegap/R$*.class"/>
|
||||
</target>
|
||||
|
||||
<target name="phonegap_debug" depends="build-javascript, debug">
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=android-8
|
||||
target=android-12
|
||||
apk-configurations=
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.phonegap;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
public static final int splash=0x7f020001;
|
||||
}
|
||||
public static final class id {
|
||||
public static final int appView=0x7f050000;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int main=0x7f030000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f040000;
|
||||
public static final int go=0x7f040001;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
@@ -60,7 +61,7 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
173
framework/src/com/phonegap/App.java
Executable file
173
framework/src/com/phonegap/App.java
Executable file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* This class exposes methods in DroidGap that can be called from JavaScript.
|
||||
*/
|
||||
public class App extends Plugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("clearCache")) {
|
||||
this.clearCache();
|
||||
}
|
||||
else if (action.equals("loadUrl")) {
|
||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||
}
|
||||
else if (action.equals("cancelLoadUrl")) {
|
||||
this.cancelLoadUrl();
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
}
|
||||
else if (action.equals("addService")) {
|
||||
this.addService(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("overrideBackbutton")) {
|
||||
this.overrideBackbutton(args.getBoolean(0));
|
||||
}
|
||||
else if (action.equals("isBackbuttonOverridden")) {
|
||||
boolean b = this.isBackbuttonOverridden();
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
public void clearCache() {
|
||||
((DroidGap)this.ctx).clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
* @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void loadUrl(String url, JSONObject props) throws JSONException {
|
||||
System.out.println("App.loadUrl("+url+","+props+")");
|
||||
int wait = 0;
|
||||
|
||||
// If there are properties, then set them on the Activity
|
||||
if (props != null) {
|
||||
JSONArray keys = props.names();
|
||||
for (int i=0; i<keys.length(); i++) {
|
||||
String key = keys.getString(i);
|
||||
if (key.equals("wait")) {
|
||||
wait = props.getInt(key);
|
||||
}
|
||||
else {
|
||||
Object value = props.get(key);
|
||||
if (value == null) {
|
||||
|
||||
}
|
||||
else if (value.getClass().equals(String.class)) {
|
||||
this.ctx.getIntent().putExtra(key, (String)value);
|
||||
}
|
||||
else if (value.getClass().equals(Boolean.class)) {
|
||||
this.ctx.getIntent().putExtra(key, (Boolean)value);
|
||||
}
|
||||
else if (value.getClass().equals(Integer.class)) {
|
||||
this.ctx.getIntent().putExtra(key, (Integer)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If wait property, then delay loading
|
||||
if (wait > 0) {
|
||||
((DroidGap)this.ctx).loadUrl(url, wait);
|
||||
}
|
||||
else {
|
||||
((DroidGap)this.ctx).loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel loadUrl before it has been loaded.
|
||||
*/
|
||||
public void cancelLoadUrl() {
|
||||
((DroidGap)this.ctx).cancelLoadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear web history in this web view.
|
||||
*/
|
||||
public void clearHistory() {
|
||||
((DroidGap)this.ctx).clearHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
public void addService(String serviceType, String className) {
|
||||
this.ctx.addService(serviceType, className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
*
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
public void overrideBackbutton(boolean override) {
|
||||
System.out.println("WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
||||
((DroidGap)this.ctx).bound = override;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the Android back button is overridden by the user.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isBackbuttonOverridden() {
|
||||
return ((DroidGap)this.ctx).bound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the Android application.
|
||||
*/
|
||||
public void exitApp() {
|
||||
((DroidGap)this.ctx).finish();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
|
||||
/**
|
||||
* This class called by DroidGap to play and record audio.
|
||||
* This class called by PhonegapActivity to play and record audio.
|
||||
* The file can be local or over a network using http.
|
||||
*
|
||||
* Audio formats supported (tested):
|
||||
@@ -63,6 +63,9 @@ public class AudioHandler extends Plugin {
|
||||
else if (action.equals("startPlayingAudio")) {
|
||||
this.startPlayingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("seekToAudio")) {
|
||||
this.seekToAudio(args.getString(0), args.getInt(1));
|
||||
}
|
||||
else if (action.equals("pausePlayingAudio")) {
|
||||
this.pausePlayingAudio(args.getString(0));
|
||||
}
|
||||
@@ -70,12 +73,16 @@ public class AudioHandler extends Plugin {
|
||||
this.stopPlayingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("getCurrentPositionAudio")) {
|
||||
long l = this.getCurrentPositionAudio(args.getString(0));
|
||||
return new PluginResult(status, l);
|
||||
float f = this.getCurrentPositionAudio(args.getString(0));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
long l = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||
return new PluginResult(status, l);
|
||||
float f = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("release")) {
|
||||
boolean b = this.release(args.getString(0));
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
@@ -83,7 +90,7 @@ public class AudioHandler extends Plugin {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
@@ -117,6 +124,21 @@ public class AudioHandler extends Plugin {
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release the audio player instance to save memory.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
private boolean release(String id) {
|
||||
if (!this.players.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
this.players.remove(id);
|
||||
audio.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording and save the specified file.
|
||||
@@ -162,6 +184,20 @@ public class AudioHandler extends Plugin {
|
||||
audio.startPlaying(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to a location.
|
||||
*
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
|
||||
*/
|
||||
public void seekToAudio(String id, int milliseconds) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.seekToPlaying(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*
|
||||
@@ -194,10 +230,10 @@ public class AudioHandler extends Plugin {
|
||||
* @param id The id of the audio player
|
||||
* @return position in msec
|
||||
*/
|
||||
public long getCurrentPositionAudio(String id) {
|
||||
public float getCurrentPositionAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return(audio.getCurrentPosition());
|
||||
return(audio.getCurrentPosition()/1000.0f);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -209,7 +245,7 @@ public class AudioHandler extends Plugin {
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
*/
|
||||
public long getDurationAudio(String id, String file) {
|
||||
public float getDurationAudio(String id, String file) {
|
||||
|
||||
// Get audio file
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaRecorder;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.os.Environment;
|
||||
|
||||
/**
|
||||
* This class implements the audio playback and recording capabilities used by PhoneGap.
|
||||
@@ -53,7 +54,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
private String id; // The id of this player (used to identify Media object in JavaScript)
|
||||
private int state = MEDIA_NONE; // State of recording or playback
|
||||
private String audioFile = null; // File name to play or record to
|
||||
private long duration = -1; // Duration of audio
|
||||
private float duration = -1; // Duration of audio
|
||||
|
||||
private MediaRecorder recorder = null; // Audio recording object
|
||||
private String tempFile = null; // Temporary recording file name
|
||||
@@ -70,10 +71,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
public AudioPlayer(AudioHandler handler, String id) {
|
||||
this.handler = handler;
|
||||
this.id = id;
|
||||
|
||||
// YES, I know this is bad, but I can't do it the right way because Google didn't have the
|
||||
// foresight to add android.os.environment.getExternalDataDirectory until Android 2.2
|
||||
this.tempFile = "/sdcard/tmprecording.mp3";
|
||||
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +207,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
this.mPlayer.prepare();
|
||||
|
||||
// Get duration
|
||||
this.duration = this.mPlayer.getDuration();
|
||||
this.duration = getDurationInSeconds();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -233,6 +231,15 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek or jump to a new time in the track.
|
||||
*/
|
||||
public void seekToPlaying(int milliseconds) {
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.seekTo(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*/
|
||||
@@ -310,7 +317,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
* -1=can't be determined
|
||||
* -2=not allowed
|
||||
*/
|
||||
public long getDuration(String file) {
|
||||
public float getDuration(String file) {
|
||||
|
||||
// Can't get duration of recording
|
||||
if (this.recorder != null) {
|
||||
@@ -353,7 +360,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
}
|
||||
|
||||
// Save off duration
|
||||
this.duration = this.mPlayer.getDuration();
|
||||
this.duration = getDurationInSeconds();
|
||||
this.prepareOnly = false;
|
||||
|
||||
// Send status notification to JavaScript
|
||||
@@ -361,6 +368,15 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* By default Android returns the length of audio in mills but we want seconds
|
||||
*
|
||||
* @return length of clip in seconds
|
||||
*/
|
||||
private float getDurationInSeconds() {
|
||||
return (this.mPlayer.getDuration() / 1000.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when there has been an error during an asynchronous operation
|
||||
* (other errors will throw exceptions at method call time).
|
||||
|
||||
@@ -1,51 +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.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/*
|
||||
* This class literally exists to protect DroidGap from Javascript directly.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
public class BrowserKey {
|
||||
|
||||
DroidGap mAction;
|
||||
boolean bound;
|
||||
WebView mView;
|
||||
|
||||
BrowserKey(WebView view, DroidGap action)
|
||||
{
|
||||
bound = false;
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
public void override()
|
||||
{
|
||||
Log.d("PhoneGap", "WARNING: Back Button Default Behaviour will be overridden. The backKeyDown event will be fired!");
|
||||
bound = true;
|
||||
}
|
||||
|
||||
public boolean isBound()
|
||||
{
|
||||
return bound;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
bound = false;
|
||||
}
|
||||
|
||||
public void exitApp()
|
||||
{
|
||||
mAction.finish();
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,14 @@ import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap.
|
||||
* The CallbackServer class implements an XHR server and a polling server with a list of JavaScript
|
||||
@@ -41,6 +45,8 @@ import java.util.LinkedList;
|
||||
*/
|
||||
public class CallbackServer implements Runnable {
|
||||
|
||||
private static final String LOG_TAG = "CallbackServer";
|
||||
|
||||
/**
|
||||
* The list of JavaScript statements to be sent to JavaScript.
|
||||
*/
|
||||
@@ -69,7 +75,7 @@ public class CallbackServer implements Runnable {
|
||||
/**
|
||||
* Indicates that polling should be used instead of XHR.
|
||||
*/
|
||||
private boolean usePolling;
|
||||
private boolean usePolling = true;
|
||||
|
||||
/**
|
||||
* Security token to prevent other apps from accessing this callback server via XHR
|
||||
@@ -84,10 +90,28 @@ public class CallbackServer implements Runnable {
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
|
||||
if (android.net.Proxy.getDefaultHost() != null) {
|
||||
this.javascript = new LinkedList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init callback server and start XHR if running local app.
|
||||
*
|
||||
* If PhoneGap app is loaded from file://, then we can use XHR
|
||||
* otherwise we have to use polling due to cross-domain security restrictions.
|
||||
*
|
||||
* @param url The URL of the PhoneGap app being loaded
|
||||
*/
|
||||
public void init(String url) {
|
||||
//System.out.println("CallbackServer.start("+url+")");
|
||||
|
||||
// Determine if XHR or polling is to be used
|
||||
if ((url != null) && !url.startsWith("file://")) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else if (android.net.Proxy.getDefaultHost() != null) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else {
|
||||
this.usePolling = false;
|
||||
@@ -96,7 +120,7 @@ public class CallbackServer implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if polling should be used instead of XHR.
|
||||
* Return if polling is being used instead of XHR.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@@ -158,9 +182,9 @@ public class CallbackServer implements Runnable {
|
||||
String request;
|
||||
ServerSocket waitSocket = new ServerSocket(0);
|
||||
this.port = waitSocket.getLocalPort();
|
||||
//System.out.println(" -- using port " +this.port);
|
||||
//System.out.println("CallbackServer -- using port " +this.port);
|
||||
this.token = java.util.UUID.randomUUID().toString();
|
||||
//System.out.println(" -- using token "+this.token);
|
||||
//System.out.println("CallbackServer -- using token "+this.token);
|
||||
|
||||
while (this.active) {
|
||||
//System.out.println("CallbackServer: Waiting for data on socket");
|
||||
@@ -168,43 +192,66 @@ public class CallbackServer implements Runnable {
|
||||
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),40);
|
||||
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
|
||||
request = xhrReader.readLine();
|
||||
//System.out.println("Request="+request);
|
||||
if (request.contains("GET")) {
|
||||
String response = "";
|
||||
//System.out.println("CallbackServerRequest="+request);
|
||||
if (this.active && (request != null)) {
|
||||
if (request.contains("GET")) {
|
||||
|
||||
// Get requested file
|
||||
String[] requestParts = request.split(" ");
|
||||
|
||||
// Must have security token
|
||||
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
|
||||
//System.out.println("CallbackServer -- Processing GET request");
|
||||
|
||||
// Must have security token
|
||||
if (request.substring(5,41).equals(this.token)) {
|
||||
//System.out.println(" -- Processing GET request");
|
||||
|
||||
// Wait until there is some data to send, or send empty data every 30 sec
|
||||
// to prevent XHR timeout on the client
|
||||
synchronized (this) {
|
||||
while (this.empty) {
|
||||
try {
|
||||
this.wait(30000); // prevent timeout from happening
|
||||
//System.out.println(">>> break <<<");
|
||||
break;
|
||||
// Wait until there is some data to send, or send empty data every 10 sec
|
||||
// to prevent XHR timeout on the client
|
||||
synchronized (this) {
|
||||
while (this.empty) {
|
||||
try {
|
||||
this.wait(10000); // prevent timeout from happening
|
||||
//System.out.println("CallbackServer>>> break <<<");
|
||||
break;
|
||||
}
|
||||
catch (Exception e) { }
|
||||
}
|
||||
catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If server is still running
|
||||
if (this.active) {
|
||||
// If server is still running
|
||||
if (this.active) {
|
||||
|
||||
// If no data, then send 404 back to client before it times out
|
||||
if (this.empty) {
|
||||
//System.out.println(" -- sending data 0");
|
||||
output.writeBytes("HTTP/1.1 404 NO DATA\r\n\r\n");
|
||||
// If no data, then send 404 back to client before it times out
|
||||
if (this.empty) {
|
||||
//System.out.println("CallbackServer -- sending data 0");
|
||||
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space
|
||||
}
|
||||
else {
|
||||
//System.out.println("CallbackServer -- sending item");
|
||||
response = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
String js = this.getJavascript();
|
||||
if (js != null) {
|
||||
response += encode(js, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//System.out.println(" -- sending item");
|
||||
output.writeBytes("HTTP/1.1 200 OK\r\n\r\n"+this.getJavascript());
|
||||
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
|
||||
}
|
||||
//System.out.println("CallbackServer: response="+response);
|
||||
//System.out.println("CallbackServer: closing output");
|
||||
output.writeBytes(response);
|
||||
output.flush();
|
||||
}
|
||||
//System.out.println("CallbackServer: closing output");
|
||||
output.close();
|
||||
output.close();
|
||||
xhrReader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -219,11 +266,13 @@ public class CallbackServer implements Runnable {
|
||||
*/
|
||||
public void stopServer() {
|
||||
//System.out.println("CallbackServer.stopServer()");
|
||||
this.active = false;
|
||||
if (this.active) {
|
||||
this.active = false;
|
||||
|
||||
// Break out of server wait
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
// Break out of server wait
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,4 +327,81 @@ public class CallbackServer implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/* The Following code has been modified from original implementation of URLEncoder */
|
||||
|
||||
/* start */
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
static final String digits = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* This will encode the return value to JavaScript. We revert the encoding for
|
||||
* common characters that don't require encoding to reduce the size of the string
|
||||
* being passed to JavaScript.
|
||||
*
|
||||
* @param s to be encoded
|
||||
* @param enc encoding type
|
||||
* @return encoded string
|
||||
*/
|
||||
public static String encode(String s, String enc) throws UnsupportedEncodingException {
|
||||
if (s == null || enc == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// check for UnsupportedEncodingException
|
||||
"".getBytes(enc);
|
||||
|
||||
// Guess a bit bigger for encoded form
|
||||
StringBuilder buf = new StringBuilder(s.length() + 16);
|
||||
int start = -1;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
||||
|| (ch >= '0' && ch <= '9')
|
||||
|| " .-*_'(),<>=?@[]{}:~\"\\/;!".indexOf(ch) > -1) {
|
||||
if (start >= 0) {
|
||||
convert(s.substring(start, i), buf, enc);
|
||||
start = -1;
|
||||
}
|
||||
if (ch != ' ') {
|
||||
buf.append(ch);
|
||||
} else {
|
||||
buf.append(' ');
|
||||
}
|
||||
} else {
|
||||
if (start < 0) {
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start >= 0) {
|
||||
convert(s.substring(start, s.length()), buf, enc);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void convert(String s, StringBuilder buf, String enc) throws UnsupportedEncodingException {
|
||||
byte[] bytes = s.getBytes(enc);
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
buf.append('%');
|
||||
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
|
||||
buf.append(digits.charAt(bytes[j] & 0xf));
|
||||
}
|
||||
}
|
||||
|
||||
/* end */
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class CameraLauncher extends Plugin {
|
||||
this.takePicture(args.getInt(0), destType);
|
||||
}
|
||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||
this.getImage(srcType, destType);
|
||||
this.getImage(args.getInt(0), srcType, destType);
|
||||
}
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
@@ -100,7 +100,7 @@ public class CameraLauncher extends Plugin {
|
||||
/**
|
||||
* Take a picture with the camera.
|
||||
* When an image is captured or the camera view is cancelled, the result is returned
|
||||
* in DroidGap.onActivityResult, which forwards the result to this.onActivityResult.
|
||||
* 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:
|
||||
@@ -129,10 +129,14 @@ public class CameraLauncher extends Plugin {
|
||||
/**
|
||||
* Get image from photo library.
|
||||
*
|
||||
* @param returnType
|
||||
* @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 srcType, int returnType) {
|
||||
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);
|
||||
@@ -162,7 +166,14 @@ public class CameraLauncher extends Plugin {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
try {
|
||||
// Read in bitmap of captured image
|
||||
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
||||
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 base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
@@ -197,6 +208,9 @@ public class CameraLauncher extends Plugin {
|
||||
// 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.");
|
||||
@@ -224,6 +238,9 @@ public class CameraLauncher extends Plugin {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
this.processPicture(bitmap);
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
@@ -257,11 +274,15 @@ public class CameraLauncher extends Plugin {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
353
framework/src/com/phonegap/Capture.java
Normal file
353
framework/src/com/phonegap/Capture.java
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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) 2011, IBM Corporation
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
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;
|
||||
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
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (mimeType.equals("image/jpeg")) {
|
||||
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
|
||||
* @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() {
|
||||
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() {
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
|
||||
// Specify file so that large image is captured and returned
|
||||
File photo = new File(Environment.getExternalStorageDirectory(), "Capture.jpg");
|
||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||
this.imageUri = Uri.fromFile(photo);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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").
|
||||
* @throws JSONException
|
||||
*/
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
// 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();
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error message to JavaScript.
|
||||
*
|
||||
* @param err
|
||||
*/
|
||||
public void fail(String err) {
|
||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import java.util.List;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
@@ -55,7 +56,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
@@ -155,6 +155,9 @@ public abstract class ContactAccessor {
|
||||
else if (key.startsWith("urls")) {
|
||||
map.put("urls", true);
|
||||
}
|
||||
else if (key.startsWith("photos")) {
|
||||
map.put("photos", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
@@ -162,11 +165,38 @@ public abstract class ContactAccessor {
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get a string from a JSON object. Saves a
|
||||
* lot of try/catch writing.
|
||||
* If the property is not found in the object null will be returned.
|
||||
*
|
||||
* @param obj contact object to search
|
||||
* @param property to be looked up
|
||||
* @return The value of the property
|
||||
*/
|
||||
protected String getJsonString(JSONObject obj, String property) {
|
||||
String value = null;
|
||||
try {
|
||||
if (obj != null) {
|
||||
value = obj.getString(property);
|
||||
if (value.equals("null")) {
|
||||
Log.d(LOG_TAG, property + " is string called 'null'");
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding a JSON Contact object into the database.
|
||||
* @return TODO
|
||||
*/
|
||||
public abstract void save(JSONObject contact);
|
||||
public abstract boolean save(JSONObject contact);
|
||||
|
||||
/**
|
||||
* Handles searching through SDK-specific contacts API.
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.Contacts;
|
||||
@@ -62,6 +63,7 @@ import android.webkit.WebView;
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
private static final String PEOPLE_ID_EQUALS = "people._id = ?";
|
||||
/**
|
||||
* A static map that converts the JavaScript property name to Android database column name.
|
||||
*/
|
||||
@@ -102,22 +104,28 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
*/
|
||||
public JSONArray search(JSONArray fields, JSONObject options) {
|
||||
String searchTerm = "";
|
||||
int limit = 1;
|
||||
boolean multiple = false;
|
||||
try {
|
||||
searchTerm = options.getString("filter");
|
||||
int limit = Integer.MAX_VALUE;
|
||||
boolean multiple = true;
|
||||
|
||||
if (options != null) {
|
||||
searchTerm = options.optString("filter");
|
||||
if (searchTerm.length()==0) {
|
||||
searchTerm = "%";
|
||||
}
|
||||
else {
|
||||
searchTerm = "%" + searchTerm + "%";
|
||||
}
|
||||
multiple = options.getBoolean("multiple");
|
||||
if (multiple) {
|
||||
limit = options.getInt("limit");
|
||||
try {
|
||||
multiple = options.getBoolean("multiple");
|
||||
if (!multiple) {
|
||||
limit = 1;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
// Multiple was not specified so we assume the default is true.
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
else {
|
||||
searchTerm = "%";
|
||||
}
|
||||
|
||||
ContentResolver cr = mApp.getContentResolver();
|
||||
@@ -140,7 +148,7 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
// Do query for name and note
|
||||
Cursor cur = cr.query(People.CONTENT_URI,
|
||||
new String[] {People.DISPLAY_NAME, People.NOTES},
|
||||
"people._id = ?",
|
||||
PEOPLE_ID_EQUALS,
|
||||
new String[] {contactId},
|
||||
null);
|
||||
cur.moveToFirst();
|
||||
@@ -305,11 +313,13 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
while (cursor.moveToNext()) {
|
||||
im = new JSONObject();
|
||||
try{
|
||||
im.put("primary", false);
|
||||
im.put("id", cursor.getString(
|
||||
cursor.getColumnIndex(ContactMethods._ID)));
|
||||
im.put("perf", false);
|
||||
im.put("value", cursor.getString(
|
||||
cursor.getColumnIndex(ContactMethodsColumns.DATA)));
|
||||
im.put("type", cursor.getString(
|
||||
cursor.getColumnIndex(ContactMethodsColumns.TYPE)));
|
||||
im.put("type", getContactType(cursor.getInt(
|
||||
cursor.getColumnIndex(ContactMethodsColumns.TYPE))));
|
||||
ims.put(im);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
@@ -335,13 +345,10 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
while (cursor.moveToNext()) {
|
||||
organization = new JSONObject();
|
||||
try{
|
||||
organization.put("id", cursor.getString(cursor.getColumnIndex(Organizations._ID)));
|
||||
organization.put("name", cursor.getString(cursor.getColumnIndex(Organizations.COMPANY)));
|
||||
organization.put("title", cursor.getString(cursor.getColumnIndex(Organizations.TITLE)));
|
||||
// organization.put("department", cursor.getString(cursor.getColumnIndex(Organizations)));
|
||||
// organization.put("description", cursor.getString(cursor.getColumnIndex(Organizations)));
|
||||
// organization.put("endDate", cursor.getString(cursor.getColumnIndex(Organizations)));
|
||||
// organization.put("location", cursor.getString(cursor.getColumnIndex(Organizations)));
|
||||
// organization.put("startDate", cursor.getString(cursor.getColumnIndex(Organizations)));
|
||||
organizations.put(organization);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
@@ -368,6 +375,7 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
while (cursor.moveToNext()) {
|
||||
address = new JSONObject();
|
||||
try{
|
||||
address.put("id", cursor.getString(cursor.getColumnIndex(ContactMethods._ID)));
|
||||
address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactMethodsColumns.DATA)));
|
||||
addresses.put(address);
|
||||
} catch (JSONException e) {
|
||||
@@ -394,9 +402,10 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
while (cursor.moveToNext()) {
|
||||
phone = new JSONObject();
|
||||
try{
|
||||
phone.put("primary", false);
|
||||
phone.put("id", cursor.getString(cursor.getColumnIndex(Phones._ID)));
|
||||
phone.put("perf", false);
|
||||
phone.put("value", cursor.getString(cursor.getColumnIndex(Phones.NUMBER)));
|
||||
phone.put("type", cursor.getString(cursor.getColumnIndex(Phones.TYPE)));
|
||||
phone.put("type", getPhoneType(cursor.getInt(cursor.getColumnIndex(Phones.TYPE))));
|
||||
phones.put(phone);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
@@ -422,7 +431,8 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
while (cursor.moveToNext()) {
|
||||
email = new JSONObject();
|
||||
try{
|
||||
email.put("primary", false);
|
||||
email.put("id", cursor.getString(cursor.getColumnIndex(ContactMethods._ID)));
|
||||
email.put("perf", false);
|
||||
email.put("value", cursor.getString(cursor.getColumnIndex(ContactMethods.DATA)));
|
||||
// TODO Find out why adding an email type throws and exception
|
||||
//email.put("type", cursor.getString(cursor.getColumnIndex(ContactMethods.TYPE)));
|
||||
@@ -434,10 +444,372 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
return emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will save a contact object into the devices contacts database.
|
||||
*
|
||||
* @param contact the contact to be saved.
|
||||
* @returns true if the contact is successfully saved, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public void save(JSONObject contact) {
|
||||
// TODO Auto-generated method stub
|
||||
public boolean save(JSONObject contact) {
|
||||
ContentValues personValues = new ContentValues();
|
||||
|
||||
String id = getJsonString(contact, "id");
|
||||
|
||||
String name = getJsonString(contact, "displayName");
|
||||
if (name != null) {
|
||||
personValues.put(Contacts.People.NAME, name);
|
||||
}
|
||||
String note = getJsonString(contact, "note");
|
||||
if (note != null) {
|
||||
personValues.put(Contacts.People.NOTES, note);
|
||||
}
|
||||
|
||||
/* STARRED 0 = Contacts, 1 = Favorites */
|
||||
personValues.put(Contacts.People.STARRED, 0);
|
||||
|
||||
Uri newPersonUri;
|
||||
// Add new contact
|
||||
if (id == null) {
|
||||
newPersonUri = Contacts.People.createPersonInMyContactsGroup(mApp.getContentResolver(), personValues);
|
||||
}
|
||||
// modify existing contact
|
||||
else {
|
||||
newPersonUri = Uri.withAppendedPath(Contacts.People.CONTENT_URI, id);
|
||||
mApp.getContentResolver().update(newPersonUri, personValues, PEOPLE_ID_EQUALS, new String[]{id});
|
||||
}
|
||||
|
||||
if (newPersonUri != null) {
|
||||
// phoneNumbers
|
||||
savePhoneNumbers(contact, newPersonUri);
|
||||
// emails
|
||||
saveEntries(contact, newPersonUri, "emails", Contacts.KIND_EMAIL);
|
||||
// addresses
|
||||
saveAddresses(contact, newPersonUri);
|
||||
// organizations
|
||||
saveOrganizations(contact, newPersonUri);
|
||||
// ims
|
||||
saveEntries(contact, newPersonUri, "ims", Contacts.KIND_IM);
|
||||
|
||||
// Successfully create a Contact
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a JSON contact object and loops through the available organizations. If the
|
||||
* organization has an id that is not equal to null the organization will be updated in the database.
|
||||
* If the id is null then we treat it as a new organization.
|
||||
*
|
||||
* @param contact the contact to extract the organizations from
|
||||
* @param uri the base URI for this contact.
|
||||
*/
|
||||
private void saveOrganizations(JSONObject contact, Uri newPersonUri) {
|
||||
ContentValues values = new ContentValues();
|
||||
Uri orgUri = Uri.withAppendedPath(newPersonUri,
|
||||
Contacts.Organizations.CONTENT_DIRECTORY);
|
||||
String id = null;
|
||||
try {
|
||||
JSONArray orgs = contact.getJSONArray("organizations");
|
||||
if (orgs != null && orgs.length() > 0) {
|
||||
JSONObject org;
|
||||
for (int i=0; i<orgs.length(); i++) {
|
||||
org = orgs.getJSONObject(i);
|
||||
id = getJsonString(org, "id");
|
||||
values.put(Contacts.Organizations.COMPANY, getJsonString(org, "name"));
|
||||
values.put(Contacts.Organizations.TITLE, getJsonString(org, "title"));
|
||||
if (id == null) {
|
||||
Uri contactUpdate = mApp.getContentResolver().insert(orgUri, values);
|
||||
}
|
||||
else {
|
||||
Uri tempUri = Uri.withAppendedPath(orgUri, id);
|
||||
mApp.getContentResolver().update(tempUri, values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not save organizations = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a JSON contact object and loops through the available addresses. If the
|
||||
* address has an id that is not equal to null the address will be updated in the database.
|
||||
* If the id is null then we treat it as a new address.
|
||||
*
|
||||
* @param contact the contact to extract the addresses from
|
||||
* @param uri the base URI for this contact.
|
||||
*/
|
||||
private void saveAddresses(JSONObject contact, Uri uri) {
|
||||
ContentValues values = new ContentValues();
|
||||
Uri newUri = Uri.withAppendedPath(uri,
|
||||
Contacts.People.ContactMethods.CONTENT_DIRECTORY);
|
||||
String id = null;
|
||||
try {
|
||||
JSONArray entries = contact.getJSONArray("addresses");
|
||||
if (entries != null && entries.length() > 0) {
|
||||
JSONObject entry;
|
||||
values.put(Contacts.ContactMethods.KIND, Contacts.KIND_POSTAL);
|
||||
for (int i=0; i<entries.length(); i++) {
|
||||
entry = entries.getJSONObject(i);
|
||||
id = getJsonString(entry, "id");
|
||||
|
||||
String address = getJsonString(entry, "formatted");
|
||||
if (address != null) {
|
||||
values.put(Contacts.ContactMethods.DATA, address);
|
||||
}
|
||||
else {
|
||||
values.put(Contacts.ContactMethods.DATA, createAddressString(entry));
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
Uri contactUpdate = mApp.getContentResolver().insert(newUri, values);
|
||||
}
|
||||
else {
|
||||
Uri tempUri = Uri.withAppendedPath(newUri, id);
|
||||
mApp.getContentResolver().update(tempUri, values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not save address = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a ContactAddress JSON object and creates a fully
|
||||
* formatted address string.
|
||||
*
|
||||
* @param entry the full address object
|
||||
* @return a formatted address string
|
||||
*/
|
||||
private String createAddressString(JSONObject entry) {
|
||||
StringBuffer buffer = new StringBuffer("");
|
||||
if (getJsonString(entry, "locality") != null ) {
|
||||
buffer.append(getJsonString(entry, "locality"));
|
||||
}
|
||||
if (getJsonString(entry, "region") != null ) {
|
||||
if (buffer.length() > 0 ) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(getJsonString(entry, "region"));
|
||||
}
|
||||
if (getJsonString(entry, "postalCode") != null ) {
|
||||
if (buffer.length() > 0 ) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(getJsonString(entry, "postalCode"));
|
||||
}
|
||||
if (getJsonString(entry, "country") != null ) {
|
||||
if (buffer.length() > 0 ) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(getJsonString(entry, "country"));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a JSON contact object and loops through the available entries (Emails/IM's). If the
|
||||
* entry has an id that is not equal to null the entry will be updated in the database.
|
||||
* If the id is null then we treat it as a new entry.
|
||||
*
|
||||
* @param contact the contact to extract the entries from
|
||||
* @param uri the base URI for this contact.
|
||||
*/
|
||||
private void saveEntries(JSONObject contact, Uri uri, String dataType, int contactKind) {
|
||||
ContentValues values = new ContentValues();
|
||||
Uri newUri = Uri.withAppendedPath(uri,
|
||||
Contacts.People.ContactMethods.CONTENT_DIRECTORY);
|
||||
String id = null;
|
||||
|
||||
try {
|
||||
JSONArray entries = contact.getJSONArray(dataType);
|
||||
if (entries != null && entries.length() > 0) {
|
||||
JSONObject entry;
|
||||
values.put(Contacts.ContactMethods.KIND, contactKind);
|
||||
for (int i=0; i<entries.length(); i++) {
|
||||
entry = entries.getJSONObject(i);
|
||||
id = getJsonString(entry, "id");
|
||||
values.put(Contacts.ContactMethods.DATA, getJsonString(entry, "value"));
|
||||
values.put(Contacts.ContactMethods.TYPE, getContactType(getJsonString(entry, "type")));
|
||||
if (id==null) {
|
||||
Uri contactUpdate = mApp.getContentResolver().insert(newUri, values);
|
||||
}
|
||||
else {
|
||||
Uri tempUri = Uri.withAppendedPath(newUri, id);
|
||||
mApp.getContentResolver().update(tempUri, values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not save " + dataType + " = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string from the W3C Contact API to it's Android int value.
|
||||
* @param string
|
||||
* @return Android int value
|
||||
*/
|
||||
private int getContactType(String string) {
|
||||
int type = Contacts.ContactMethods.TYPE_OTHER;
|
||||
if (string!=null) {
|
||||
if ("home".equals(string.toLowerCase())) {
|
||||
return Contacts.ContactMethods.TYPE_HOME;
|
||||
}
|
||||
else if ("work".equals(string.toLowerCase())) {
|
||||
return Contacts.ContactMethods.TYPE_WORK;
|
||||
}
|
||||
else if ("other".equals(string.toLowerCase())) {
|
||||
return Contacts.ContactMethods.TYPE_OTHER;
|
||||
}
|
||||
else if ("custom".equals(string.toLowerCase())) {
|
||||
return Contacts.ContactMethods.TYPE_CUSTOM;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* getPhoneType converts an Android phone type into a string
|
||||
* @param type
|
||||
* @return phone type as string.
|
||||
*/
|
||||
private String getContactType(int type) {
|
||||
String stringType;
|
||||
switch (type) {
|
||||
case Contacts.ContactMethods.TYPE_CUSTOM:
|
||||
stringType = "custom";
|
||||
break;
|
||||
case Contacts.ContactMethods.TYPE_HOME:
|
||||
stringType = "home";
|
||||
break;
|
||||
case Contacts.ContactMethods.TYPE_WORK:
|
||||
stringType = "work";
|
||||
break;
|
||||
case Contacts.ContactMethods.TYPE_OTHER:
|
||||
default:
|
||||
stringType = "other";
|
||||
break;
|
||||
}
|
||||
return stringType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a JSON contact object and loops through the available phone numbers. If the phone
|
||||
* number has an id that is not equal to null the phone number will be updated in the database.
|
||||
* If the id is null then we treat it as a new phone number.
|
||||
*
|
||||
* @param contact the contact to extract the phone numbers from
|
||||
* @param uri the base URI for this contact.
|
||||
*/
|
||||
private void savePhoneNumbers(JSONObject contact, Uri uri) {
|
||||
ContentValues values = new ContentValues();
|
||||
Uri phonesUri = Uri.withAppendedPath(uri,
|
||||
Contacts.People.Phones.CONTENT_DIRECTORY);
|
||||
String id = null;
|
||||
|
||||
try {
|
||||
JSONArray phones = contact.getJSONArray("phoneNumbers");
|
||||
if (phones != null && phones.length() > 0) {
|
||||
JSONObject phone;
|
||||
for (int i=0; i<phones.length(); i++) {
|
||||
phone = phones.getJSONObject(i);
|
||||
id = getJsonString(phone, "id");
|
||||
values.put(Contacts.Phones.NUMBER, getJsonString(phone, "value"));
|
||||
values.put(Contacts.Phones.TYPE, getPhoneType(getJsonString(phone, "type")));
|
||||
if (id==null) {
|
||||
Uri phoneUpdate = mApp.getContentResolver().insert(phonesUri, values);
|
||||
}
|
||||
else {
|
||||
Uri newUri = Uri.withAppendedPath(phonesUri, id);
|
||||
mApp.getContentResolver().update(newUri, values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not save phones = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string from the W3C Contact API to it's Android int value.
|
||||
* @param string
|
||||
* @return Android int value
|
||||
*/
|
||||
private int getPhoneType(String string) {
|
||||
int type = Contacts.Phones.TYPE_OTHER;
|
||||
if ("home".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_HOME;
|
||||
}
|
||||
else if ("mobile".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_MOBILE;
|
||||
}
|
||||
else if ("work".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_WORK;
|
||||
}
|
||||
else if ("work fax".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_FAX_WORK;
|
||||
}
|
||||
else if ("home fax".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_FAX_HOME;
|
||||
}
|
||||
else if ("fax".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_FAX_WORK;
|
||||
}
|
||||
else if ("pager".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_PAGER;
|
||||
}
|
||||
else if ("other".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_OTHER;
|
||||
}
|
||||
else if ("custom".equals(string.toLowerCase())) {
|
||||
return Contacts.Phones.TYPE_CUSTOM;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* getPhoneType converts an Android phone type into a string
|
||||
* @param type
|
||||
* @return phone type as string.
|
||||
*/
|
||||
private String getPhoneType(int type) {
|
||||
String stringType;
|
||||
switch (type) {
|
||||
case Contacts.Phones.TYPE_CUSTOM:
|
||||
stringType = "custom";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_FAX_HOME:
|
||||
stringType = "home fax";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_FAX_WORK:
|
||||
stringType = "work fax";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_HOME:
|
||||
stringType = "home";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_MOBILE:
|
||||
stringType = "mobile";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_PAGER:
|
||||
stringType = "pager";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_WORK:
|
||||
stringType = "work";
|
||||
break;
|
||||
case Contacts.Phones.TYPE_OTHER:
|
||||
default:
|
||||
stringType = "custom";
|
||||
break;
|
||||
}
|
||||
return stringType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -447,7 +819,7 @@ public class ContactAccessorSdk3_4 extends ContactAccessor {
|
||||
*/
|
||||
public boolean remove(String id) {
|
||||
int result = mApp.getContentResolver().delete(People.CONTENT_URI,
|
||||
"people._id = ?",
|
||||
PEOPLE_ID_EQUALS,
|
||||
new String[] {id});
|
||||
|
||||
return (result > 0) ? true : false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,11 +42,18 @@ public class ContactManager extends Plugin {
|
||||
|
||||
try {
|
||||
if (action.equals("search")) {
|
||||
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.getJSONObject(1));
|
||||
return new PluginResult(status, res);
|
||||
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1));
|
||||
return new PluginResult(status, res, "navigator.service.contacts.cast");
|
||||
}
|
||||
else if (action.equals("save")) {
|
||||
// TODO Coming soon!
|
||||
if (contactAccessor.save(args.getJSONObject(0))) {
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
else {
|
||||
JSONObject r = new JSONObject();
|
||||
r.put("code", 0);
|
||||
return new PluginResult(PluginResult.Status.ERROR, r);
|
||||
}
|
||||
}
|
||||
else if (action.equals("remove")) {
|
||||
if (contactAccessor.remove(args.getString(0))) {
|
||||
|
||||
@@ -11,15 +11,14 @@ import java.util.TimeZone;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
public class Device extends Plugin {
|
||||
|
||||
public static String phonegapVersion = "0.9.2"; // PhoneGap version
|
||||
public static String phonegapVersion = "0.9.5"; // PhoneGap version
|
||||
public static String platform = "Android"; // Device OS
|
||||
public static String uuid; // Device UUID
|
||||
|
||||
@@ -35,7 +34,7 @@ public class Device extends Plugin {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
Device.uuid = getUuid();
|
||||
}
|
||||
@@ -115,34 +114,13 @@ public class Device extends Plugin {
|
||||
public String getPhonegapVersion() {
|
||||
return Device.phonegapVersion;
|
||||
}
|
||||
|
||||
public String getLine1Number(){
|
||||
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return operator.getLine1Number();
|
||||
}
|
||||
|
||||
public String getDeviceId(){
|
||||
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return operator.getDeviceId();
|
||||
}
|
||||
|
||||
public String getSimSerialNumber(){
|
||||
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return operator.getSimSerialNumber();
|
||||
}
|
||||
|
||||
public String getSubscriberId(){
|
||||
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
return operator.getSubscriberId();
|
||||
}
|
||||
|
||||
public String getModel()
|
||||
{
|
||||
public String getModel() {
|
||||
String model = android.os.Build.MODEL;
|
||||
return model;
|
||||
}
|
||||
public String getProductName()
|
||||
{
|
||||
|
||||
public String getProductName() {
|
||||
String productname = android.os.Build.PRODUCT;
|
||||
return productname;
|
||||
}
|
||||
@@ -157,8 +135,7 @@ public class Device extends Plugin {
|
||||
return osversion;
|
||||
}
|
||||
|
||||
public String getSDKVersion()
|
||||
{
|
||||
public String getSDKVersion() {
|
||||
String sdkversion = android.os.Build.VERSION.SDK;
|
||||
return sdkversion;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import java.io.File;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class provides file directory utilities.
|
||||
@@ -21,6 +20,8 @@ import android.util.Log;
|
||||
*/
|
||||
public class DirectoryManager {
|
||||
|
||||
private static final String LOG_TAG = "DirectoryManager";
|
||||
|
||||
/**
|
||||
* Determine if a file or directory exists.
|
||||
*
|
||||
@@ -36,7 +37,6 @@ public class DirectoryManager {
|
||||
File newPath = constructFilePaths(path.toString(), name);
|
||||
status = newPath.exists();
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else{
|
||||
status = false;
|
||||
@@ -72,29 +72,6 @@ public class DirectoryManager {
|
||||
return (freeSpace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create directory on SD card.
|
||||
*
|
||||
* @param directoryName The name of the directory to create.
|
||||
* @return T=successful, F=failed
|
||||
*/
|
||||
protected static boolean createDirectory(String directoryName) {
|
||||
boolean status;
|
||||
|
||||
// Make sure SD card exists
|
||||
if ((testSaveLocationExists()) && (!directoryName.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), directoryName);
|
||||
status = newPath.mkdir();
|
||||
status = true;
|
||||
}
|
||||
|
||||
// If no SD card or invalid dir name
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if SD card exists.
|
||||
@@ -117,95 +94,6 @@ public class DirectoryManager {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete directory.
|
||||
*
|
||||
* @param fileName The name of the directory to delete
|
||||
* @return T=deleted, F=could not delete
|
||||
*/
|
||||
protected static boolean deleteDirectory(String fileName) {
|
||||
boolean status;
|
||||
SecurityManager checker = new SecurityManager();
|
||||
|
||||
// Make sure SD card exists
|
||||
if ((testSaveLocationExists()) && (!fileName.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), fileName);
|
||||
checker.checkDelete(newPath.toString());
|
||||
|
||||
// If dir to delete is really a directory
|
||||
if (newPath.isDirectory()) {
|
||||
String[] listfile = newPath.list();
|
||||
|
||||
// Delete all files within the specified directory and then delete the directory
|
||||
try{
|
||||
for (int i=0; i < listfile.length; i++){
|
||||
File deletedFile = new File (newPath.toString()+"/"+listfile[i].toString());
|
||||
deletedFile.delete();
|
||||
}
|
||||
newPath.delete();
|
||||
Log.i("DirectoryManager deleteDirectory", fileName);
|
||||
status = true;
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If dir not a directory, then error
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete file.
|
||||
*
|
||||
* @param fileName The name of the file to delete
|
||||
* @return T=deleted, F=not deleted
|
||||
*/
|
||||
protected static boolean deleteFile(String fileName) {
|
||||
boolean status;
|
||||
SecurityManager checker = new SecurityManager();
|
||||
|
||||
// Make sure SD card exists
|
||||
if ((testSaveLocationExists()) && (!fileName.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), fileName);
|
||||
checker.checkDelete(newPath.toString());
|
||||
|
||||
// If file to delete is really a file
|
||||
if (newPath.isFile()){
|
||||
try {
|
||||
Log.i("DirectoryManager deleteFile", fileName);
|
||||
newPath.delete();
|
||||
status = true;
|
||||
}catch (SecurityException se){
|
||||
se.printStackTrace();
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
// If not a file, then error
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file object from two file paths.
|
||||
*
|
||||
@@ -215,8 +103,12 @@ public class DirectoryManager {
|
||||
*/
|
||||
private static File constructFilePaths (String file1, String file2) {
|
||||
File newPath;
|
||||
newPath = new File(file1+"/"+file2);
|
||||
if (file2.startsWith(file1)) {
|
||||
newPath = new File(file2);
|
||||
}
|
||||
else {
|
||||
newPath = new File(file1+"/"+file2);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
365
framework/src/com/phonegap/FileTransfer.java
Normal file
365
framework/src/com/phonegap/FileTransfer.java
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.webkit.CookieManager;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
public class FileTransfer extends Plugin {
|
||||
|
||||
private static final String LOG_TAG = "FileUploader";
|
||||
private static final String LINE_START = "--";
|
||||
private static final String LINE_END = "\r\n";
|
||||
private static final String BOUNDRY = "*****";
|
||||
|
||||
public static int FILE_NOT_FOUND_ERR = 1;
|
||||
public static int INVALID_URL_ERR = 2;
|
||||
public static int CONNECTION_ERR = 3;
|
||||
|
||||
private SSLSocketFactory defaultSSLSocketFactory = null;
|
||||
private HostnameVerifier defaultHostnameVerifier = null;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
String file = null;
|
||||
String server = null;
|
||||
try {
|
||||
file = args.getString(0);
|
||||
server = args.getString(1);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Missing filename or server name");
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing filename or server name");
|
||||
}
|
||||
|
||||
// Setup the options
|
||||
String fileKey = null;
|
||||
String fileName = null;
|
||||
String mimeType = null;
|
||||
|
||||
fileKey = getArgument(args, 2, "file");
|
||||
fileName = getArgument(args, 3, "image.jpg");
|
||||
mimeType = getArgument(args, 4, "image/jpeg");
|
||||
|
||||
try {
|
||||
JSONObject params = args.optJSONObject(5);
|
||||
boolean trustEveryone = args.optBoolean(6);
|
||||
|
||||
if (action.equals("upload")) {
|
||||
FileUploadResult r = upload(file, server, fileKey, fileName, mimeType, params, trustEveryone);
|
||||
Log.d(LOG_TAG, "****** About to return a result from upload");
|
||||
return new PluginResult(PluginResult.Status.OK, r.toJSONObject());
|
||||
} else {
|
||||
return new PluginResult(PluginResult.Status.INVALID_ACTION);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileUploadError(FILE_NOT_FOUND_ERR);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileUploadError(INVALID_URL_ERR);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (SSLException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
Log.d(LOG_TAG, "Got my ssl exception!!!");
|
||||
JSONObject error = createFileUploadError(CONNECTION_ERR);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
JSONObject error = createFileUploadError(CONNECTION_ERR);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
// always verify the host - don't check for certificate
|
||||
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will install a trust manager that will blindly trust all SSL
|
||||
* certificates. The reason this code is being added is to enable developers
|
||||
* to do development using self signed SSL certificates on their web server.
|
||||
*
|
||||
* The standard HttpsURLConnection class will throw an exception on self
|
||||
* signed certificates if this code is not run.
|
||||
*/
|
||||
private void trustAllHosts() {
|
||||
// Create a trust manager that does not validate certificate chains
|
||||
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
||||
return new java.security.cert.X509Certificate[] {};
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
} };
|
||||
|
||||
// Install the all-trusting trust manager
|
||||
try {
|
||||
// Backup the current SSL socket factory
|
||||
defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
|
||||
// Install our all trusting manager
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an error object based on the passed in errorCode
|
||||
* @param errorCode the error
|
||||
* @return JSONObject containing the error
|
||||
*/
|
||||
private JSONObject createFileUploadError(int errorCode) {
|
||||
JSONObject error = null;
|
||||
try {
|
||||
error = new JSONObject();
|
||||
error.put("code", errorCode);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to read a parameter from the list of JSON args.
|
||||
* @param args the args passed to the Plugin
|
||||
* @param position the position to retrieve the arg from
|
||||
* @param defaultString the default to be used if the arg does not exist
|
||||
* @return String with the retrieved value
|
||||
*/
|
||||
private String getArgument(JSONArray args, int position, String defaultString) {
|
||||
String arg = defaultString;
|
||||
if(args.length() >= position) {
|
||||
arg = args.optString(position);
|
||||
if (arg == null || "null".equals(arg)) {
|
||||
arg = defaultString;
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the specified file to the server URL provided using an HTTP
|
||||
* multipart request.
|
||||
* @param file Full path of the file on the file system
|
||||
* @param server URL of the server to receive the file
|
||||
* @param fileKey Name of file request parameter
|
||||
* @param fileName File name to be used on server
|
||||
* @param mimeType Describes file content type
|
||||
* @param params key:value pairs of user-defined parameters
|
||||
* @return FileUploadResult containing result of upload request
|
||||
*/
|
||||
public FileUploadResult upload(String file, String server, final String fileKey, final String fileName,
|
||||
final String mimeType, JSONObject params, boolean trustEveryone) throws IOException, SSLException {
|
||||
// Create return object
|
||||
FileUploadResult result = new FileUploadResult();
|
||||
|
||||
// Get a input stream of the file on the phone
|
||||
InputStream fileInputStream = getPathFromUri(file);
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
DataOutputStream dos = null;
|
||||
|
||||
int bytesRead, bytesAvailable, bufferSize;
|
||||
long totalBytes;
|
||||
byte[] buffer;
|
||||
int maxBufferSize = 8096;
|
||||
|
||||
//------------------ CLIENT REQUEST
|
||||
// open a URL connection to the server
|
||||
URL url = new URL(server);
|
||||
|
||||
// Open a HTTP connection to the URL based on protocol
|
||||
if (url.getProtocol().toLowerCase().equals("https")) {
|
||||
// Using standard HTTPS connection. Will not allow self signed certificate
|
||||
if (!trustEveryone) {
|
||||
conn = (HttpsURLConnection) url.openConnection();
|
||||
}
|
||||
// Use our HTTPS connection that blindly trusts everyone.
|
||||
// This should only be used in debug environments
|
||||
else {
|
||||
// Setup the HTTPS connection class to trust everyone
|
||||
trustAllHosts();
|
||||
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
|
||||
// Save the current hostnameVerifier
|
||||
defaultHostnameVerifier = https.getHostnameVerifier();
|
||||
// Setup the connection not to verify hostnames
|
||||
https.setHostnameVerifier(DO_NOT_VERIFY);
|
||||
conn = https;
|
||||
}
|
||||
}
|
||||
// Return a standard HTTP conneciton
|
||||
else {
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
// Allow Inputs
|
||||
conn.setDoInput(true);
|
||||
|
||||
// Allow Outputs
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// Don't use a cached copy.
|
||||
conn.setUseCaches(false);
|
||||
|
||||
// Use a post method.
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+BOUNDRY);
|
||||
|
||||
// Set the cookies on the response
|
||||
String cookie = CookieManager.getInstance().getCookie(server);
|
||||
if (cookie != null) {
|
||||
conn.setRequestProperty("Cookie", cookie);
|
||||
}
|
||||
|
||||
dos = new DataOutputStream( conn.getOutputStream() );
|
||||
|
||||
// Send any extra parameters
|
||||
try {
|
||||
for (Iterator iter = params.keys(); iter.hasNext();) {
|
||||
Object key = iter.next();
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"" + key.toString() + "\";");
|
||||
dos.writeBytes(LINE_END + LINE_END);
|
||||
dos.writeBytes(params.getString(key.toString()));
|
||||
dos.writeBytes(LINE_END);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"" + fileName +"\"" + LINE_END);
|
||||
dos.writeBytes("Content-Type: " + mimeType + LINE_END);
|
||||
dos.writeBytes(LINE_END);
|
||||
|
||||
// create a buffer of maximum size
|
||||
bytesAvailable = fileInputStream.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
// read file and write it into form...
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
totalBytes = 0;
|
||||
|
||||
while (bytesRead > 0) {
|
||||
totalBytes += bytesRead;
|
||||
result.setBytesSent(totalBytes);
|
||||
dos.write(buffer, 0, bufferSize);
|
||||
bytesAvailable = fileInputStream.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
}
|
||||
|
||||
// send multipart form data necesssary after file data...
|
||||
dos.writeBytes(LINE_END);
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_START + LINE_END);
|
||||
|
||||
// close streams
|
||||
fileInputStream.close();
|
||||
dos.flush();
|
||||
dos.close();
|
||||
|
||||
//------------------ read the SERVER RESPONSE
|
||||
StringBuffer responseString = new StringBuffer("");
|
||||
DataInputStream inStream;
|
||||
try {
|
||||
inStream = new DataInputStream ( conn.getInputStream() );
|
||||
} catch(FileNotFoundException e) {
|
||||
throw new IOException("Received error from server");
|
||||
}
|
||||
|
||||
String line;
|
||||
while (( line = inStream.readLine()) != null) {
|
||||
responseString.append(line);
|
||||
}
|
||||
Log.d(LOG_TAG, "got response from server");
|
||||
Log.d(LOG_TAG, responseString.toString());
|
||||
|
||||
// send request and retrieve response
|
||||
result.setResponseCode(conn.getResponseCode());
|
||||
result.setResponse(responseString.toString());
|
||||
|
||||
inStream.close();
|
||||
conn.disconnect();
|
||||
|
||||
// Revert back to the proper verifier and socket factories
|
||||
if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) {
|
||||
((HttpsURLConnection)conn).setHostnameVerifier(defaultHostnameVerifier);
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an input stream based on file path or content:// uri
|
||||
*
|
||||
* @param path
|
||||
* @return an input stream
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private InputStream getPathFromUri(String path) throws FileNotFoundException {
|
||||
if (path.startsWith("content:")) {
|
||||
Uri uri = Uri.parse(path);
|
||||
return ctx.getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else {
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
52
framework/src/com/phonegap/FileUploadResult.java
Normal file
52
framework/src/com/phonegap/FileUploadResult.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the result and/or status of uploading a file to a remote server.
|
||||
*/
|
||||
public class FileUploadResult {
|
||||
|
||||
private long bytesSent = 0; // bytes sent
|
||||
private int responseCode = -1; // HTTP response code
|
||||
private String response = null; // HTTP response
|
||||
|
||||
public long getBytesSent() {
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
public void setBytesSent(long bytes) {
|
||||
this.bytesSent = bytes;
|
||||
}
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
public void setResponseCode(int responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() throws JSONException {
|
||||
return new JSONObject(
|
||||
"{bytesSent:" + bytesSent +
|
||||
",responseCode:" + responseCode +
|
||||
",response:" + JSONObject.quote(response) + "}");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,7 +86,7 @@ public class GeoListener {
|
||||
* @param msg The error message
|
||||
*/
|
||||
void fail(int code, String msg) {
|
||||
this.broker.sendJavascript("navigator._geo.fail('" + this.id + "', " + ", " + code + ", '" + msg + "');");
|
||||
this.broker.sendJavascript("navigator._geo.fail('" + this.id + "', '" + code + "', '" + msg + "');");
|
||||
this.stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
@@ -19,7 +21,7 @@ import android.os.Bundle;
|
||||
*/
|
||||
public class GpsListener implements LocationListener {
|
||||
|
||||
private DroidGap mCtx; // DroidGap object
|
||||
private PhonegapActivity mCtx; // PhonegapActivity object
|
||||
|
||||
private LocationManager mLocMan; // Location manager object
|
||||
private GeoListener owner; // Geolistener object (parent)
|
||||
@@ -35,7 +37,7 @@ public class GpsListener implements LocationListener {
|
||||
* @param interval
|
||||
* @param m
|
||||
*/
|
||||
public GpsListener(DroidGap ctx, int interval, GeoListener m) {
|
||||
public GpsListener(PhonegapActivity ctx, int interval, GeoListener m) {
|
||||
this.owner = m;
|
||||
this.mCtx = ctx;
|
||||
this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
@@ -15,7 +17,7 @@ import android.os.Bundle;
|
||||
|
||||
public class NetworkListener implements LocationListener {
|
||||
|
||||
private DroidGap mCtx; // DroidGap object
|
||||
private PhonegapActivity mCtx; // PhonegapActivity object
|
||||
|
||||
private LocationManager mLocMan; // Location manager object
|
||||
private GeoListener owner; // Geolistener object (parent)
|
||||
@@ -31,7 +33,7 @@ public class NetworkListener implements LocationListener {
|
||||
* @param interval
|
||||
* @param m
|
||||
*/
|
||||
public NetworkListener(DroidGap ctx, int interval, GeoListener m) {
|
||||
public NetworkListener(PhonegapActivity ctx, int interval, GeoListener m) {
|
||||
this.owner = m;
|
||||
this.mCtx = ctx;
|
||||
this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
* Copyright (c) 2010-2011, IBM Corporation
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
@@ -12,24 +12,59 @@ import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.net.*;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
|
||||
public class NetworkManager extends Plugin {
|
||||
|
||||
public static int NOT_REACHABLE = 0;
|
||||
public static int NOT_REACHABLE = 0;
|
||||
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
|
||||
public static int REACHABLE_VIA_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";
|
||||
|
||||
ConnectivityManager sockMan;
|
||||
private static final String LOG_TAG = "NetworkManager";
|
||||
|
||||
private String connectionCallbackId;
|
||||
|
||||
ConnectivityManager sockMan;
|
||||
BroadcastReceiver receiver;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public NetworkManager() {
|
||||
this.receiver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,11 +73,26 @@ public class NetworkManager extends Plugin {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
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.
|
||||
*
|
||||
@@ -67,6 +117,13 @@ public class NetworkManager extends Plugin {
|
||||
int i = this.isReachable(args.getString(0), args.getBoolean(1));
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("getConnectionInfo")) {
|
||||
this.connectionCallbackId = callbackId;
|
||||
NetworkInfo info = sockMan.getActiveNetworkInfo();
|
||||
PluginResult pluginResult = new PluginResult(status, this.getConnectionInfo(info));
|
||||
pluginResult.setKeepCallback(true);
|
||||
return pluginResult;
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
@@ -83,12 +140,104 @@ public class NetworkManager extends Plugin {
|
||||
// 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) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a network connection exists.
|
||||
*
|
||||
* @return
|
||||
@@ -126,7 +275,7 @@ public class NetworkManager extends Plugin {
|
||||
public int isReachable(String uri, boolean isIpAddress) {
|
||||
int reachable = NOT_REACHABLE;
|
||||
|
||||
if (uri.indexOf("http://") == -1) {
|
||||
if (uri.indexOf("http://") == -1 && uri.indexOf("https://") == -1) {
|
||||
uri = "http://" + uri;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.phonegap;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
@@ -172,7 +173,7 @@ public class Notification extends Plugin {
|
||||
*/
|
||||
public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
|
||||
|
||||
final DroidGap ctx = this.ctx;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
@@ -208,7 +209,7 @@ public class Notification extends Plugin {
|
||||
*/
|
||||
public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
|
||||
|
||||
final DroidGap ctx = this.ctx;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
final String[] fButtons = buttonLabels.split(",");
|
||||
|
||||
@@ -272,7 +273,7 @@ public class Notification extends Plugin {
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final DroidGap ctx = this.ctx;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.spinnerDialog = ProgressDialog.show(ctx, title , message, true, true,
|
||||
@@ -308,7 +309,7 @@ public class Notification extends Plugin {
|
||||
this.progressDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final DroidGap ctx = this.ctx;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.progressDialog = new ProgressDialog(ctx);
|
||||
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
package com.phonegap;
|
||||
|
||||
public class SplashScreen {
|
||||
private final DroidGap gap;
|
||||
public SplashScreen(DroidGap gap) {
|
||||
this.gap = gap;
|
||||
}
|
||||
public void hide() {
|
||||
gap.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
gap.hideSplashScreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,21 @@ import android.database.Cursor;
|
||||
import android.database.sqlite.*;
|
||||
|
||||
/**
|
||||
* This class implements the HTML5 database support for Android 1.X devices.
|
||||
* It is not used for Android 2.X, since HTML5 database is built in to the browser.
|
||||
* This class implements the HTML5 database support for Android 1.X devices. It
|
||||
* is not used for Android 2.X, since HTML5 database is built in to the browser.
|
||||
*/
|
||||
public class Storage extends Plugin {
|
||||
|
||||
// Data Definition Language
|
||||
private static final String ALTER = "alter";
|
||||
private static final String CREATE = "create";
|
||||
private static final String DROP = "drop";
|
||||
private static final String TRUNCATE = "truncate";
|
||||
|
||||
SQLiteDatabase myDb = null; // Database object
|
||||
String path = null; // Database path
|
||||
String dbName = null; // Database name
|
||||
|
||||
SQLiteDatabase myDb = null; // Database object
|
||||
String path = null; // Database path
|
||||
String dbName = null; // Database name
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -34,29 +40,37 @@ public class Storage extends Plugin {
|
||||
/**
|
||||
* 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.
|
||||
* @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 = "";
|
||||
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
// TODO: Do we want to allow a user to do this, since they could get to other app databases?
|
||||
// TODO: Do we want to allow a user to do this, since they could get
|
||||
// to other app databases?
|
||||
if (action.equals("setStorage")) {
|
||||
this.setStorage(args.getString(0));
|
||||
}
|
||||
else if (action.equals("openDatabase")) {
|
||||
this.openDatabase(args.getString(0), args.getString(1), args.getString(2), args.getLong(3));
|
||||
}
|
||||
else if (action.equals("executeSql")) {
|
||||
JSONArray a = args.getJSONArray(1);
|
||||
int len = a.length();
|
||||
String[] s = new String[len];
|
||||
for (int i=0; i<len; i++) {
|
||||
s[i] = a.getString(i);
|
||||
} else if (action.equals("openDatabase")) {
|
||||
this.openDatabase(args.getString(0), args.getString(1),
|
||||
args.getString(2), args.getLong(3));
|
||||
} else if (action.equals("executeSql")) {
|
||||
String[] s = null;
|
||||
if (args.isNull(1)) {
|
||||
s = new String[0];
|
||||
} else {
|
||||
JSONArray a = args.getJSONArray(1);
|
||||
int len = a.length();
|
||||
s = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
s[i] = a.getString(i);
|
||||
}
|
||||
}
|
||||
this.executeSql(args.getString(0), s, args.getString(2));
|
||||
}
|
||||
@@ -67,15 +81,17 @@ public class Storage extends Plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
* Identifies if action to be executed returns a value and should be run
|
||||
* synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
* @param action
|
||||
* The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clean up and close database.
|
||||
*/
|
||||
@@ -87,33 +103,40 @@ public class Storage extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the application package for the database. Each application saves its
|
||||
* database files in a directory with the application package as part of the file name.
|
||||
* Set the application package for the database. Each application saves its
|
||||
* database files in a directory with the application package as part of the
|
||||
* file name.
|
||||
*
|
||||
* For example, application "com.phonegap.demo.Demo" would save its database
|
||||
* files in "/data/data/com.phonegap.demo/databases/" directory.
|
||||
*
|
||||
* @param appPackage The application package.
|
||||
* @param appPackage
|
||||
* The application package.
|
||||
*/
|
||||
public void setStorage(String appPackage) {
|
||||
this.path = "/data/data/" + appPackage + "/databases/";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open database.
|
||||
*
|
||||
* @param db The name of the database
|
||||
* @param version The version
|
||||
* @param display_name The display name
|
||||
* @param size The size in bytes
|
||||
* @param db
|
||||
* The name of the database
|
||||
* @param version
|
||||
* The version
|
||||
* @param display_name
|
||||
* The display name
|
||||
* @param size
|
||||
* The size in bytes
|
||||
*/
|
||||
public void openDatabase(String db, String version, String display_name, long size) {
|
||||
|
||||
public void openDatabase(String db, String version, String display_name,
|
||||
long size) {
|
||||
|
||||
// If database is open, then close it
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
@@ -121,27 +144,36 @@ public class Storage extends Plugin {
|
||||
|
||||
// If no database path, generate from application package
|
||||
if (this.path == null) {
|
||||
Package pack = this.ctx.getClass().getPackage();
|
||||
String appPackage = pack.getName();
|
||||
this.setStorage(appPackage);
|
||||
Package pack = this.ctx.getClass().getPackage();
|
||||
String appPackage = pack.getName();
|
||||
this.setStorage(appPackage);
|
||||
}
|
||||
|
||||
|
||||
this.dbName = this.path + db + ".db";
|
||||
this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute SQL statement.
|
||||
*
|
||||
* @param query The SQL query
|
||||
* @param params Parameters for the query
|
||||
* @param tx_id Transaction id
|
||||
* @param query
|
||||
* The SQL query
|
||||
* @param params
|
||||
* Parameters for the query
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void executeSql(String query, String[] params, String tx_id) {
|
||||
try {
|
||||
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||
this.processResults(myCursor, tx_id);
|
||||
myCursor.close();
|
||||
if (isDDL(query)) {
|
||||
this.myDb.execSQL(query);
|
||||
this.sendJavascript("droiddb.completeQuery('" + tx_id + "', '');");
|
||||
}
|
||||
else {
|
||||
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||
this.processResults(myCursor, tx_id);
|
||||
myCursor.close();
|
||||
}
|
||||
}
|
||||
catch (SQLiteException ex) {
|
||||
ex.printStackTrace();
|
||||
@@ -151,44 +183,64 @@ public class Storage extends Plugin {
|
||||
this.sendJavascript("droiddb.fail('" + ex.getMessage() + "','" + tx_id + "');");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see the the query is a Data Definintion command
|
||||
*
|
||||
* @param query to be executed
|
||||
* @return true if it is a DDL command, false otherwise
|
||||
*/
|
||||
private boolean isDDL(String query) {
|
||||
String cmd = query.toLowerCase();
|
||||
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process query results.
|
||||
*
|
||||
* @param cur Cursor into query results
|
||||
* @param tx_id Transaction id
|
||||
* @param cur
|
||||
* Cursor into query results
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void processResults(Cursor cur, String tx_id) {
|
||||
|
||||
|
||||
String result = "[]";
|
||||
// If query result has rows
|
||||
|
||||
if (cur.moveToFirst()) {
|
||||
JSONArray fullresult = new JSONArray();
|
||||
String key = "";
|
||||
String value = "";
|
||||
int colCount = cur.getColumnCount();
|
||||
|
||||
|
||||
// Build up JSON result object for each row
|
||||
do {
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject row = new JSONObject();
|
||||
try {
|
||||
for (int i = 0; i < colCount; ++i) {
|
||||
key = cur.getColumnName(i);
|
||||
value = cur.getString(i).replace("\"", "\\\""); // must escape " with \" for JavaScript
|
||||
result.put(key, value);
|
||||
value = cur.getString(i);
|
||||
row.put(key, value);
|
||||
}
|
||||
fullresult.put(row);
|
||||
|
||||
// Send row back to JavaScript
|
||||
this.sendJavascript("droiddb.addResult('" + result.toString() + "','" + tx_id + "');");
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
} while (cur.moveToNext());
|
||||
|
||||
|
||||
result = fullresult.toString();
|
||||
}
|
||||
|
||||
// Let JavaScript know that there are no more rows
|
||||
this.sendJavascript("droiddb.completeQuery('" + tx_id + "');");
|
||||
|
||||
this.sendJavascript("droiddb.completeQuery('" + tx_id + "', " + result
|
||||
+ ");");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
3
framework/src/com/phonegap/TempListener.java
Normal file → Executable file
3
framework/src/com/phonegap/TempListener.java
Normal file → Executable file
@@ -11,6 +11,7 @@ import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
|
||||
@@ -37,7 +38,7 @@ public class TempListener extends Plugin implements SensorEventListener {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import com.phonegap.DroidGap;
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
@@ -43,7 +42,7 @@ public interface IPlugin {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
void setContext(DroidGap ctx);
|
||||
void setContext(PhonegapActivity ctx);
|
||||
|
||||
/**
|
||||
* Sets the main View of the application, this is the WebView within which
|
||||
@@ -55,13 +54,17 @@ public interface IPlugin {
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onPause();
|
||||
void onPause(boolean multitasking);
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onResume();
|
||||
void onResume(boolean multitasking);
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
|
||||
43
framework/src/com/phonegap/api/PhonegapActivity.java
Executable file
43
framework/src/com/phonegap/api/PhonegapActivity.java
Executable file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* The Phonegap activity abstract class that is extended by DroidGap.
|
||||
* It is used to isolate plugin development, and remove dependency on entire Phonegap library.
|
||||
*/
|
||||
public abstract class PhonegapActivity extends Activity {
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
abstract public void addService(String serviceType, String className);
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
abstract public void sendJavascript(String statement);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract public void startActivityForResult(Plugin command, Intent intent, int requestCode);
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import com.phonegap.DroidGap;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.webkit.WebView;
|
||||
public abstract class Plugin implements IPlugin {
|
||||
|
||||
public WebView webView; // WebView object
|
||||
public DroidGap ctx; // DroidGap object
|
||||
public PhonegapActivity ctx; // PhonegapActivity object
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
@@ -48,7 +48,7 @@ public abstract class Plugin implements IPlugin {
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(DroidGap ctx) {
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@@ -64,14 +64,24 @@ public abstract class Plugin implements IPlugin {
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onPause() {
|
||||
public void onPause(boolean multitasking) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume() {
|
||||
public void onResume(boolean multitasking) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,8 +13,8 @@ import java.util.Map.Entry;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
import com.phonegap.DroidGap;
|
||||
|
||||
/**
|
||||
* PluginManager is exposed to JavaScript in the PhoneGap WebView.
|
||||
@@ -27,7 +27,7 @@ public final class PluginManager {
|
||||
private HashMap<String, Plugin> plugins = new HashMap<String,Plugin>();
|
||||
private HashMap<String, String> services = new HashMap<String,String>();
|
||||
|
||||
private final DroidGap ctx;
|
||||
private final PhonegapActivity ctx;
|
||||
private final WebView app;
|
||||
|
||||
/**
|
||||
@@ -36,7 +36,7 @@ public final class PluginManager {
|
||||
* @param app
|
||||
* @param ctx
|
||||
*/
|
||||
public PluginManager(WebView app, DroidGap ctx) {
|
||||
public PluginManager(WebView app, PhonegapActivity ctx) {
|
||||
this.ctx = ctx;
|
||||
this.app = app;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public final class PluginManager {
|
||||
}
|
||||
if (isPhoneGapPlugin(c)) {
|
||||
final Plugin plugin = this.addPlugin(clazz, c);
|
||||
final DroidGap ctx = this.ctx;
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
runAsync = async && !plugin.isSynch(action);
|
||||
if (runAsync) {
|
||||
// Run this on a different thread so that this one can return back to JS
|
||||
@@ -195,7 +195,7 @@ public final class PluginManager {
|
||||
try {
|
||||
Plugin plugin = (Plugin)clazz.newInstance();
|
||||
this.plugins.put(className, plugin);
|
||||
plugin.setContext((DroidGap)this.ctx);
|
||||
plugin.setContext(this.ctx);
|
||||
plugin.setView(this.app);
|
||||
return plugin;
|
||||
}
|
||||
@@ -230,27 +230,31 @@ public final class PluginManager {
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onPause() {
|
||||
public void onPause(boolean multitasking) {
|
||||
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
|
||||
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
|
||||
while(it.hasNext()) {
|
||||
Entry<String,Plugin> entry = it.next();
|
||||
Plugin plugin = entry.getValue();
|
||||
plugin.onPause();
|
||||
plugin.onPause(multitasking);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume() {
|
||||
public void onResume(boolean multitasking) {
|
||||
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
|
||||
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
|
||||
while(it.hasNext()) {
|
||||
Entry<String,Plugin> entry = it.next();
|
||||
Plugin plugin = entry.getValue();
|
||||
plugin.onResume();
|
||||
plugin.onResume(multitasking);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,4 +270,17 @@ public final class PluginManager {
|
||||
plugin.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
|
||||
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
|
||||
while(it.hasNext()) {
|
||||
Entry<String,Plugin> entry = it.next();
|
||||
Plugin plugin = entry.getValue();
|
||||
plugin.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,13 @@ package com.phonegap.api;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class PluginResult {
|
||||
private final int status;
|
||||
private final String message;
|
||||
private boolean keepCallback = false;
|
||||
private String cast = null;
|
||||
|
||||
public PluginResult(Status status) {
|
||||
this.status = status.ordinal();
|
||||
@@ -22,7 +25,19 @@ public class PluginResult {
|
||||
|
||||
public PluginResult(Status status, String message) {
|
||||
this.status = status.ordinal();
|
||||
this.message = "'" + message + "'";
|
||||
this.message = JSONObject.quote(message);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONArray message, String cast) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
this.cast = cast;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONObject message, String cast) {
|
||||
this.status = status.ordinal();
|
||||
this.message = message.toString();
|
||||
this.cast = cast;
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONArray message) {
|
||||
@@ -71,7 +86,15 @@ public class PluginResult {
|
||||
}
|
||||
|
||||
public String toSuccessCallbackString(String callbackId) {
|
||||
return "PhoneGap.callbackSuccess('"+callbackId+"', " + this.getJSONString() + " );";
|
||||
StringBuffer buf = new StringBuffer("");
|
||||
if (cast != null) {
|
||||
buf.append("var temp = "+cast+"("+this.getJSONString() + ");\n");
|
||||
buf.append("PhoneGap.callbackSuccess('"+callbackId+"',temp);");
|
||||
}
|
||||
else {
|
||||
buf.append("PhoneGap.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String toErrorCallbackString(String callbackId) {
|
||||
|
||||
9
framework/src/com/phonegap/file/EncodingException.java
Normal file
9
framework/src/com/phonegap/file/EncodingException.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.phonegap.file;
|
||||
|
||||
public class EncodingException extends Exception {
|
||||
|
||||
public EncodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
9
framework/src/com/phonegap/file/FileExistsException.java
Normal file
9
framework/src/com/phonegap/file/FileExistsException.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.phonegap.file;
|
||||
|
||||
public class FileExistsException extends Exception {
|
||||
|
||||
public FileExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.phonegap.file;
|
||||
|
||||
public class InvalidModificationException extends Exception {
|
||||
|
||||
public InvalidModificationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.phonegap.file;
|
||||
|
||||
public class NoModificationAllowedException extends Exception {
|
||||
|
||||
public NoModificationAllowedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.phonegap.file;
|
||||
|
||||
public class TypeMismatchException extends Exception {
|
||||
|
||||
public TypeMismatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
60
lib/classic.rb
Normal file → Executable file
60
lib/classic.rb
Normal file → Executable file
@@ -5,7 +5,7 @@ class Classic
|
||||
@android_sdk_path, @name, @pkg, @www, @path = a
|
||||
build
|
||||
end
|
||||
|
||||
|
||||
def build
|
||||
setup
|
||||
clobber
|
||||
@@ -16,23 +16,29 @@ class Classic
|
||||
copy_libs
|
||||
add_name_to_strings
|
||||
write_java
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def setup
|
||||
@android_dir = File.expand_path(File.dirname(__FILE__).gsub('lib',''))
|
||||
@android_dir = File.expand_path(File.dirname(__FILE__).gsub(/lib$/,''))
|
||||
@framework_dir = File.join(@android_dir, "framework")
|
||||
@icon = File.join(@www, 'icon.png')
|
||||
@icon = File.join(@www, 'icon.png') unless !@icon.nil? && File.exists?(@icon)
|
||||
# Hash that stores the location of icons for each resolution type. Uses the default icon for all resolutions as a baseline.
|
||||
@icons = {
|
||||
:"drawable-ldpi" => @icon,
|
||||
:"drawable-mdpi" => @icon,
|
||||
:"drawable-hdpi" => @icon
|
||||
} if @icons.nil?
|
||||
@app_js_dir = ''
|
||||
@content = 'index.html'
|
||||
end
|
||||
|
||||
|
||||
# replaces @path with new android project
|
||||
def clobber
|
||||
FileUtils.rm_r(@path) if File.exists? @path
|
||||
FileUtils.mkdir_p @path
|
||||
end
|
||||
|
||||
# removes local.properties and recreates based on android_sdk_path
|
||||
|
||||
# removes local.properties and recreates based on android_sdk_path
|
||||
# then generates framework/phonegap.jar
|
||||
def build_jar
|
||||
%w(local.properties phonegap.js phonegap.jar).each do |f|
|
||||
@@ -40,7 +46,7 @@ class Classic
|
||||
end
|
||||
open(File.join(@framework_dir, "local.properties"), 'w') do |f|
|
||||
f.puts "sdk.dir=#{ @android_sdk_path }"
|
||||
end
|
||||
end
|
||||
Dir.chdir(@framework_dir)
|
||||
`ant jar`
|
||||
Dir.chdir(@android_dir)
|
||||
@@ -49,9 +55,9 @@ class Classic
|
||||
# runs android create project
|
||||
# TODO need to allow more flexible SDK targetting via config.xml
|
||||
def create_android
|
||||
IO.popen("android list targets") { |f|
|
||||
IO.popen("android list targets") { |f|
|
||||
targets = f.readlines(nil)[0].scan(/id\:.*$/)
|
||||
if (targets.length > 0)
|
||||
if (targets.length > 0)
|
||||
target_id = targets.last.match(/\d+/).to_a.first
|
||||
`android create project -t #{ target_id } -k #{ @pkg } -a #{ @name } -n #{ @name } -p #{ @path }`
|
||||
else
|
||||
@@ -60,7 +66,7 @@ class Classic
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
# copies the project/www folder into tmp/android/www
|
||||
def include_www
|
||||
FileUtils.mkdir_p File.join(@path, "assets", "www")
|
||||
@@ -82,11 +88,12 @@ class Classic
|
||||
|
||||
# copies stuff from src directory into the android project directory (@path)
|
||||
def copy_libs
|
||||
version = IO.read(File.join(@framework_dir, '../VERSION'))
|
||||
framework_res_dir = File.join(@framework_dir, "res")
|
||||
app_res_dir = File.join(@path, "res")
|
||||
# copies in the jar
|
||||
FileUtils.mkdir_p File.join(@path, "libs")
|
||||
FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs")
|
||||
FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs")
|
||||
# copies in the strings.xml
|
||||
FileUtils.mkdir_p File.join(app_res_dir, "values")
|
||||
FileUtils.cp File.join(framework_res_dir, "values","strings.xml"), File.join(app_res_dir, "values", "strings.xml")
|
||||
@@ -96,11 +103,19 @@ class Classic
|
||||
FileUtils.cp File.join(framework_res_dir, "layout", f), File.join(app_res_dir, "layout", f)
|
||||
end
|
||||
# icon file copy
|
||||
# if it is not in the www directory use the default one in the src dir
|
||||
@icon = File.join(framework_res_dir, "drawable", "icon.png") unless File.exists?(@icon)
|
||||
%w(drawable-hdpi drawable-ldpi drawable-mdpi).each do |e|
|
||||
# if specific resolution icons are specified, use those. if not, see if a general purpose icon was defined.
|
||||
# finally, fall back to using the default PhoneGap one.
|
||||
currentIcon = ""
|
||||
if !@icons[e.to_sym].nil? && File.exists?(File.join(@www, @icons[e.to_sym]))
|
||||
currentIcon = File.join(@www, @icons[e.to_sym])
|
||||
elsif File.exists?(@icon)
|
||||
currentIcon = @icon
|
||||
else
|
||||
currentIcon = File.join(framework_res_dir, "drawable", "icon.png")
|
||||
end
|
||||
FileUtils.mkdir_p(File.join(app_res_dir, e))
|
||||
FileUtils.cp(@icon, File.join(app_res_dir, e, "icon.png"))
|
||||
FileUtils.cp(currentIcon, File.join(app_res_dir, e, "icon.png"))
|
||||
end
|
||||
# concat JS and put into www folder. this can be overridden in the config.xml via @app_js_dir
|
||||
js_dir = File.join(@framework_dir, "assets", "js")
|
||||
@@ -110,9 +125,9 @@ class Classic
|
||||
phonegapjs << IO.read(File.join(js_dir, script))
|
||||
phonegapjs << "\n\n"
|
||||
end
|
||||
File.open(File.join(@path, "assets", "www", @app_js_dir, "phonegap.js"), 'w') {|f| f.write(phonegapjs) }
|
||||
File.open(File.join(@path, "assets", "www", @app_js_dir, "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) }
|
||||
end
|
||||
|
||||
|
||||
# puts app name in strings
|
||||
def add_name_to_strings
|
||||
x = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
||||
@@ -123,11 +138,10 @@ class Classic
|
||||
"
|
||||
open(File.join(@path, "res", "values", "strings.xml"), 'w') do |f|
|
||||
f.puts x.gsub(' ','')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# this is so fucking unholy yet oddly beautiful
|
||||
# not sure if I should thank Ruby or apologize for this abusive use of string interpolation
|
||||
# create java source file
|
||||
def write_java
|
||||
j = "
|
||||
package #{ @pkg };
|
||||
@@ -150,7 +164,7 @@ class Classic
|
||||
FileUtils.mkdir_p(code_dir)
|
||||
open(File.join(code_dir, "#{ @name }.java"),'w') { |f| f.puts j }
|
||||
end
|
||||
|
||||
|
||||
# friendly output for now
|
||||
def msg
|
||||
puts "Created #{ @path }"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Create
|
||||
#
|
||||
#
|
||||
# Generates an Android project from a valid WWW directory and puts it in ../[PROJECT NAME]_android
|
||||
#
|
||||
class Create < Classic
|
||||
@@ -8,65 +8,90 @@ class Create < Classic
|
||||
read_config
|
||||
build
|
||||
end
|
||||
|
||||
|
||||
def guess_paths(path)
|
||||
# if no path is supplied uses current directory for project
|
||||
path = FileUtils.pwd if path.nil?
|
||||
|
||||
|
||||
# if a www is found use it for the project
|
||||
path = File.join(path, 'www') if File.exists? File.join(path, 'www')
|
||||
|
||||
|
||||
# defaults
|
||||
@name = path.split("/").last.gsub('-','').gsub(' ','') # no dashses nor spaces
|
||||
@path = File.join(path, '..', "#{ @name }_android")
|
||||
@www = path
|
||||
@pkg = "com.phonegap.#{ @name }"
|
||||
@www = path
|
||||
@pkg = "com.phonegap.#{ @name }"
|
||||
@android_sdk_path = Dir.getwd[0,1] != "/" ? `android-sdk-path.bat android.bat`.gsub('\\tools','').gsub('\\', '\\\\\\\\') : `which android`.gsub(/\/tools\/android$/,'').chomp
|
||||
@android_dir = File.expand_path(File.dirname(__FILE__).gsub('lib',''))
|
||||
@framework_dir = File.join(@android_dir, "framework")
|
||||
@icon = File.join(@www, 'icon.png')
|
||||
@app_js_dir = ''
|
||||
@content = 'index.html'
|
||||
|
||||
|
||||
# stop executation on errors
|
||||
raise 'Expected index.html in the following folder #{ path }.\nThe path is expected to be the directory droidgap create is run from or specified as a command line arg like droidgap create my_path.' unless File.exists? File.join(path, 'index.html')
|
||||
raise "Expected index.html in the following folder #{ path }.\nThe path is expected to be the directory droidgap create is run from or specified as a command line arg like droidgap create my_path." unless File.exists? File.join(path, 'index.html')
|
||||
raise 'Could not find android in your PATH!' if @android_sdk_path.empty?
|
||||
end
|
||||
|
||||
# reads in a config.xml file
|
||||
def read_config
|
||||
config_file = File.join(@www, 'config.xml')
|
||||
|
||||
|
||||
if File.exists?(config_file)
|
||||
require 'rexml/document'
|
||||
f = File.new config_file
|
||||
doc = REXML::Document.new(f)
|
||||
@config = {}
|
||||
doc = REXML::Document.new(f)
|
||||
@config = {}
|
||||
@config[:id] = doc.root.attributes["id"]
|
||||
@config[:version] = doc.root.attributes["version"]
|
||||
|
||||
@config[:icons] = {}
|
||||
defaultIconSize = 0
|
||||
doc.root.elements.each do |n|
|
||||
@config[:name] = n.text.gsub('-','').gsub(' ','') if n.name == 'name'
|
||||
@config[:description] = n.text if n.name == 'description'
|
||||
@config[:icon] = n.attributes["src"] if n.name == 'icon'
|
||||
@config[:content] = n.attributes["src"] if n.name == 'content'
|
||||
|
||||
@config[:name] = n.text.gsub('-','').gsub(' ','') if n.name == 'name'
|
||||
@config[:description] = n.text if n.name == 'description'
|
||||
@config[:content] = n.attributes["src"] if n.name == 'content'
|
||||
if n.name == 'icon'
|
||||
if n.attributes["width"] == '72' && n.attributes["height"] == '72'
|
||||
@config[:icons]["drawable-hdpi".to_sym] = n.attributes["src"]
|
||||
if 72 > defaultIconSize
|
||||
@config[:icon] = n.attributes["src"]
|
||||
defaultIconSize = 72
|
||||
end
|
||||
elsif n.attributes["width"] == '48' && n.attributes["height"] == '48'
|
||||
@config[:icons]["drawable-mdpi".to_sym] = n.attributes["src"]
|
||||
if 48 > defaultIconSize
|
||||
@config[:icon] = n.attributes["src"]
|
||||
defaultIconSize = 48
|
||||
end
|
||||
elsif n.attributes["width"] == '36' && n.attributes["height"] == '36'
|
||||
@config[:icons]["drawable-ldpi".to_sym] = n.attributes["src"]
|
||||
if 36 > defaultIconSize
|
||||
@config[:icon] = n.attributes["src"]
|
||||
defaultIconSize = 36
|
||||
end
|
||||
else
|
||||
@config[:icon] = n.attributes["src"]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if n.name == "preference" && n.attributes["name"] == 'javascript_folder'
|
||||
@config[:js_dir] = n.attributes["value"]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# extract android specific stuff
|
||||
@config[:versionCode] = doc.elements["//android:versionCode"] ? doc.elements["//android:versionCode"].text : 3
|
||||
@config[:minSdkVersion] = doc.elements["//android:minSdkVersion"] ? doc.elements["//android:minSdkVersion"].text : 1
|
||||
# will change the name from the directory to the name element text
|
||||
@name = @config[:name] if @config[:name]
|
||||
# set the icon from the config
|
||||
@icon = File.join(@www, @config[:icon])
|
||||
@icon = File.join(@www, @config[:icon]) if @config[:icon]
|
||||
@icons = @config[:icons] if @config[:icons].length > 0
|
||||
# sets the app js dir where phonegap.js gets copied
|
||||
@app_js_dir = @config[:js_dir] ? @config[:js_dir] : ''
|
||||
# sets the start page
|
||||
@content = @config[:content] ? @config[:content] : 'index.html'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
19
lib/update.rb
Normal file → Executable file
19
lib/update.rb
Normal file → Executable file
@@ -15,9 +15,9 @@ class Update
|
||||
end
|
||||
|
||||
# removes local.properties and recreates based on android_sdk_path
|
||||
# then generates framework/phonegap.jar
|
||||
# then generates framework/phonegap.jar & framework/assets/www/phonegap.js
|
||||
def build_jar
|
||||
puts "Building the JAR..."
|
||||
puts "Building the JAR and combining JS files..."
|
||||
%w(local.properties phonegap.js phonegap.jar).each do |f|
|
||||
FileUtils.rm File.join(@framework_dir, f) if File.exists? File.join(@framework_dir, f)
|
||||
end
|
||||
@@ -32,23 +32,20 @@ class Update
|
||||
# copies stuff from framework into the project
|
||||
# TODO need to allow for www import inc icon
|
||||
def copy_libs
|
||||
puts "Copying over libraries and assets and creating phonegap.js..."
|
||||
|
||||
FileUtils.mkdir_p File.join(@path, "libs")
|
||||
FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs")
|
||||
puts "Copying over libraries and assets..."
|
||||
version = IO.read(File.join(@framework_dir, '../VERSION'))
|
||||
|
||||
# concat JS and put into www folder.
|
||||
FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs")
|
||||
|
||||
# concat JS and put into www folder. this can be overridden in the config.xml via @app_js_dir
|
||||
js_dir = File.join(@framework_dir, "assets", "js")
|
||||
|
||||
phonegapjs = IO.read(File.join(js_dir, 'phonegap.js.base'))
|
||||
|
||||
Dir.new(js_dir).entries.each do |script|
|
||||
next if script[0].chr == "." or script == "phonegap.js.base"
|
||||
phonegapjs << IO.read(File.join(js_dir, script))
|
||||
phonegapjs << "\n\n"
|
||||
end
|
||||
|
||||
File.open(File.join(@path, "assets", "www", "phonegap.js"), 'w') {|f| f.write(phonegapjs) }
|
||||
File.open(File.join(@path, "assets", "www", "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) }
|
||||
end
|
||||
#
|
||||
end
|
||||
31
util/yuicompressor/LICENSE
Executable file
31
util/yuicompressor/LICENSE
Executable file
@@ -0,0 +1,31 @@
|
||||
YUI is issued by Yahoo! under the BSD License below.
|
||||
|
||||
Copyright (c) 2010, Yahoo! Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms, with or
|
||||
without modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Yahoo! Inc. nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission of Yahoo! Inc.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
http://developer.yahoo.com/yui/license.html
|
||||
|
||||
140
util/yuicompressor/README
Executable file
140
util/yuicompressor/README
Executable file
@@ -0,0 +1,140 @@
|
||||
==============================================================================
|
||||
YUI Compressor
|
||||
==============================================================================
|
||||
|
||||
NAME
|
||||
|
||||
YUI Compressor - The Yahoo! JavaScript and CSS Compressor
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
Usage: java -jar yuicompressor-x.y.z.jar [options] [input file]
|
||||
|
||||
Global Options
|
||||
-h, --help Displays this information
|
||||
--type <js|css> Specifies the type of the input file
|
||||
--charset <charset> Read the input file using <charset>
|
||||
--line-break <column> Insert a line break after the specified column number
|
||||
-v, --verbose Display informational messages and warnings
|
||||
-o <file> Place the output into <file>. Defaults to stdout.
|
||||
|
||||
JavaScript Options
|
||||
--nomunge Minify only, do not obfuscate
|
||||
--preserve-semi Preserve all semicolons
|
||||
--disable-optimizations Disable all micro optimizations
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The YUI Compressor is a JavaScript compressor which, in addition to removing
|
||||
comments and white-spaces, obfuscates local variables using the smallest
|
||||
possible variable name. This obfuscation is safe, even when using constructs
|
||||
such as 'eval' or 'with' (although the compression is not optimal is those
|
||||
cases) Compared to jsmin, the average savings is around 20%.
|
||||
|
||||
The YUI Compressor is also able to safely compress CSS files. The decision
|
||||
on which compressor is being used is made on the file extension (js or css)
|
||||
|
||||
GLOBAL OPTIONS
|
||||
|
||||
-h, --help
|
||||
Prints help on how to use the YUI Compressor
|
||||
|
||||
--line-break
|
||||
Some source control tools don't like files containing lines longer than,
|
||||
say 8000 characters. The linebreak option is used in that case to split
|
||||
long lines after a specific column. It can also be used to make the code
|
||||
more readable, easier to debug (especially with the MS Script Debugger)
|
||||
Specify 0 to get a line break after each semi-colon in JavaScript, and
|
||||
after each rule in CSS.
|
||||
|
||||
--type js|css
|
||||
The type of compressor (JavaScript or CSS) is chosen based on the
|
||||
extension of the input file name (.js or .css) This option is required
|
||||
if no input file has been specified. Otherwise, this option is only
|
||||
required if the input file extension is neither 'js' nor 'css'.
|
||||
|
||||
--charset character-set
|
||||
If a supported character set is specified, the YUI Compressor will use it
|
||||
to read the input file. Otherwise, it will assume that the platform's
|
||||
default character set is being used. The output file is encoded using
|
||||
the same character set.
|
||||
|
||||
-o outfile
|
||||
Place output in file outfile. If not specified, the YUI Compressor will
|
||||
default to the standard output, which you can redirect to a file.
|
||||
|
||||
-v, --verbose
|
||||
Display informational messages and warnings.
|
||||
|
||||
JAVASCRIPT ONLY OPTIONS
|
||||
|
||||
--nomunge
|
||||
Minify only. Do not obfuscate local symbols.
|
||||
|
||||
--preserve-semi
|
||||
Preserve unnecessary semicolons (such as right before a '}') This option
|
||||
is useful when compressed code has to be run through JSLint (which is the
|
||||
case of YUI for example)
|
||||
|
||||
--disable-optimizations
|
||||
Disable all the built-in micro optimizations.
|
||||
|
||||
NOTES
|
||||
|
||||
+ If no input file is specified, it defaults to stdin.
|
||||
|
||||
+ The YUI Compressor requires Java version >= 1.4.
|
||||
|
||||
+ It is possible to prevent a local variable, nested function or function
|
||||
argument from being obfuscated by using "hints". A hint is a string that
|
||||
is located at the very beginning of a function body like so:
|
||||
|
||||
function fn (arg1, arg2, arg3) {
|
||||
"arg2:nomunge, localVar:nomunge, nestedFn:nomunge";
|
||||
|
||||
...
|
||||
var localVar;
|
||||
...
|
||||
|
||||
function nestedFn () {
|
||||
....
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
The hint itself disappears from the compressed file.
|
||||
|
||||
+ C-style comments starting with /*! are preserved. This is useful with
|
||||
comments containing copyright/license information. For example:
|
||||
|
||||
/*!
|
||||
* TERMS OF USE - EASING EQUATIONS
|
||||
* Open source under the BSD License.
|
||||
* Copyright 2001 Robert Penner All rights reserved.
|
||||
*/
|
||||
|
||||
becomes:
|
||||
|
||||
/*
|
||||
* TERMS OF USE - EASING EQUATIONS
|
||||
* Open source under the BSD License.
|
||||
* Copyright 2001 Robert Penner All rights reserved.
|
||||
*/
|
||||
|
||||
AUTHOR
|
||||
|
||||
The YUI Compressor was written and is maintained by:
|
||||
Julien Lecomte <jlecomte@yahoo-inc.com>
|
||||
The CSS portion is a port of Isaac Schlueter's cssmin utility.
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
Copyright (c) 2007-2009, Yahoo! Inc. All rights reserved.
|
||||
|
||||
LICENSE
|
||||
|
||||
All code specific to YUI Compressor is issued under a BSD license.
|
||||
YUI Compressor extends and implements code from Mozilla's Rhino project.
|
||||
Rhino is issued under the Mozilla Public License (MPL), and MPL applies
|
||||
to the Rhino source and binaries that are distributed with YUI Compressor.
|
||||
BIN
util/yuicompressor/yuicompressor-2.4.2.jar
Executable file
BIN
util/yuicompressor/yuicompressor-2.4.2.jar
Executable file
Binary file not shown.
Reference in New Issue
Block a user