Compare commits

...

76 Commits

Author SHA1 Message Date
macdonst 7bb34dea14 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-29 00:02:07 -04:00
macdonst 004453b03f Upping version to 1.0.0 2011-07-29 12:01:46 +08:00
macdonst a1edf92fa4 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-28 23:58:09 -04:00
macdonst e28458869f Issue #185: Fix mis-spelling in file.js 2011-07-29 11:56:29 +08:00
macdonst 229e15f685 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-26 00:31:37 -04:00
macdonst 39d6952494 Upping version to 1.0.0rc3 2011-07-26 12:30:41 +08:00
macdonst b864a8a6c6 Upping version to 1.0.0rc3 2011-07-26 00:20:35 -04:00
macdonst f5dac1451d Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-26 00:18:33 -04:00
macdonst 2bf765897b Normalize Android Camera.takePicture with iOS and BB versions.
Both iOS and BlackBerry support the PNG image format so I added support for Android.

Also, iOS and BB use targetWidth/targetHeight to specify the resolution of the image.  I've swiched from using maxResolution to targetWidth/targetHeight in this change list.
2011-07-26 12:18:04 +08:00
macdonst 411288b051 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-25 11:05:38 -04:00
macdonst 1c97467e39 Issue #169: Media.seekTo() does not update Media._position value.
Calling Media.seekTo() now updates the Media._position value. I could not make seekTo() to work when your audio clip is not playing as that is not a supported action of the AndroidMedia player class.
2011-07-23 03:21:45 +08:00
macdonst 7c39edfcd0 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-21 22:31:26 -04:00
macdonst 9f673db79f Issue #176: rc2 for Android does not have updated main.js - demo app code
This commit fixes the issue in main.js but it will still need to be packaged up in the rc3 zip.
2011-07-22 10:06:43 +08:00
Dave Johnson 8c807315e9 there was a "Location" and a "Geolocation" plugin defined. We use "Geolocation" in the JavaScript 2011-07-21 16:42:59 -07:00
Joe Bowser be48b576d9 Merge branch 'master' of github.com:phonegap/phonegap-android 2011-07-21 13:16:09 -07:00
Joe Bowser 648e56cb67 Merging maxResolution 2011-07-21 13:15:52 -07:00
macdonst b37defd3cf Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-21 15:18:10 -04:00
macdonst c093881f54 Issue #174: contact attribs should return null instead of empty array
Currently the implementation will return an empty array for the following Contact attributes: phoneNumbers, emails, addresses, ims, organizations, addresses, websites and photos.  With this fix these attributes will be null unless the lenght of the array is greater than 0.
2011-07-22 03:16:45 +08:00
Brian LeRoux e09c728fd0 Edited framework/src/com/phonegap/DroidGap.java via GitHub 2011-07-21 11:47:20 -07:00
macdonst d098b6133e Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-21 11:59:41 -04:00
macdonst 029ddeade0 Fix Issue #170: Sub pages reload on orientation or keyboard changes
Needed to add android:configChanges="orientation|keyboardHidden" to the com.phonegap.DroidGap activity in AndroidManifest.xml.
2011-07-20 23:21:34 +08:00
macdonst 17ccb2db4d Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-20 11:13:33 -04:00
Bryce Curtis 6b84ead393 Issue #167: Remove window.app and use navigator.app instead. Remove App() from namespace. 2011-07-19 11:00:13 -05:00
macdonst 9bf3a82964 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-18 16:11:51 -04:00
macdonst 7afa2d3840 Upping version to 1.0.0rc2 2011-07-19 04:11:17 +08:00
macdonst e789349c23 Handle content:// uri's in resolveLocalFileSystemURI
Sometimes Android will hand you a content:// uri in the place of a file path. Particularily the Camera.getPicture() code will do this. I've updated the file utils code to handle this type of uri and return a real file path.
2011-07-19 04:10:55 +08:00
macdonst f7ebc98375 Upping version to 1.0.0rc2 2011-07-18 12:48:26 -04:00
Bryce Curtis 2787a960d8 Issue #153: Display default value in prompt(). 2011-07-16 15:07:34 -05:00
Dave Johnson 4af8952dc3 Merge pull request #161 from don/master
Write error to log when plugins.xml is missing
2011-07-15 22:03:42 -07:00
Don Coleman 701717fd55 remove comment from xml declaration 2011-07-15 23:47:08 -04:00
Don Coleman 3de2084af2 write error to log when plugins.xml is missing 2011-07-15 23:45:32 -04:00
Joe Bowser 6d532c9fe5 Minor change to Android Manifest for Android 3.2 to force it out of Compatibltiy Mode 2011-07-15 16:19:08 -07:00
macdonst eb0e0d9d11 Issue #156: Camera.DestinationType.FILE_URI on Android not conforming to API Spec
Instead of capturing the orginal image to /sdcard/Pic.jpg or /sdcard/Capture.jpg we detect if the SD card is mounted. If mounted the file is placed in the apps temp directory at:

/sdcard/Android/data/{package name}/cache/

If the SD card is not mounted we default to internal storage at:

/data/data/{package name}/cache/
2011-07-16 05:03:48 +08:00
Bryce Curtis 53410781e4 Issue #154: Propagate existing parameters when starting new DroidGap activity. 2011-07-15 15:00:12 -05:00
Bryce Curtis 2bee9a8442 Remove deprecated addService() method. The new way to register a plugin is to include it in res/xml/plugins.xml. 2011-07-15 14:26:20 -05:00
Bryce Curtis 7c9eca1fab Replace deprecated call to activityStop. 2011-07-15 14:04:46 -05:00
Bryce Curtis 017fa1b917 Use the same database based upon application context for each html page loaded as part of this app. 2011-07-13 16:48:29 -05:00
Bryce Curtis 24bb836221 Shouldn't return error on first call. This prevents successful invocation, which prevents deviceready from firing. 2011-07-13 00:21:34 -05:00
macdonst 6993c7edd1 Merge pull request #152 from macdonst/issue151
Issue151: Remove minification of phonegap.*.js file
2011-07-12 15:03:25 -07:00
macdonst 4cc3772e84 Issue #151: Remove minification of phonegap.*.js file 2011-07-12 15:33:46 -04:00
macdonst 2a3c387ce3 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-12 12:23:34 -04:00
macdonst c80ddc1b22 Issue #149: Deprecate support for Android 1.X devices
Right now we are just removing the code for Contacts on 1.5/1.6 devices. We still need to keep around our implementation of Geolocation and Storage for older devices since some versions of Android have broken implementations of these features. Android 3.0 I'm looking at you!
2011-07-13 00:18:38 +08:00
macdonst e1092590d6 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-12 11:05:56 -04:00
macdonst 24f979394f Remove deprecated Network.isReachable (use the Network Information API instead) 2011-07-12 23:01:42 +08:00
macdonst 9971d61601 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-12 10:58:28 -04:00
Bryce Curtis 6c65a6a016 Make sure we load the correct resource id for plugins.xml. 2011-07-11 22:56:20 -05:00
macdonst 37b9cc47bd Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-11 23:30:41 -04:00
macdonst 66f7afbed2 Issue #146: File API - File::writeAsText not in the API, remove 2011-07-12 11:13:24 +08:00
macdonst b1c0be3dd6 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-11 22:53:46 -04:00
Dave Johnson 60be45b9d9 Fix example to not include the min.js that is non-existent 2011-07-11 18:21:55 -07:00
macdonst 393bd5a1f5 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-11 17:28:56 -04:00
macdonst 1de036a744 Setting version as 1.0.0rc1 2011-07-12 05:25:53 +08:00
macdonst a235513991 Setting version as 1.0.0rc1 2011-07-11 17:24:33 -04:00
macdonst 22a9cabeb9 Updating Contacts for June 16th W3C Spec 2011-07-11 23:18:24 +08:00
Bryce Curtis 5de4ae7554 Remove dependency on notification.activityStart/Stop so they can be deprecated to an optional plugin. Also remove hideLoadingDialogOnPage option, since it no longer is relevant. 2011-07-08 23:07:22 -05:00
Bryce Curtis f19d8f9bba Change to PhoneGap naming convention affects droidgap creation & update. Also, create script uses phonegap-x.js, not phonegap-x.min.js. 2011-07-08 16:27:57 -05:00
macdonst d4ccc702b2 Merge pull request #145 from macdonst/fixJar
Update .gitignore and .jar file name
2011-07-08 13:44:45 -07:00
macdonst a0c748620a Update .gitignore and .jar file name 2011-07-08 16:40:55 -04:00
macdonst b85a769372 Merge pull request #144 from macdonst/is129
Fix for #129: PhoneGap JS Naming Convention
2011-07-08 12:03:26 -07:00
macdonst dd52081deb Fix for #129: PhoneGap JS Naming Convention 2011-07-08 14:35:31 -04:00
macdonst ebd92a4b12 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-07 16:49:22 -04:00
macdonst 6e62a76564 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-07 13:08:25 -04:00
macdonst 709eacd9dc Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-07-07 11:49:24 -04:00
macdonst 7cc1cc4a3f Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-30 15:43:50 -04:00
macdonst 102d37d48a Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-30 11:58:12 -04:00
macdonst afb48e52b6 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-29 09:55:31 -04:00
macdonst 2a786044de Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-28 14:26:50 -04:00
macdonst 5c8913351c Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-27 12:34:33 -04:00
macdonst 226e4dddcd Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-24 16:43:31 -04:00
macdonst 66dbd9ef8b Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-24 10:56:05 -04:00
macdonst 1a9471a2e0 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-22 14:48:49 -04:00
macdonst 5e733ede9f Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-16 09:57:02 -04:00
macdonst e5fb0c0e71 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-14 09:59:19 -04:00
macdonst b46cbfd673 Merge branch 'master' of git://github.com/phonegap/phonegap-android 2011-06-08 15:17:36 -04:00
macdonst fbb6b22de6 Updating Network Connection API to match spec released on June 7th 2011-06-08 15:03:03 -04:00
Ron Reiter 307f9d1871 Add maxResolution flag 2011-04-04 02:57:10 +03:00
34 changed files with 833 additions and 1621 deletions
+2
View File
@@ -4,6 +4,8 @@ gen
assets/www/phonegap.js assets/www/phonegap.js
local.properties local.properties
framework/phonegap.jar framework/phonegap.jar
framework/phonegap-*.jar
framework/bin framework/bin
framework/assets/www/.DS_Store framework/assets/www/.DS_Store
framework/assets/www/phonegap-*.js
.DS_Store .DS_Store
+1 -1
View File
@@ -1 +1 @@
0.9.6.1 1.0.0
+1 -1
View File
@@ -5,7 +5,7 @@
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title> <title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8"> <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.0.9.6.1.min.js"></script> <script type="text/javascript" charset="utf-8" src="phonegap-1.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="main.js"></script> <script type="text/javascript" charset="utf-8" src="main.js"></script>
</head> </head>
+13 -26
View File
@@ -88,16 +88,6 @@ function close() {
viewport.style.display = "none"; 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) { function contacts_success(contacts) {
alert(contacts.length alert(contacts.length
+ ' contacts returned.' + ' contacts returned.'
@@ -109,27 +99,24 @@ function get_contacts() {
var obj = new ContactFindOptions(); var obj = new ContactFindOptions();
obj.filter = ""; obj.filter = "";
obj.multiple = true; obj.multiple = true;
obj.limit = 5; navigator.contacts.find(
navigator.service.contacts.find(
[ "displayName", "name" ], contacts_success, [ "displayName", "name" ], contacts_success,
fail, obj); 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() { function check_network() {
navigator.network.isReachable("www.mobiledevelopersolutions.com", var networkState = navigator.network.connection.type;
networkReachableCallback, {});
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.NONE] = 'No network connection';
confirm('Connection type:\n ' + states[networkState]);
} }
function init() { function init() {
+3 -1
View File
@@ -5,6 +5,7 @@
android:largeScreens="true" android:largeScreens="true"
android:normalScreens="true" android:normalScreens="true"
android:smallScreens="true" android:smallScreens="true"
android:xlargeScreens="true"
android:resizeable="true" android:resizeable="true"
android:anyDensity="true" android:anyDensity="true"
/> />
@@ -37,7 +38,8 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.phonegap.DroidGap" android:label="@string/app_name"> <activity android:name="com.phonegap.DroidGap" android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<intent-filter> <intent-filter>
</intent-filter> </intent-filter>
</activity> </activity>
+3 -11
View File
@@ -8,6 +8,7 @@
if (!PhoneGap.hasResource("app")) { if (!PhoneGap.hasResource("app")) {
PhoneGap.addResource("app"); PhoneGap.addResource("app");
(function() {
/** /**
* Constructor * Constructor
@@ -58,16 +59,6 @@ App.prototype.clearHistory = function() {
PhoneGap.exec(null, null, "App", "clearHistory", []); 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. * Override the default behavior of the Android back button.
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
@@ -89,6 +80,7 @@ App.prototype.exitApp = function() {
}; };
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
navigator.app = window.app = new App(); navigator.app = new App();
}); });
}());
} }
+47 -1
View File
@@ -34,6 +34,21 @@ Camera.DestinationType = {
}; };
Camera.prototype.DestinationType = Camera.DestinationType; Camera.prototype.DestinationType = Camera.DestinationType;
/**
* Encoding of image returned from getPicture.
*
* Example: navigator.camera.getPicture(success, fail,
* { quality: 80,
* destinationType: Camera.DestinationType.DATA_URL,
* sourceType: Camera.PictureSourceType.CAMERA,
* encodingType: Camera.EncodingType.PNG})
*/
Camera.EncodingType = {
JPEG: 0, // Return JPEG encoded image
PNG: 1 // Return PNG encoded image
};
Camera.prototype.EncodingType = Camera.EncodingType;
/** /**
* Source to getPicture from. * Source to getPicture from.
* *
@@ -78,6 +93,12 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
if (options.quality) { if (options.quality) {
quality = this.options.quality; quality = this.options.quality;
} }
var maxResolution = 0;
if (options.maxResolution) {
maxResolution = this.options.maxResolution;
}
var destinationType = Camera.DestinationType.DATA_URL; var destinationType = Camera.DestinationType.DATA_URL;
if (this.options.destinationType) { if (this.options.destinationType) {
destinationType = this.options.destinationType; destinationType = this.options.destinationType;
@@ -86,7 +107,32 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
if (typeof this.options.sourceType === "number") { if (typeof this.options.sourceType === "number") {
sourceType = this.options.sourceType; sourceType = this.options.sourceType;
} }
PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType]); var encodingType = Camera.EncodingType.JPEG;
if (typeof options.encodingType == "number") {
encodingType = this.options.encodingType;
}
var targetWidth = -1;
if (typeof options.targetWidth == "number") {
targetWidth = options.targetWidth;
} else if (typeof options.targetWidth == "string") {
var width = new Number(options.targetWidth);
if (isNaN(width) === false) {
targetWidth = width.valueOf();
}
}
var targetHeight = -1;
if (typeof options.targetHeight == "number") {
targetHeight = options.targetHeight;
} else if (typeof options.targetHeight == "string") {
var height = new Number(options.targetHeight);
if (isNaN(height) === false) {
targetHeight = height.valueOf();
}
}
PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType]);
}; };
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
+28 -27
View File
@@ -21,17 +21,14 @@ PhoneGap.addResource("contact");
* @param {Array.<ContactAddress>} addresses array of addresses * @param {Array.<ContactAddress>} addresses array of addresses
* @param {Array.<ContactField>} ims instant messaging user ids * @param {Array.<ContactField>} ims instant messaging user ids
* @param {Array.<ContactOrganization>} organizations * @param {Array.<ContactOrganization>} organizations
* @param {DOMString} revision date contact was last updated
* @param {DOMString} birthday contact's birthday * @param {DOMString} birthday contact's birthday
* @param {DOMString} gender contact's gender
* @param {DOMString} note user notes about contact * @param {DOMString} note user notes about contact
* @param {Array.<ContactField>} photos * @param {Array.<ContactField>} photos
* @param {Array.<ContactField>} categories * @param {Array.<ContactField>} categories
* @param {Array.<ContactField>} urls contact's web sites * @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, var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
ims, organizations, revision, birthday, gender, note, photos, categories, urls, timezone) { ims, organizations, birthday, note, photos, categories, urls) {
this.id = id || null; this.id = id || null;
this.rawId = null; this.rawId = null;
this.displayName = displayName || null; this.displayName = displayName || null;
@@ -42,14 +39,11 @@ var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, a
this.addresses = addresses || null; // ContactAddress[] this.addresses = addresses || null; // ContactAddress[]
this.ims = ims || null; // ContactField[] this.ims = ims || null; // ContactField[]
this.organizations = organizations || null; // ContactOrganization[] this.organizations = organizations || null; // ContactOrganization[]
this.revision = revision || null;
this.birthday = birthday || null; this.birthday = birthday || null;
this.gender = gender || null;
this.note = note || null; this.note = note || null;
this.photos = photos || null; // ContactField[] this.photos = photos || null; // ContactField[]
this.categories = categories || null; // ContactField[] this.categories = categories || null; // ContactField[]
this.urls = urls || null; // ContactField[] this.urls = urls || null; // ContactField[]
this.timezone = timezone || null;
}; };
/** /**
@@ -66,11 +60,10 @@ var ContactError = function() {
*/ */
ContactError.UNKNOWN_ERROR = 0; ContactError.UNKNOWN_ERROR = 0;
ContactError.INVALID_ARGUMENT_ERROR = 1; ContactError.INVALID_ARGUMENT_ERROR = 1;
ContactError.NOT_FOUND_ERROR = 2; ContactError.TIMEOUT_ERROR = 2;
ContactError.TIMEOUT_ERROR = 3; ContactError.PENDING_OPERATION_ERROR = 3;
ContactError.PENDING_OPERATION_ERROR = 4; ContactError.IO_ERROR = 4;
ContactError.IO_ERROR = 5; ContactError.NOT_SUPPORTED_ERROR = 5;
ContactError.NOT_SUPPORTED_ERROR = 6;
ContactError.PERMISSION_DENIED_ERROR = 20; ContactError.PERMISSION_DENIED_ERROR = 20;
/** /**
@@ -81,7 +74,7 @@ ContactError.PERMISSION_DENIED_ERROR = 20;
Contact.prototype.remove = function(successCB, errorCB) { Contact.prototype.remove = function(successCB, errorCB) {
if (this.id === null) { if (this.id === null) {
var errorObj = new ContactError(); var errorObj = new ContactError();
errorObj.code = ContactError.NOT_FOUND_ERROR; errorObj.code = ContactError.UNKNOWN_ERROR;
errorCB(errorObj); errorCB(errorObj);
} }
else { else {
@@ -197,8 +190,10 @@ var ContactField = function(type, value, pref) {
* @param postalCode * @param postalCode
* @param country * @param country
*/ */
var ContactAddress = function(formatted, streetAddress, locality, region, postalCode, country) { var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
this.id = null; this.id = null;
this.pref = pref || null;
this.type = type || null;
this.formatted = formatted || null; this.formatted = formatted || null;
this.streetAddress = streetAddress || null; this.streetAddress = streetAddress || null;
this.locality = locality || null; this.locality = locality || null;
@@ -219,8 +214,10 @@ var ContactAddress = function(formatted, streetAddress, locality, region, postal
* @param location * @param location
* @param desc * @param desc
*/ */
var ContactOrganization = function(name, dept, title) { var ContactOrganization = function(pref, type, name, dept, title) {
this.id = null; this.id = null;
this.pref = pref || null;
this.type = type || null;
this.name = name || null; this.name = name || null;
this.department = dept || null; this.department = dept || null;
this.title = title || null; this.title = title || null;
@@ -243,7 +240,16 @@ var Contacts = function() {
* @return array of Contacts matching search criteria * @return array of Contacts matching search criteria
*/ */
Contacts.prototype.find = function(fields, successCB, errorCB, options) { Contacts.prototype.find = function(fields, successCB, errorCB, options) {
PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]); if (successCB === null) {
throw new TypeError("You must specify a success callback for the find command.");
}
if (fields === null || fields === "undefined" || fields.length === "undefined" || fields.length <= 0) {
if (typeof errorCB === "function") {
errorCB({"code": ContactError.INVALID_ARGUMENT_ERROR});
}
} else {
PhoneGap.exec(successCB, errorCB, "Contacts", "search", [fields, options]);
}
}; };
/** /**
@@ -267,7 +273,7 @@ Contacts.prototype.create = function(properties) {
/** /**
* This function returns and array of contacts. It is required as we need to convert raw * 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 * JSON objects into concrete Contact objects. Currently this method is called after
* navigator.service.contacts.find but before the find methods success call back. * navigator.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. * @param jsonArray an array of JSON Objects that need to be converted to Contact objects.
* @returns an array of Contact objects * @returns an array of Contact objects
@@ -276,7 +282,7 @@ Contacts.prototype.cast = function(pluginResult) {
var contacts = []; var contacts = [];
var i; var i;
for (i=0; i<pluginResult.message.length; i++) { for (i=0; i<pluginResult.message.length; i++) {
contacts.push(navigator.service.contacts.create(pluginResult.message[i])); contacts.push(navigator.contacts.create(pluginResult.message[i]));
} }
pluginResult.message = contacts; pluginResult.message = contacts;
return pluginResult; return pluginResult;
@@ -287,23 +293,18 @@ Contacts.prototype.cast = function(pluginResult) {
* @constructor * @constructor
* @param filter used to match contacts against * @param filter used to match contacts against
* @param multiple boolean used to determine if more than one contact should be returned * @param multiple boolean used to determine if more than one contact should be returned
* @param updatedSince return only contact records that have been updated on or after the given time
*/ */
var ContactFindOptions = function(filter, multiple, updatedSince) { var ContactFindOptions = function(filter, multiple) {
this.filter = filter || ''; this.filter = filter || '';
this.multiple = multiple || true; this.multiple = multiple || false;
this.updatedSince = updatedSince || '';
}; };
/** /**
* Add the contact interface into the browser. * Add the contact interface into the browser.
*/ */
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
if(typeof navigator.service === "undefined") { if(typeof navigator.contacts === "undefined") {
navigator.service = {}; navigator.contacts = new Contacts();
}
if(typeof navigator.service.contacts === "undefined") {
navigator.service.contacts = new Contacts();
} }
}); });
} }
+2 -6
View File
@@ -92,10 +92,6 @@ FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback) {
return PhoneGap.exec(successCallback, errorCallback, "File", "getFreeDiskSpace", []); return PhoneGap.exec(successCallback, errorCallback, "File", "getFreeDiskSpace", []);
}; };
FileMgr.prototype.writeAsText = function(fileName, data, append, successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "writeAsText", [fileName, data, append]);
};
FileMgr.prototype.write = function(fileName, data, position, successCallback, errorCallback) { FileMgr.prototype.write = function(fileName, data, position, successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "write", [fileName, data, position]); PhoneGap.exec(successCallback, errorCallback, "File", "write", [fileName, data, position]);
}; };
@@ -176,7 +172,7 @@ FileReader.prototype.abort = function() {
} }
// If abort callback // If abort callback
if (typeof this.onabort === "function") { if (typeof this.onabort === "function") {
this.oneabort({"type":"abort", "target":this}); this.onabort({"type":"abort", "target":this});
} }
// If load end callback // If load end callback
if (typeof this.onloadend === "function") { if (typeof this.onloadend === "function") {
@@ -435,7 +431,7 @@ FileWriter.prototype.abort = function() {
} }
// If abort callback // If abort callback
if (typeof this.onabort === "function") { if (typeof this.onabort === "function") {
this.oneabort({"type":"abort", "target":this}); this.onabort({"type":"abort", "target":this});
} }
this.readyState = FileWriter.DONE; this.readyState = FileWriter.DONE;
+4 -1
View File
@@ -63,6 +63,7 @@ var Media = function(src, successCallback, errorCallback, statusCallback, positi
// Media messages // Media messages
Media.MEDIA_STATE = 1; Media.MEDIA_STATE = 1;
Media.MEDIA_DURATION = 2; Media.MEDIA_DURATION = 2;
Media.MEDIA_POSITION = 3;
Media.MEDIA_ERROR = 9; Media.MEDIA_ERROR = 9;
// Media states // Media states
@@ -187,7 +188,6 @@ PhoneGap.Media.getMediaObject = function(id) {
*/ */
PhoneGap.Media.onStatus = function(id, msg, value) { PhoneGap.Media.onStatus = function(id, msg, value) {
var media = PhoneGap.mediaObjects[id]; var media = PhoneGap.mediaObjects[id];
// If state update // If state update
if (msg === Media.MEDIA_STATE) { if (msg === Media.MEDIA_STATE) {
if (value === Media.MEDIA_STOPPED) { if (value === Media.MEDIA_STOPPED) {
@@ -207,5 +207,8 @@ PhoneGap.Media.onStatus = function(id, msg, value) {
media.errorCallback(value); media.errorCallback(value);
} }
} }
else if (msg == Media.MEDIA_POSITION) {
media._position = value;
}
}; };
} }
+1 -51
View File
@@ -9,56 +9,6 @@
if (!PhoneGap.hasResource("network")) { if (!PhoneGap.hasResource("network")) {
PhoneGap.addResource("network"); PhoneGap.addResource("network");
/**
* This class contains information about any NetworkStatus.
* @constructor
*/
var NetworkStatus = function() {
//this.code = null;
//this.message = "";
};
NetworkStatus.NOT_REACHABLE = 0;
NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
/**
* This class provides access to device Network data (reachability).
* @constructor
*/
var Network = function() {
/**
* The last known Network status.
* { hostName: string, ipAddress: string,
remoteHostStatus: int(0/1/2), internetConnectionStatus: int(0/1/2), localWiFiConnectionStatus: int (0/2) }
*/
this.lastReachability = null;
};
/**
* Called by the geolocation framework when the reachability status has changed.
* @param {Reachibility} reachability The current reachability status.
*/
// TODO: Callback from native code not implemented for Android
Network.prototype.updateReachability = function(reachability) {
this.lastReachability = reachability;
};
/**
* Determine if a URI is reachable over the network.
* @param {Object} uri
* @param {Function} callback
* @param {Object} options (isIpAddress:boolean)
*/
Network.prototype.isReachable = function(uri, callback, options) {
var isIpAddress = false;
if (options && options.isIpAddress) {
isIpAddress = options.isIpAddress;
}
PhoneGap.exec(callback, null, "Network Status", "isReachable", [uri, isIpAddress]);
};
/** /**
* This class contains information about the current network Connection. * This class contains information about the current network Connection.
* @constructor * @constructor
@@ -123,7 +73,7 @@ Connection.prototype.getInfo = function(successCallback, errorCallback) {
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
if (typeof navigator.network === "undefined") { if (typeof navigator.network === "undefined") {
navigator.network = new Network(); navigator.network = new Object();
} }
if (typeof navigator.network.connection === "undefined") { if (typeof navigator.network.connection === "undefined") {
navigator.network.connection = new Connection(); navigator.network.connection = new Connection();
-20
View File
@@ -365,10 +365,6 @@ PhoneGap.Channel.join(function() {
// Fire onDeviceReady event once all constructors have run and PhoneGap info has been // Fire onDeviceReady event once all constructors have run and PhoneGap info has been
// received from native side, and any user defined initialization channels. // received from native side, and any user defined initialization channels.
PhoneGap.Channel.join(function() { PhoneGap.Channel.join(function() {
// Turn off app loading dialog
navigator.notification.activityStop();
PhoneGap.onDeviceReady.fire(); PhoneGap.onDeviceReady.fire();
// Fire the onresume event, since first one happens before JavaScript is loaded // Fire the onresume event, since first one happens before JavaScript is loaded
@@ -928,20 +924,4 @@ PhoneGap.includeJavascript = function(jsfile, successCallback) {
id.appendChild(el); 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);
}
}
};
} }
+1 -1
View File
@@ -1,7 +1,7 @@
<html> <html>
<head> <head>
<title></title> <title></title>
<script src="phonegap.0.9.6.1.min.js"></script> <script src="phonegap-1.0.0.js"></script>
</head> </head>
<body> <body>
+40 -73
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project name="PhoneGap" default="help"> <project name="PhoneGap" default="jar">
<!-- LOAD VERSION --> <!-- LOAD VERSION -->
<loadfile property="version" srcFile="../VERSION"> <loadfile property="version" srcFile="../VERSION">
@@ -40,6 +40,9 @@
This file is an integral part of the build system for your application and This file is an integral part of the build system for your application and
should be checked in in Version Control Systems. --> should be checked in in Version Control Systems. -->
<property file="default.properties" /> <property file="default.properties" />
<!-- We need to setup the double quote. -->
<property name="dblQuote">"</property>
<!-- Custom Android task to deal with the project target, and import the proper rules. <!-- Custom Android task to deal with the project target, and import the proper rules.
This requires ant 1.6.0 or above. --> This requires ant 1.6.0 or above. -->
@@ -71,88 +74,57 @@
--> -->
<setup /> <setup />
<target name="check-javascript" depends="build-javascript"> <target name="check-javascript" depends="build-javascript">
<delete dir="assets/lib"/> <delete dir="assets/lib"/>
<mkdir dir="assets/lib"/> <mkdir dir="assets/lib"/>
<echo file="assets/lib/lint.js">var alert=function(){},device={},Element={},debug={};</echo> <echo file="assets/lib/lint.js">var alert=function(){},device={},Element={},debug={};</echo>
<concat destfile="assets/lib/phonegap-lint.js" append="true"> <concat destfile="assets/lib/phonegap-lint.js" append="true">
<fileset dir="assets/lib"> <fileset dir="assets/lib">
<include name="lint.js" /> <include name="lint.js" />
</fileset> </fileset>
<fileset dir="assets/www"> <fileset dir="assets/www">
<include name="phonegap.${version}.js" /> <include name="phonegap-${version}.js" />
</fileset> </fileset>
</concat> </concat>
<exec executable="cmd" os="Windows 7"> <exec executable="cmd" os="Windows 7">
<arg value="/c"/> <arg value="/c"/>
<arg value="java"/> <arg value="java"/>
<arg value="-cp"/> <arg value="-cp"/>
<arg value="${basedir}/util/js.jar"/> <arg value="${basedir}/util/js.jar"/>
<arg value="org.mozilla.javascript.tools.shell.Main"/> <arg value="org.mozilla.javascript.tools.shell.Main"/>
<arg value="${basedir}/util/jslint.js"/> <arg value="${basedir}/util/jslint.js"/>
<arg value="${basedir}/js/lib/phonegap-lint.js"/> <arg value="${basedir}/js/lib/phonegap-lint.js"/>
</exec> </exec>
<exec executable="java" os="Mac OS X"> <exec executable="java" os="Mac OS X">
<arg value="-cp"/> <arg value="-cp"/>
<arg value="../util/js.jar"/> <arg value="../util/js.jar"/>
<arg value="org.mozilla.javascript.tools.shell.Main"/> <arg value="org.mozilla.javascript.tools.shell.Main"/>
<arg value="../util/jslint.js"/> <arg value="../util/jslint.js"/>
<arg value="assets/lib/phonegap-lint.js"/> <arg value="assets/lib/phonegap-lint.js"/>
</exec> </exec>
</target>
<!-- 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> </target>
<!-- Combine JavaScript files into one phonegap-uncompressed.js file. <!-- Combine JavaScript files into one phonegap-uncompressed.js file. -->
Compress this file using yuicompressor to create phonegap.js. -->
<target name="build-javascript"> <target name="build-javascript">
<!-- Clean up existing files --> <!-- 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"/> <delete file="assets/www/phonegap_${version}.js"/>
<!-- Create uncompressed JS file --> <!-- Create uncompressed JS file -->
<concat destfile="assets/www/phonegap.${version}.js"> <concat destfile="assets/www/phonegap-${version}.js">
<fileset dir="assets/js" includes="phonegap.js.base" /> <fileset dir="assets/js" includes="phonegap.js.base" />
<fileset dir="assets/js" includes="*.js" /> <fileset dir="assets/js" includes="*.js" />
</concat> </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 --> <!-- update project files to reference phonegap-x.x.x.min.js -->
<replaceregexp match="phonegap(.*)\.js" replace="phonegap.${version}.min.js" byline="true"> <replaceregexp match="phonegap(.*)\.js" replace="phonegap-${version}.js" byline="true">
<fileset file="assets/www/index.html" /> <fileset file="assets/www/index.html" />
<fileset file="../example/index.html" /> <fileset file="../example/index.html" />
</replaceregexp> </replaceregexp>
<replaceregexp match="phonegapVersion = [\u0022].*[\u0022];" replace="phonegapVersion = ${dblQuote}${version}${dblQuote};" byline="true">
<fileset file="src/com/phonegap/Device.java" />
</replaceregexp>
<!-- Delete temp file --> <!-- Delete temp file -->
<delete file="assets/www/phonegap-tmp.js"/> <delete file="assets/www/phonegap-tmp.js"/>
@@ -160,14 +132,9 @@
<!-- Build PhoneGap jar file that includes all native code, and PhoneGap JS file <!-- Build PhoneGap jar file that includes all native code, and PhoneGap JS file
that includes all JavaScript code. 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"> <target name="jar" depends="build-javascript, compile">
<jar jarfile="phonegap.${version}.jar" basedir="bin/classes" excludes="com/phonegap/R.class,com/phonegap/R$*.class"/> <jar jarfile="phonegap-${version}.jar" basedir="bin/classes" excludes="com/phonegap/R.class,com/phonegap/R$*.class"/>
</target> </target>
<target name="phonegap_debug" depends="build-javascript, debug"> <target name="phonegap_debug" depends="build-javascript, debug">
Executable → Regular
+1 -2
View File
@@ -1,4 +1,4 @@
<!--?xml version="1.0" encoding="utf-8"?--> <?xml version="1.0" encoding="utf-8"?>
<plugins> <plugins>
<plugin name="App" value="com.phonegap.App"/> <plugin name="App" value="com.phonegap.App"/>
<plugin name="Geolocation" value="com.phonegap.GeoBroker"/> <plugin name="Geolocation" value="com.phonegap.GeoBroker"/>
@@ -10,7 +10,6 @@
<plugin name="Contacts" value="com.phonegap.ContactManager"/> <plugin name="Contacts" value="com.phonegap.ContactManager"/>
<plugin name="Crypto" value="com.phonegap.CryptoHandler"/> <plugin name="Crypto" value="com.phonegap.CryptoHandler"/>
<plugin name="File" value="com.phonegap.FileUtils"/> <plugin name="File" value="com.phonegap.FileUtils"/>
<plugin name="Location" value="com.phonegap.GeoBroker"/>
<plugin name="Network Status" value="com.phonegap.NetworkManager"/> <plugin name="Network Status" value="com.phonegap.NetworkManager"/>
<plugin name="Notification" value="com.phonegap.Notification"/> <plugin name="Notification" value="com.phonegap.Notification"/>
<plugin name="Storage" value="com.phonegap.Storage"/> <plugin name="Storage" value="com.phonegap.Storage"/>
-13
View File
@@ -43,9 +43,6 @@ public class App extends Plugin {
} }
else if (action.equals("clearHistory")) { else if (action.equals("clearHistory")) {
this.clearHistory(); this.clearHistory();
}
else if (action.equals("addService")) {
this.addService(args.getString(0), args.getString(1));
} }
else if (action.equals("overrideBackbutton")) { else if (action.equals("overrideBackbutton")) {
this.overrideBackbutton(args.getBoolean(0)); this.overrideBackbutton(args.getBoolean(0));
@@ -148,16 +145,6 @@ public class App extends Plugin {
((DroidGap)this.ctx).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. * Override the default behavior of the Android back button.
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+19 -12
View File
@@ -11,11 +11,12 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaRecorder;
import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener; import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaRecorder;
import android.os.Environment; import android.os.Environment;
import android.util.Log;
/** /**
* This class implements the audio playback and recording capabilities used by PhoneGap. * This class implements the audio playback and recording capabilities used by PhoneGap.
@@ -28,7 +29,9 @@ import android.os.Environment;
*/ */
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener { public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
// AudioPlayer states private static final String LOG_TAG = "AudioPlayer";
// AudioPlayer states
private static int MEDIA_NONE = 0; private static int MEDIA_NONE = 0;
private static int MEDIA_STARTING = 1; private static int MEDIA_STARTING = 1;
private static int MEDIA_RUNNING = 2; private static int MEDIA_RUNNING = 2;
@@ -38,6 +41,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
// AudioPlayer message ids // AudioPlayer message ids
private static int MEDIA_STATE = 1; private static int MEDIA_STATE = 1;
private static int MEDIA_DURATION = 2; private static int MEDIA_DURATION = 2;
private static int MEDIA_POSITION = 3;
private static int MEDIA_ERROR = 9; private static int MEDIA_ERROR = 9;
// AudioPlayer error codes // AudioPlayer error codes
@@ -99,7 +103,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/ */
public void startRecording(String file) { public void startRecording(String file) {
if (this.mPlayer != null) { if (this.mPlayer != null) {
System.out.println("AudioPlayer Error: Can't record in play mode."); Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PLAY_MODE_SET+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PLAY_MODE_SET+");");
} }
@@ -124,7 +128,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_RECORDING+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_RECORDING+");");
} }
else { else {
System.out.println("AudioPlayer Error: Already recording."); Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_ALREADY_RECORDING+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_ALREADY_RECORDING+");");
} }
} }
@@ -166,7 +170,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/ */
public void startPlaying(String file) { public void startPlaying(String file) {
if (this.recorder != null) { if (this.recorder != null) {
System.out.println("AudioPlayer Error: Can't play in record mode."); Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RECORD_MODE_SET+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RECORD_MODE_SET+");");
} }
@@ -225,7 +229,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_RUNNING); this.setState(MEDIA_RUNNING);
} }
else { else {
System.out.println("AudioPlayer Error: startPlaying() called during invalid state: "+this.state); Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RESUME_STATE+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RESUME_STATE+");");
} }
} }
@@ -237,6 +241,8 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void seekToPlaying(int milliseconds) { public void seekToPlaying(int milliseconds) {
if (this.mPlayer != null) { if (this.mPlayer != null) {
this.mPlayer.seekTo(milliseconds); this.mPlayer.seekTo(milliseconds);
Log.d(LOG_TAG, "Send a onStatus update for the new seek");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+milliseconds/1000.0f+");");
} }
} }
@@ -251,7 +257,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_PAUSED); this.setState(MEDIA_PAUSED);
} }
else { else {
System.out.println("AudioPlayer Error: pausePlaying() called during invalid state: "+this.state); Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PAUSE_STATE+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PAUSE_STATE+");");
} }
} }
@@ -265,7 +271,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_STOPPED); this.setState(MEDIA_STOPPED);
} }
else { else {
System.out.println("AudioPlayer Error: stopPlaying() called during invalid state: "+this.state); Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STOP_STATE+");"); this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STOP_STATE+");");
} }
} }
@@ -286,7 +292,9 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/ */
public long getCurrentPosition() { public long getCurrentPosition() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
return this.mPlayer.getCurrentPosition(); int curPos = this.mPlayer.getCurrentPosition();
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");");
return curPos;
} }
else { else {
return -1; return -1;
@@ -386,7 +394,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @param arg2 an extra code, specific to the error. * @param arg2 an extra code, specific to the error.
*/ */
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) { public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
System.out.println("AudioPlayer.onError(" + arg1 + ", " + arg2+")"); Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
// TODO: Not sure if this needs to be sent? // TODO: Not sure if this needs to be sent?
this.mPlayer.stop(); this.mPlayer.stop();
@@ -409,5 +417,4 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = state; this.state = state;
} }
} }
+83 -7
View File
@@ -26,8 +26,7 @@ import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat; import android.graphics.Bitmap.CompressFormat;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.util.Log;
import android.provider.MediaStore;
/** /**
* This class launches the camera view, allows the user to take a picture, closes the camera view, * This class launches the camera view, allows the user to take a picture, closes the camera view,
@@ -43,7 +42,12 @@ public class CameraLauncher extends Plugin {
private static final int CAMERA = 1; // Take picture from camera private static final int CAMERA = 1; // Take picture from camera
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android) private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
private static final int JPEG = 0; // Take a picture of type JPEG
private static final int PNG = 1; // Take a picture of type PNG
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private int targetWidth; // desired width of the image
private int targetHeight; // desired height of the image
private Uri imageUri; // Uri of captured image private Uri imageUri; // Uri of captured image
public String callbackId; public String callbackId;
@@ -76,8 +80,18 @@ public class CameraLauncher extends Plugin {
if (args.length() > 2) { if (args.length() > 2) {
srcType = args.getInt(2); srcType = args.getInt(2);
} }
if (args.length() > 3) {
this.targetWidth = args.getInt(3);
}
if (args.length() > 4) {
this.targetHeight = args.getInt(4);
}
int encodingType = JPEG;
if (args.length() > 5) {
encodingType = args.getInt(5);
}
if (srcType == CAMERA) { if (srcType == CAMERA) {
this.takePicture(args.getInt(0), destType); this.takePicture(args.getInt(0), destType, encodingType);
} }
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
this.getImage(args.getInt(0), srcType, destType); this.getImage(args.getInt(0), srcType, destType);
@@ -111,7 +125,7 @@ public class CameraLauncher extends Plugin {
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param returnType Set the type of image to return. * @param returnType Set the type of image to return.
*/ */
public void takePicture(int quality, int returnType) { public void takePicture(int quality, int returnType, int encodingType) {
this.mQuality = quality; this.mQuality = quality;
// Display camera // Display camera
@@ -119,14 +133,30 @@ public class CameraLauncher extends Plugin {
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
// TODO: What if there isn't any external storage? // TODO: What if there isn't any external storage?
File photo = new File(Environment.getExternalStorageDirectory(), "Pic.jpg"); File photo = createCaptureFile(encodingType);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo); this.imageUri = Uri.fromFile(photo);
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1); this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
} }
/** /**
* Create a file in the applications temporary directory based upon the supplied encoding.
*
* @param encodingType of the image to be taken
* @return a File object pointing to the temporary picture
*/
private File createCaptureFile(int encodingType) {
File photo = null;
if (encodingType == JPEG) {
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.jpg");
} else {
photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.png");
}
return photo;
}
/**
* Get image from photo library. * Get image from photo library.
* *
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
@@ -145,6 +175,50 @@ public class CameraLauncher extends Plugin {
new String("Get Picture")), (srcType+1)*16 + returnType + 1); new String("Get Picture")), (srcType+1)*16 + returnType + 1);
} }
/**
* Scales the bitmap according to the requested size.
*
* @param bitmap The bitmap to scale.
* @return Bitmap A new Bitmap object of the same bitmap after scaling.
*/
public Bitmap scaleBitmap(Bitmap bitmap) {
int newWidth = this.targetWidth;
int newHeight = this.targetHeight;
int origWidth = bitmap.getWidth();
int origHeight = bitmap.getHeight();
// If no new width or height were specified return the original bitmap
if (newWidth <= 0 && newHeight <= 0) {
return bitmap;
}
// Only the width was specified
else if (newWidth > 0 && newHeight <= 0) {
newHeight = (newWidth * origHeight) / origWidth;
}
// only the height was specified
else if (newWidth <= 0 && newHeight > 0) {
newWidth = (newHeight * origWidth) / origHeight;
}
// If the user specified both a positive width and height
// (potentially different aspect ratio) then the width or height is
// scaled so that the image fits while maintaining aspect ratio.
// Alternatively, the specified width and height could have been
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
// would result in whitespace in the new image.
else {
double newRatio = newWidth / (double)newHeight;
double origRatio = origWidth / (double)origHeight;
if (origRatio > newRatio) {
newHeight = (newWidth * origHeight) / origWidth;
} else if (origRatio < newRatio) {
newWidth = (newHeight * origWidth) / origHeight;
}
}
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
}
/** /**
* Called when the camera view exits. * Called when the camera view exits.
* *
@@ -161,7 +235,6 @@ public class CameraLauncher extends Plugin {
// If CAMERA // If CAMERA
if (srcType == CAMERA) { if (srcType == CAMERA) {
// If image available // If image available
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
try { try {
@@ -175,6 +248,8 @@ public class CameraLauncher extends Plugin {
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
} }
bitmap = scaleBitmap(bitmap);
// If sending base64 image back // If sending base64 image back
if (destType == DATA_URL) { if (destType == DATA_URL) {
this.processPicture(bitmap); this.processPicture(bitmap);
@@ -237,6 +312,7 @@ public class CameraLauncher extends Plugin {
if (destType == DATA_URL) { if (destType == DATA_URL) {
try { try {
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
bitmap = scaleBitmap(bitmap);
this.processPicture(bitmap); this.processPicture(bitmap);
bitmap.recycle(); bitmap.recycle();
bitmap = null; bitmap = null;
+8 -2
View File
@@ -95,7 +95,13 @@ public class Capture extends Plugin {
obj.put("duration", 0); obj.put("duration", 0);
obj.put("codecs", ""); obj.put("codecs", "");
if (mimeType.equals("image/jpeg")) { // If the mimeType isn't set the rest will fail
// so let's see if we can determine it.
if (mimeType == null || mimeType.equals("")) {
mimeType = FileUtils.getMimeType(filePath);
}
if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) {
obj = getImageData(filePath, obj); obj = getImageData(filePath, obj);
} }
else if (filePath.endsWith("audio/3gpp")) { else if (filePath.endsWith("audio/3gpp")) {
@@ -168,7 +174,7 @@ public class Capture extends Plugin {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
File photo = new File(Environment.getExternalStorageDirectory(), "Capture.jpg"); File photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Capture.jpg");
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo); this.imageUri = Uri.fromFile(photo);
+66 -91
View File
@@ -24,7 +24,6 @@
package com.phonegap; package com.phonegap;
import java.lang.reflect.Constructor;
import java.util.HashMap; import java.util.HashMap;
import android.app.Activity; import android.app.Activity;
@@ -44,53 +43,9 @@ import org.json.JSONObject;
*/ */
public abstract class ContactAccessor { public abstract class ContactAccessor {
/**
* Static singleton instance of {@link ContactAccessor} holding the
* SDK-specific implementation of the class.
*/
private static ContactAccessor sInstance;
protected final String LOG_TAG = "ContactsAccessor"; protected final String LOG_TAG = "ContactsAccessor";
protected Activity mApp; protected Activity mApp;
protected WebView mView; protected WebView mView;
public static ContactAccessor getInstance(WebView view, Activity app) {
if (sInstance == null) {
String className;
/*
* Check the version of the SDK we are running on. Choose an
* implementation class designed for that version of the SDK.
*
* Unfortunately we have to use strings to represent the class
* names. If we used the conventional ContactAccessorSdk5.class.getName()
* syntax, we would get a ClassNotFoundException at runtime on pre-Eclair SDKs.
* Using the above syntax would force Dalvik to load the class and try to
* resolve references to all other classes it uses. Since the pre-Eclair
* does not have those classes, the loading of ContactAccessorSdk5 would fail.
*/
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
className = "com.phonegap.ContactAccessorSdk3_4";
} else {
className = "com.phonegap.ContactAccessorSdk5";
}
/*
* Find the required class by name and instantiate it.
*/
try {
Class<? extends ContactAccessor> clazz =
Class.forName(className).asSubclass(ContactAccessor.class);
// Grab constructor for contactsmanager class dynamically.
Constructor<? extends ContactAccessor> classConstructor = clazz.getConstructor(Class.forName("android.webkit.WebView"), Class.forName("android.app.Activity"));
sInstance = classConstructor.newInstance(view, app);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return sInstance;
}
/** /**
* Check to see if the data associated with the key is required to * Check to see if the data associated with the key is required to
@@ -114,51 +69,65 @@ public abstract class ContactAccessor {
String key; String key;
try { try {
for (int i=0; i<fields.length(); i++) { if (fields.length() == 1 && fields.getString(0).equals("*")) {
key = fields.getString(i); map.put("displayName", true);
if (key.startsWith("displayName")) { map.put("name", true);
map.put("displayName", true); map.put("nickname", true);
} map.put("phoneNumbers", true);
else if (key.startsWith("name")) { map.put("emails", true);
map.put("name", true); map.put("addresses", true);
} map.put("ims", true);
else if (key.startsWith("nickname")) { map.put("organizations", true);
map.put("nickname", true); map.put("birthday", true);
} map.put("note", true);
else if (key.startsWith("phoneNumbers")) { map.put("urls", true);
map.put("phoneNumbers", true); map.put("photos", true);
} map.put("categories", true);
else if (key.startsWith("emails")) { }
map.put("emails", true); else {
} for (int i=0; i<fields.length(); i++) {
else if (key.startsWith("addresses")) { key = fields.getString(i);
map.put("addresses", true); if (key.startsWith("displayName")) {
} map.put("displayName", true);
else if (key.startsWith("ims")) { }
map.put("ims", true); else if (key.startsWith("name")) {
} map.put("name", true);
else if (key.startsWith("organizations")) { }
map.put("organizations", true); else if (key.startsWith("nickname")) {
} map.put("nickname", true);
else if (key.startsWith("birthday")) { }
map.put("birthday", true); else if (key.startsWith("phoneNumbers")) {
} map.put("phoneNumbers", true);
else if (key.startsWith("anniversary")) { }
map.put("anniversary", true); else if (key.startsWith("emails")) {
} map.put("emails", true);
else if (key.startsWith("note")) { }
map.put("note", true); else if (key.startsWith("addresses")) {
} map.put("addresses", true);
else if (key.startsWith("relationships")) { }
map.put("relationships", true); else if (key.startsWith("ims")) {
} map.put("ims", true);
else if (key.startsWith("urls")) { }
map.put("urls", true); else if (key.startsWith("organizations")) {
} map.put("organizations", true);
else if (key.startsWith("photos")) { }
map.put("photos", true); else if (key.startsWith("birthday")) {
} map.put("birthday", true);
} }
else if (key.startsWith("note")) {
map.put("note", true);
}
else if (key.startsWith("urls")) {
map.put("urls", true);
}
else if (key.startsWith("photos")) {
map.put("photos", true);
}
else if (key.startsWith("categories")) {
map.put("categories", true);
}
}
}
} }
catch (JSONException e) { catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
@@ -196,13 +165,19 @@ public abstract class ContactAccessor {
* Handles adding a JSON Contact object into the database. * Handles adding a JSON Contact object into the database.
* @return TODO * @return TODO
*/ */
public abstract boolean save(JSONObject contact); public abstract String save(JSONObject contact);
/** /**
* Handles searching through SDK-specific contacts API. * Handles searching through SDK-specific contacts API.
*/ */
public abstract JSONArray search(JSONArray filter, JSONObject options); public abstract JSONArray search(JSONArray filter, JSONObject options);
/**
* Handles searching through SDK-specific contacts API.
* @throws JSONException
*/
public abstract JSONObject getContactById(String id) throws JSONException;
/** /**
* Handles removing a contact from the database. * Handles removing a contact from the database.
*/ */
@@ -1,827 +0,0 @@
// Taken from Android tutorials
/*
* 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) 2009 The Android Open Source Project
*
* Licensed 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.
*/
package com.phonegap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
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;
import android.provider.Contacts.ContactMethods;
import android.provider.Contacts.ContactMethodsColumns;
import android.provider.Contacts.Organizations;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.util.Log;
import android.webkit.WebView;
/**
* An implementation of {@link ContactAccessor} that uses legacy Contacts API.
* These APIs are deprecated and should not be used unless we are running on a
* pre-Eclair SDK.
* <p>
* There are several reasons why we wouldn't want to use this class on an Eclair device:
* <ul>
* <li>It would see at most one account, namely the first Google account created on the device.
* <li>It would work through a compatibility layer, which would make it inherently less efficient.
* <li>Not relevant to this particular example, but it would not have access to new kinds
* of data available through current APIs.
* </ul>
*/
@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.
*/
private static final Map<String, String> dbMap = new HashMap<String, String>();
static {
dbMap.put("id", People._ID);
dbMap.put("displayName", People.DISPLAY_NAME);
dbMap.put("phoneNumbers", Phones.NUMBER);
dbMap.put("phoneNumbers.value", Phones.NUMBER);
dbMap.put("emails", ContactMethods.DATA);
dbMap.put("emails.value", ContactMethods.DATA);
dbMap.put("addresses", ContactMethodsColumns.DATA);
dbMap.put("addresses.formatted", ContactMethodsColumns.DATA);
dbMap.put("ims", ContactMethodsColumns.DATA);
dbMap.put("ims.value", ContactMethodsColumns.DATA);
dbMap.put("organizations", Organizations.COMPANY);
dbMap.put("organizations.name", Organizations.COMPANY);
dbMap.put("organizations.title", Organizations.TITLE);
dbMap.put("note", People.NOTES);
}
/**
* Create an contact accessor.
*/
public ContactAccessorSdk3_4(WebView view, Activity app)
{
mApp = app;
mView = view;
}
@Override
/**
* This method takes the fields required and search options in order to produce an
* array of contacts that matches the criteria provided.
* @param fields an array of items to be used as search criteria
* @param options that can be applied to contact searching
* @return an array of contacts
*/
public JSONArray search(JSONArray fields, JSONObject options) {
String searchTerm = "";
int limit = Integer.MAX_VALUE;
boolean multiple = true;
if (options != null) {
searchTerm = options.optString("filter");
if (searchTerm.length()==0) {
searchTerm = "%";
}
else {
searchTerm = "%" + searchTerm + "%";
}
try {
multiple = options.getBoolean("multiple");
if (!multiple) {
limit = 1;
}
} catch (JSONException e) {
// Multiple was not specified so we assume the default is true.
}
}
else {
searchTerm = "%";
}
ContentResolver cr = mApp.getContentResolver();
Set<String> contactIds = buildSetOfContactIds(fields, searchTerm);
HashMap<String,Boolean> populate = buildPopulationSet(fields);
Iterator<String> it = contactIds.iterator();
JSONArray contacts = new JSONArray();
JSONObject contact;
String contactId;
int pos = 0;
while (it.hasNext() && (pos < limit)) {
contact = new JSONObject();
try {
contactId = it.next();
contact.put("id", contactId);
// Do query for name and note
Cursor cur = cr.query(People.CONTENT_URI,
new String[] {People.DISPLAY_NAME, People.NOTES},
PEOPLE_ID_EQUALS,
new String[] {contactId},
null);
cur.moveToFirst();
if (isRequired("displayName",populate)) {
contact.put("displayName", cur.getString(cur.getColumnIndex(People.DISPLAY_NAME)));
}
if (isRequired("phoneNumbers",populate)) {
contact.put("phoneNumbers", phoneQuery(cr, contactId));
}
if (isRequired("emails",populate)) {
contact.put("emails", emailQuery(cr, contactId));
}
if (isRequired("addresses",populate)) {
contact.put("addresses", addressQuery(cr, contactId));
}
if (isRequired("organizations",populate)) {
contact.put("organizations", organizationQuery(cr, contactId));
}
if (isRequired("ims",populate)) {
contact.put("ims", imQuery(cr, contactId));
}
if (isRequired("note",populate)) {
contact.put("note", cur.getString(cur.getColumnIndex(People.NOTES)));
}
// nickname
// urls
// relationship
// birthdays
// anniversary
pos++;
cur.close();
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
contacts.put(contact);
}
return contacts;
}
/**
* Query the database using the search term to build up a list of contact ID's
* matching the search term
* @param fields
* @param searchTerm
* @return a set of contact ID's
*/
private Set<String> buildSetOfContactIds(JSONArray fields, String searchTerm) {
Set<String> contactIds = new HashSet<String>();
String key;
try {
for (int i=0; i<fields.length(); i++) {
key = fields.getString(i);
if (key.startsWith("displayName")) {
doQuery(searchTerm, contactIds,
People.CONTENT_URI,
People._ID,
dbMap.get(key) + " LIKE ?",
new String[] {searchTerm});
}
// else if (key.startsWith("name")) {
// Log.d(LOG_TAG, "Doing " + key + " query");
// doQuery(searchTerm, contactIds,
// ContactsContract.Data.CONTENT_URI,
// ContactsContract.Data.CONTACT_ID,
// dbMap.get(key) + " LIKE ? AND " + ContactsContract.Data.MIMETYPE + " = ?",
// new String[] {searchTerm, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE});
// }
else if (key.startsWith("phoneNumbers")) {
doQuery(searchTerm, contactIds,
Phones.CONTENT_URI,
Phones.PERSON_ID,
dbMap.get(key) + " LIKE ?",
new String[] {searchTerm});
}
else if (key.startsWith("emails")) {
doQuery(searchTerm, contactIds,
ContactMethods.CONTENT_EMAIL_URI,
ContactMethods.PERSON_ID,
dbMap.get(key) + " LIKE ? AND " + ContactMethods.KIND + " = ?",
new String[] {searchTerm, ContactMethods.CONTENT_EMAIL_ITEM_TYPE});
}
else if (key.startsWith("addresses")) {
doQuery(searchTerm, contactIds,
ContactMethods.CONTENT_URI,
ContactMethods.PERSON_ID,
dbMap.get(key) + " LIKE ? AND " + ContactMethods.KIND + " = ?",
new String[] {searchTerm, ContactMethods.CONTENT_POSTAL_ITEM_TYPE});
}
else if (key.startsWith("ims")) {
doQuery(searchTerm, contactIds,
ContactMethods.CONTENT_URI,
ContactMethods.PERSON_ID,
dbMap.get(key) + " LIKE ? AND " + ContactMethods.KIND + " = ?",
new String[] {searchTerm, ContactMethods.CONTENT_IM_ITEM_TYPE});
}
else if (key.startsWith("organizations")) {
doQuery(searchTerm, contactIds,
Organizations.CONTENT_URI,
ContactMethods.PERSON_ID,
dbMap.get(key) + " LIKE ?",
new String[] {searchTerm});
}
else if (key.startsWith("note")) {
doQuery(searchTerm, contactIds,
People.CONTENT_URI,
People._ID,
dbMap.get(key) + " LIKE ?",
new String[] {searchTerm});
}
}
}
catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
return contactIds;
}
/**
* A convenience method so we don't duplicate code in doQuery
* @param searchTerm
* @param contactIds
* @param uri
* @param projection
* @param selection
* @param selectionArgs
*/
private void doQuery(String searchTerm, Set<String> contactIds,
Uri uri, String projection, String selection, String[] selectionArgs) {
ContentResolver cr = mApp.getContentResolver();
Cursor cursor = cr.query(
uri,
null,
selection,
selectionArgs,
null);
while (cursor.moveToNext()) {
contactIds.add(cursor.getString(cursor.getColumnIndex(projection)));
}
cursor.close();
}
/**
* Create a ContactField JSONArray
* @param cr database access object
* @param contactId the ID to search the database for
* @return a JSONArray representing a set of ContactFields
*/
private JSONArray imQuery(ContentResolver cr, String contactId) {
String imWhere = ContactMethods.PERSON_ID
+ " = ? AND " + ContactMethods.KIND + " = ?";
String[] imWhereParams = new String[]{contactId, ContactMethods.CONTENT_IM_ITEM_TYPE};
Cursor cursor = cr.query(ContactMethods.CONTENT_URI,
null, imWhere, imWhereParams, null);
JSONArray ims = new JSONArray();
JSONObject im;
while (cursor.moveToNext()) {
im = new JSONObject();
try{
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", getContactType(cursor.getInt(
cursor.getColumnIndex(ContactMethodsColumns.TYPE))));
ims.put(im);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
}
cursor.close();
return null;
}
/**
* Create a ContactOrganization JSONArray
* @param cr database access object
* @param contactId the ID to search the database for
* @return a JSONArray representing a set of ContactOrganization
*/
private JSONArray organizationQuery(ContentResolver cr, String contactId) {
String orgWhere = ContactMethods.PERSON_ID + " = ?";
String[] orgWhereParams = new String[]{contactId};
Cursor cursor = cr.query(Organizations.CONTENT_URI,
null, orgWhere, orgWhereParams, null);
JSONArray organizations = new JSONArray();
JSONObject organization;
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)));
organizations.put(organization);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
}
return organizations;
}
/**
* Create a ContactAddress JSONArray
* @param cr database access object
* @param contactId the ID to search the database for
* @return a JSONArray representing a set of ContactAddress
*/
private JSONArray addressQuery(ContentResolver cr, String contactId) {
String addrWhere = ContactMethods.PERSON_ID
+ " = ? AND " + ContactMethods.KIND + " = ?";
String[] addrWhereParams = new String[]{contactId,
ContactMethods.CONTENT_POSTAL_ITEM_TYPE};
Cursor cursor = cr.query(ContactMethods.CONTENT_URI,
null, addrWhere, addrWhereParams, null);
JSONArray addresses = new JSONArray();
JSONObject address;
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) {
Log.e(LOG_TAG, e.getMessage(), e);
}
}
return addresses;
}
/**
* Create a ContactField JSONArray
* @param cr database access object
* @param contactId the ID to search the database for
* @return a JSONArray representing a set of ContactFields
*/
private JSONArray phoneQuery(ContentResolver cr, String contactId) {
Cursor cursor = cr.query(
Phones.CONTENT_URI,
null,
Phones.PERSON_ID +" = ?",
new String[]{contactId}, null);
JSONArray phones = new JSONArray();
JSONObject phone;
while (cursor.moveToNext()) {
phone = new JSONObject();
try{
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", getPhoneType(cursor.getInt(cursor.getColumnIndex(Phones.TYPE))));
phones.put(phone);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
}
return phones;
}
/**
* Create a ContactField JSONArray
* @param cr database access object
* @param contactId the ID to search the database for
* @return a JSONArray representing a set of ContactFields
*/
private JSONArray emailQuery(ContentResolver cr, String contactId) {
Cursor cursor = cr.query(
ContactMethods.CONTENT_EMAIL_URI,
null,
ContactMethods.PERSON_ID +" = ?",
new String[]{contactId}, null);
JSONArray emails = new JSONArray();
JSONObject email;
while (cursor.moveToNext()) {
email = new JSONObject();
try{
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)));
emails.put(email);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
}
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 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
/**
* This method will remove a Contact from the database based on ID.
* @param id the unique ID of the contact to remove
*/
public boolean remove(String id) {
int result = mApp.getContentResolver().delete(People.CONTENT_URI,
PEOPLE_ID_EQUALS,
new String[] {id});
return (result > 0) ? true : false;
}
}
@@ -46,6 +46,7 @@ import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Activity; import android.app.Activity;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.OperationApplicationException; import android.content.OperationApplicationException;
@@ -88,7 +89,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
*/ */
private static final Map<String, String> dbMap = new HashMap<String, String>(); private static final Map<String, String> dbMap = new HashMap<String, String>();
static { static {
dbMap.put("id", ContactsContract.Contacts._ID); dbMap.put("id", ContactsContract.Data.CONTACT_ID);
dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME); dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME);
dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME); dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
@@ -115,14 +116,12 @@ public class ContactAccessorSdk5 extends ContactAccessor {
dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY); dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY);
dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT); dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE); dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE);
//dbMap.put("revision", null);
dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE); dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE);
dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE); dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
//dbMap.put("categories.value", null); //dbMap.put("categories.value", null);
dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL); dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL);
dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL); dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL);
//dbMap.put("timezone", null);
} }
/** /**
@@ -142,9 +141,6 @@ public class ContactAccessorSdk5 extends ContactAccessor {
*/ */
@Override @Override
public JSONArray search(JSONArray fields, JSONObject options) { public JSONArray search(JSONArray fields, JSONObject options) {
long totalEnd;
long totalStart = System.currentTimeMillis();
// Get the find options // Get the find options
String searchTerm = ""; String searchTerm = "";
int limit = Integer.MAX_VALUE; int limit = Integer.MAX_VALUE;
@@ -180,7 +176,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
// Build the ugly where clause and where arguments for one big query. // Build the ugly where clause and where arguments for one big query.
WhereOptions whereOptions = buildWhereClause(fields, searchTerm); WhereOptions whereOptions = buildWhereClause(fields, searchTerm);
// Get all the id's where the search term matches the fields passed in. // Get all the id's where the search term matches the fields passed in.
Cursor idCursor = mApp.getContentResolver().query(ContactsContract.Data.CONTENT_URI, Cursor idCursor = mApp.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
new String[] { ContactsContract.Data.CONTACT_ID }, new String[] { ContactsContract.Data.CONTACT_ID },
@@ -206,8 +202,49 @@ public class ContactAccessorSdk5 extends ContactAccessor {
idOptions.getWhereArgs(), idOptions.getWhereArgs(),
ContactsContract.Data.CONTACT_ID + " ASC"); ContactsContract.Data.CONTACT_ID + " ASC");
JSONArray contacts = populateContactArray(limit, populate, c);
//Log.d(LOG_TAG, "Cursor length = " + c.getCount()); return contacts;
}
/**
* A special search that finds one contact by id
*
* @param id contact to find by id
* @return a JSONObject representing the contact
* @throws JSONException
*/
public JSONObject getContactById(String id) throws JSONException {
// Do the id query
Cursor c = mApp.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.CONTACT_ID + " = ? ",
new String[] { id },
ContactsContract.Data.CONTACT_ID + " ASC");
JSONArray fields = new JSONArray();
fields.put("*");
HashMap<String,Boolean> populate = buildPopulationSet(fields);
JSONArray contacts = populateContactArray(1, populate, c);
if (contacts.length() == 1) {
return contacts.getJSONObject(0);
} else {
return null;
}
}
/**
* Creates an array of contacts from the cursor you pass in
*
* @param limit max number of contacts for the array
* @param populate whether or not you should populate a certain value
* @param c the cursor
* @return a JSONArray of contacts
*/
private JSONArray populateContactArray(int limit,
HashMap<String, Boolean> populate, Cursor c) {
String contactId = ""; String contactId = "";
String rawId = ""; String rawId = "";
@@ -334,12 +371,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
} }
c.close(); c.close();
return contacts;
}
totalEnd = System.currentTimeMillis();
Log.d(LOG_TAG,"Total time = " + (totalEnd-totalStart));
return contacts;
}
/** /**
* Builds a where clause all all the ids passed into the method * Builds a where clause all all the ids passed into the method
@@ -392,13 +425,28 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONArray addresses, JSONArray phones, JSONArray emails, JSONArray addresses, JSONArray phones, JSONArray emails,
JSONArray ims, JSONArray websites, JSONArray photos) { JSONArray ims, JSONArray websites, JSONArray photos) {
try { try {
contact.put("organizations", organizations); // Only return the array if it has at least one entry
contact.put("addresses", addresses); if (organizations.length() > 0) {
contact.put("phoneNumbers", phones); contact.put("organizations", organizations);
contact.put("emails", emails); }
contact.put("ims", ims); if (addresses.length() > 0) {
contact.put("websites", websites); contact.put("addresses", addresses);
contact.put("photos", photos); }
if (phones.length() > 0) {
contact.put("phoneNumbers", phones);
}
if (emails.length() > 0) {
contact.put("emails", emails);
}
if (ims.length() > 0) {
contact.put("ims", ims);
}
if (websites.length() > 0) {
contact.put("websites", websites);
}
if (photos.length() > 0) {
contact.put("photos", photos);
}
} }
catch (JSONException e) { catch (JSONException e) {
Log.e(LOG_TAG,e.getMessage(),e); Log.e(LOG_TAG,e.getMessage(),e);
@@ -418,15 +466,67 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ArrayList<String> whereArgs = new ArrayList<String>(); ArrayList<String> whereArgs = new ArrayList<String>();
WhereOptions options = new WhereOptions(); WhereOptions options = new WhereOptions();
/*
* Special case where the user wants all fields returned
*/
if (isWildCardSearch(fields)) {
// Get all contacts with all properties
if ("%".equals(searchTerm)) {
options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
options.setWhereArgs(new String[] {searchTerm});
return options;
} else {
// Get all contacts that match the filter but return all properties
where.add("(" + dbMap.get("displayName") + " LIKE ? )");
whereArgs.add(searchTerm);
where.add("(" + dbMap.get("name") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("nickname") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("phoneNumbers") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("emails") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("addresses") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("ims") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("organizations") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("note") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
where.add("(" + dbMap.get("urls") + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )");
whereArgs.add(searchTerm);
whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
}
}
/* /*
* Special case for when the user wants all the contacts * Special case for when the user wants all the contacts but
*/ */
if ("%".equals(searchTerm)) { if ("%".equals(searchTerm)) {
options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )"); options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
options.setWhereArgs(new String[] {searchTerm}); options.setWhereArgs(new String[] {searchTerm});
return options; return options;
} }
String key; String key;
try { try {
@@ -434,10 +534,14 @@ public class ContactAccessorSdk5 extends ContactAccessor {
for (int i=0; i<fields.length(); i++) { for (int i=0; i<fields.length(); i++) {
key = fields.getString(i); key = fields.getString(i);
if (key.startsWith("displayName")) { if (key.equals("id")) {
where.add("(" + dbMap.get(key) + " LIKE ? )"); where.add("(" + dbMap.get(key) + " = ? )");
whereArgs.add(searchTerm); whereArgs.add(searchTerm.substring(1, searchTerm.length()-1));
} }
else if (key.startsWith("displayName")) {
where.add("(" + dbMap.get(key) + " LIKE ? )");
whereArgs.add(searchTerm);
}
else if (key.startsWith("name")) { else if (key.startsWith("name")) {
where.add("(" + dbMap.get(key) + " LIKE ? AND " where.add("(" + dbMap.get(key) + " LIKE ? AND "
+ ContactsContract.Data.MIMETYPE + " = ? )"); + ContactsContract.Data.MIMETYPE + " = ? )");
@@ -523,6 +627,26 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
/** /**
* If the user passes in the '*' wildcard character for search then they want all fields for each contact
*
* @param fields
* @return true if wildcard search requested, false otherwise
*/
private boolean isWildCardSearch(JSONArray fields) {
// Only do a wildcard search if we are passed ["*"]
if (fields.length() == 1) {
try {
if ("*".equals(fields.getString(0))) {
return true;
}
} catch (JSONException e) {
return false;
}
}
return false;
}
/**
* Create a ContactOrganization JSONObject * Create a ContactOrganization JSONObject
* @param cursor the current database row * @param cursor the current database row
* @return a JSONObject representing a ContactOrganization * @return a JSONObject representing a ContactOrganization
@@ -531,6 +655,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONObject organization = new JSONObject(); JSONObject organization = new JSONObject();
try { try {
organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID))); organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID)));
organization.put("pref", false); // Android does not store pref attribute
organization.put("type", getOrgType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT))); organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT)));
organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY))); organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY)));
organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE))); organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)));
@@ -549,6 +675,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONObject address = new JSONObject(); JSONObject address = new JSONObject();
try { try {
address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID))); address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID)));
address.put("pref", false); // Android does not store pref attribute
address.put("type", getAddressType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS))); address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)));
address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET))); address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY))); address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
@@ -695,9 +823,9 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* This method will save a contact object into the devices contacts database. * This method will save a contact object into the devices contacts database.
* *
* @param contact the contact to be saved. * @param contact the contact to be saved.
* @returns true if the contact is successfully saved, false otherwise. * @returns the id if the contact is successfully saved, null otherwise.
*/ */
public boolean save(JSONObject contact) { public String save(JSONObject contact) {
AccountManager mgr = AccountManager.get(mApp); AccountManager mgr = AccountManager.get(mApp);
Account[] accounts = mgr.getAccounts(); Account[] accounts = mgr.getAccounts();
Account account = null; Account account = null;
@@ -732,8 +860,9 @@ public class ContactAccessorSdk5 extends ContactAccessor {
} }
} }
if(account == null) if(account == null) {
return false; return null;
}
String id = getJsonString(contact, "id"); String id = getJsonString(contact, "id");
// Create new contact // Create new contact
@@ -753,7 +882,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* @param contact the contact to be saved * @param contact the contact to be saved
* @param account the account to be saved under * @param account the account to be saved under
*/ */
private boolean modifyContact(String id, JSONObject contact, Account account) { private String modifyContact(String id, JSONObject contact, Account account) {
// Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact. // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact.
// But not needed to update existing values. // But not needed to update existing values.
int rawId = (new Integer(getJsonString(contact,"rawId"))).intValue(); int rawId = (new Integer(getJsonString(contact,"rawId"))).intValue();
@@ -894,6 +1023,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"));
contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")); contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"));
@@ -910,6 +1040,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
.withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " + .withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?", ContactsContract.Data.MIMETYPE + "=?",
new String[]{addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}) new String[]{addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
@@ -938,6 +1069,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId); contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
contentValues.put(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")));
contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")); contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"));
contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")); contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"));
contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")); contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"));
@@ -951,6 +1083,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
.withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " + .withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?", ContactsContract.Data.MIMETYPE + "=?",
new String[]{orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}) new String[]{orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
.withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
.withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
.withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
@@ -1109,7 +1242,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
//Modify contact //Modify contact
try { try {
mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
Log.e(LOG_TAG, Log.getStackTraceString(e), e); Log.e(LOG_TAG, Log.getStackTraceString(e), e);
@@ -1120,7 +1253,12 @@ public class ContactAccessorSdk5 extends ContactAccessor {
retVal = false; retVal = false;
} }
return retVal; // if the save was a succes return the contact ID
if (retVal) {
return id;
} else {
return null;
}
} }
/** /**
@@ -1165,7 +1303,8 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department")) .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
.withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
.withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name")) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
.withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title")) .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
.build()); .build());
@@ -1182,6 +1321,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality")) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
@@ -1296,7 +1436,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
* @param contact the contact to be saved * @param contact the contact to be saved
* @param account the account to be saved under * @param account the account to be saved under
*/ */
private boolean createNewContact(JSONObject contact, Account account) { private String createNewContact(JSONObject contact, Account account) {
// Create a list of attributes to add to the contact database // Create a list of attributes to add to the contact database
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
@@ -1463,18 +1603,21 @@ public class ContactAccessorSdk5 extends ContactAccessor {
Log.d(LOG_TAG, "Could not get photos"); Log.d(LOG_TAG, "Could not get photos");
} }
boolean retVal = true; String newId = null;
//Add contact //Add contact
try { try {
mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); ContentProviderResult[] cpResults = mApp.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
if (cpResults.length >= 0) {
newId = cpResults[0].uri.getLastPathSegment();
}
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
retVal = false; newId = null;
} catch (OperationApplicationException e) { } catch (OperationApplicationException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
retVal = false; newId = null;
} }
return retVal; return newId;
} }
@Override @Override
@@ -1645,58 +1788,144 @@ public class ContactAccessorSdk5 extends ContactAccessor {
return stringType; return stringType;
} }
/** /**
* Converts a string from the W3C Contact API to it's Android int value. * Converts a string from the W3C Contact API to it's Android int value.
* @param string * @param string
* @return Android int value * @return Android int value
*/ */
private int getContactType(String string) { private int getContactType(String string) {
int type = ContactsContract.CommonDataKinds.Email.TYPE_OTHER; int type = ContactsContract.CommonDataKinds.Email.TYPE_OTHER;
if (string!=null) { if (string!=null) {
if ("home".equals(string.toLowerCase())) { if ("home".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Email.TYPE_HOME; return ContactsContract.CommonDataKinds.Email.TYPE_HOME;
} }
else if ("work".equals(string.toLowerCase())) { else if ("work".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Email.TYPE_WORK; return ContactsContract.CommonDataKinds.Email.TYPE_WORK;
} }
else if ("other".equals(string.toLowerCase())) { else if ("other".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Email.TYPE_OTHER; return ContactsContract.CommonDataKinds.Email.TYPE_OTHER;
} }
else if ("mobile".equals(string.toLowerCase())) { else if ("mobile".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Email.TYPE_MOBILE; return ContactsContract.CommonDataKinds.Email.TYPE_MOBILE;
} }
else if ("custom".equals(string.toLowerCase())) { else if ("custom".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM; return ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM;
} }
} }
return type; return type;
} }
/** /**
* getPhoneType converts an Android phone type into a string * getPhoneType converts an Android phone type into a string
* @param type * @param type
* @return phone type as string. * @return phone type as string.
*/ */
private String getContactType(int type) { private String getContactType(int type) {
String stringType; String stringType;
switch (type) { switch (type) {
case ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM: case ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM:
stringType = "custom"; stringType = "custom";
break; break;
case ContactsContract.CommonDataKinds.Email.TYPE_HOME: case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
stringType = "home"; stringType = "home";
break; break;
case ContactsContract.CommonDataKinds.Email.TYPE_WORK: case ContactsContract.CommonDataKinds.Email.TYPE_WORK:
stringType = "work"; stringType = "work";
break; break;
case ContactsContract.CommonDataKinds.Email.TYPE_MOBILE: case ContactsContract.CommonDataKinds.Email.TYPE_MOBILE:
stringType = "mobile"; stringType = "mobile";
break; break;
case ContactsContract.CommonDataKinds.Email.TYPE_OTHER: case ContactsContract.CommonDataKinds.Email.TYPE_OTHER:
default: default:
stringType = "other"; stringType = "other";
break; break;
} }
return stringType; return stringType;
} }
/**
* Converts a string from the W3C Contact API to it's Android int value.
* @param string
* @return Android int value
*/
private int getOrgType(String string) {
int type = ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
if (string!=null) {
if ("work".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_WORK;
}
else if ("other".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_OTHER;
}
else if ("custom".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM;
}
}
return type;
}
/**
* getPhoneType converts an Android phone type into a string
* @param type
* @return phone type as string.
*/
private String getOrgType(int type) {
String stringType;
switch (type) {
case ContactsContract.CommonDataKinds.Organization.TYPE_CUSTOM:
stringType = "custom";
break;
case ContactsContract.CommonDataKinds.Organization.TYPE_WORK:
stringType = "work";
break;
case ContactsContract.CommonDataKinds.Organization.TYPE_OTHER:
default:
stringType = "other";
break;
}
return stringType;
}
/**
* Converts a string from the W3C Contact API to it's Android int value.
* @param string
* @return Android int value
*/
private int getAddressType(String string) {
int type = ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
if (string!=null) {
if ("work".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK;
}
else if ("other".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER;
}
else if ("home".equals(string.toLowerCase())) {
return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME;
}
}
return type;
}
/**
* getPhoneType converts an Android phone type into a string
* @param type
* @return phone type as string.
*/
private String getAddressType(int type) {
String stringType;
switch (type) {
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
stringType = "home";
break;
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK:
stringType = "work";
break;
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER:
default:
stringType = "other";
break;
}
return stringType;
}
} }
+49 -21
View File
@@ -16,9 +16,18 @@ import android.util.Log;
public class ContactManager extends Plugin { public class ContactManager extends Plugin {
private static ContactAccessor contactAccessor; private ContactAccessor contactAccessor;
private static final String LOG_TAG = "Contact Query"; private static final String LOG_TAG = "Contact Query";
public static final int UNKNOWN_ERROR = 0;
public static final int INVALID_ARGUMENT_ERROR = 1;
public static final int TIMEOUT_ERROR = 2;
public static final int PENDING_OPERATION_ERROR = 3;
public static final int IO_ERROR = 4;
public static final int NOT_SUPPORTED_ERROR = 5;
public static final int PERMISSION_DENIED_ERROR = 20;
/** /**
* Constructor. * Constructor.
*/ */
@@ -34,38 +43,57 @@ public class ContactManager extends Plugin {
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
if (contactAccessor == null) { PluginResult.Status status = PluginResult.Status.OK;
contactAccessor = ContactAccessor.getInstance(webView, ctx); String result = "";
}
PluginResult.Status status = PluginResult.Status.OK; /**
String result = ""; * Check to see if we are on an Android 1.X device. If we are return an error as we
* do not support this as of PhoneGap 1.0.
*/
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
JSONObject res = null;
try {
res = new JSONObject();
res.put("code", NOT_SUPPORTED_ERROR);
res.put("message", "Contacts are not supported in Android 1.X devices");
} catch (JSONException e) {
// This should never happen
Log.e(LOG_TAG, e.getMessage(), e);
}
return new PluginResult(PluginResult.Status.ERROR, res);
}
/**
* Only create the contactAccessor after we check the Android version or the program will crash
* older phones.
*/
if (this.contactAccessor == null) {
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.ctx);
}
try { try {
if (action.equals("search")) { if (action.equals("search")) {
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1)); JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1));
return new PluginResult(status, res, "navigator.service.contacts.cast"); return new PluginResult(status, res, "navigator.contacts.cast");
} }
else if (action.equals("save")) { else if (action.equals("save")) {
if (contactAccessor.save(args.getJSONObject(0))) { String id = contactAccessor.save(args.getJSONObject(0));
return new PluginResult(status, result); if (id != null) {
} JSONObject res = contactAccessor.getContactById(id);
else { if (res != null) {
JSONObject r = new JSONObject(); return new PluginResult(status, res);
r.put("code", 0); }
return new PluginResult(PluginResult.Status.ERROR, r);
} }
} }
else if (action.equals("remove")) { else if (action.equals("remove")) {
if (contactAccessor.remove(args.getString(0))) { if (contactAccessor.remove(args.getString(0))) {
return new PluginResult(status, result); return new PluginResult(status, result);
} }
else {
JSONObject r = new JSONObject();
r.put("code", 2);
return new PluginResult(PluginResult.Status.ERROR, r);
}
} }
return new PluginResult(status, result); // If we get to this point an error has occurred
JSONObject r = new JSONObject();
r.put("code", UNKNOWN_ERROR);
return new PluginResult(PluginResult.Status.ERROR, r);
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+1 -1
View File
@@ -18,7 +18,7 @@ import android.provider.Settings;
public class Device extends Plugin { public class Device extends Plugin {
public static String phonegapVersion = "0.9.6.1"; // PhoneGap version public static String phonegapVersion = "1.0.0"; // PhoneGap version
public static String platform = "Android"; // Device OS public static String platform = "Android"; // Device OS
public static String uuid; // Device UUID public static String uuid; // Device UUID
@@ -9,6 +9,7 @@ package com.phonegap;
import java.io.File; import java.io.File;
import android.content.Context;
import android.os.Environment; import android.os.Environment;
import android.os.StatFs; import android.os.StatFs;
@@ -111,4 +112,31 @@ public class DirectoryManager {
} }
return newPath; return newPath;
} }
/**
* Determine if we can use the SD Card to store the temporary file. If not then use
* the internal cache directory.
*
* @return the absolute path of where to store the file
*/
protected static String getTempDirectoryPath(Context ctx) {
File cache = null;
// SD Card Mounted
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/Android/data/" + ctx.getPackageName() + "/cache/");
}
// Use internal storage
else {
cache = ctx.getCacheDir();
}
// Create the cache directory if it doesn't exist
if (!cache.exists()) {
cache.mkdirs();
}
return cache.getAbsolutePath();
}
} }
+53 -25
View File
@@ -15,6 +15,7 @@ import org.json.JSONException;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -94,10 +95,6 @@ import com.phonegap.api.PluginManager;
* // (String - default=null) * // (String - default=null)
* super.setStringProperty("loadingDialog", "Wait,Loading Demo..."); * super.setStringProperty("loadingDialog", "Wait,Loading Demo...");
* *
* // Hide loadingDialog when page loaded instead of when deviceready event
* // occurs. (Boolean - default=false)
* super.setBooleanProperty("hideLoadingDialogOnPage", true);
*
* // Cause all links on web page to be loaded into existing web view, * // Cause all links on web page to be loaded into existing web view,
* // instead of being loaded into new browser. (Boolean - default=false) * // instead of being loaded into new browser. (Boolean - default=false)
* super.setBooleanProperty("loadInWebView", true); * super.setBooleanProperty("loadInWebView", true);
@@ -129,6 +126,7 @@ public class DroidGap extends PhonegapActivity {
protected PluginManager pluginManager; protected PluginManager pluginManager;
protected boolean cancelLoadUrl = false; protected boolean cancelLoadUrl = false;
protected boolean clearHistory = false; protected boolean clearHistory = false;
protected ProgressDialog spinnerDialog = null;
// The initial URL for our app // The initial URL for our app
// ie http://server/path/index.html#abc?query // ie http://server/path/index.html#abc?query
@@ -149,10 +147,6 @@ public class DroidGap extends PhonegapActivity {
/* /*
* The variables below are used to cache some of the activity properties. * The variables below are used to cache some of the activity properties.
*/ */
// Flag indicates that "app loading" dialog should be hidden once page is loaded.
// The default is to hide it once PhoneGap JavaScript code has initialized.
protected boolean hideLoadingDialogOnPageLoad = false;
// Flag indicates that a URL navigated to from PhoneGap app should be loaded into same webview // Flag indicates that a URL navigated to from PhoneGap app should be loaded into same webview
// instead of being loaded into the web browser. // instead of being loaded into the web browser.
@@ -241,9 +235,9 @@ public class DroidGap extends PhonegapActivity {
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL); settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
// Enable database // Enable database
Package pack = this.getClass().getPackage(); settings.setDatabaseEnabled(true);
String appPackage = pack.getName(); String databasePath = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
WebViewReflect.setStorage(settings, true, "/data/data/" + appPackage + "/app_database/"); settings.setDatabasePath(databasePath);
// Enable DOM storage // Enable DOM storage
WebViewReflect.setDomStorage(settings); WebViewReflect.setDomStorage(settings);
@@ -309,9 +303,6 @@ public class DroidGap extends PhonegapActivity {
root.setBackgroundResource(this.splashscreen); root.setBackgroundResource(this.splashscreen);
} }
// If hideLoadingDialogOnPageLoad
this.hideLoadingDialogOnPageLoad = this.getBooleanProperty("hideLoadingDialogOnPageLoad", false);
// If loadInWebView // If loadInWebView
this.loadInWebView = this.getBooleanProperty("loadInWebView", false); this.loadInWebView = this.getBooleanProperty("loadInWebView", false);
@@ -373,10 +364,7 @@ public class DroidGap extends PhonegapActivity {
message = loading; message = loading;
} }
} }
JSONArray parm = new JSONArray(); me.spinnerStart(title, message);
parm.put(title);
parm.put(message);
me.pluginManager.exec("Notification", "activityStart", null, parm.toString(), false);
} }
// Create a timeout timer for loadUrl // Create a timeout timer for loadUrl
@@ -761,6 +749,36 @@ public class DroidGap extends PhonegapActivity {
this.finish(); this.finish();
} }
} }
/**
* Show the spinner. Must be called from the UI thread.
*
* @param title Title of the dialog
* @param message The message of the dialog
*/
public void spinnerStart(final String title, final String message) {
if (this.spinnerDialog != null) {
this.spinnerDialog.dismiss();
this.spinnerDialog = null;
}
final DroidGap me = this;
this.spinnerDialog = ProgressDialog.show(DroidGap.this, title , message, true, true,
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
me.spinnerDialog = null;
}
});
}
/**
* Stop spinner.
*/
public void spinnerStop() {
if (this.spinnerDialog != null) {
this.spinnerDialog.dismiss();
this.spinnerDialog = null;
}
}
/** /**
* Provides a hook for calling "alert" from javascript. Useful for * Provides a hook for calling "alert" from javascript. Useful for
@@ -903,6 +921,9 @@ public class DroidGap extends PhonegapActivity {
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
dlg.setMessage(message); dlg.setMessage(message);
final EditText input = new EditText(this.ctx); final EditText input = new EditText(this.ctx);
if (defaultValue != null) {
input.setText(defaultValue);
}
dlg.setView(input); dlg.setView(input);
dlg.setCancelable(false); dlg.setCancelable(false);
dlg.setPositiveButton(android.R.string.ok, dlg.setPositiveButton(android.R.string.ok,
@@ -1100,9 +1121,19 @@ public class DroidGap extends PhonegapActivity {
// our app is reloaded and restarted. All state is lost. // our app is reloaded and restarted. All state is lost.
if (this.ctx.loadInWebView || url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0) { if (this.ctx.loadInWebView || url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0) {
try { try {
// Init parameters to new DroidGap activity and propagate existing parameters
HashMap<String, Object> params = new HashMap<String, Object>(); HashMap<String, Object> params = new HashMap<String, Object>();
params.put("loadingDialog", ""); params.put("loadingDialog", null);
params.put("hideLoadingDialogOnPageLoad", true); if (this.ctx.loadInWebView) {
params.put("loadInWebView", true);
}
params.put("keepRunning", this.ctx.keepRunning);
params.put("loadUrlTimeoutValue", this.ctx.loadUrlTimeoutValue);
String errorUrl = this.ctx.getStringProperty("errorUrl", null);
if (errorUrl != null) {
params.put("errorUrl", errorUrl);
}
this.ctx.showWebPage(url, true, false, params); this.ctx.showWebPage(url, true, false, params);
} catch (android.content.ActivityNotFoundException e) { } catch (android.content.ActivityNotFoundException e) {
System.out.println("Error loading url into DroidGap - "+url+":"+ e.toString()); System.out.println("Error loading url into DroidGap - "+url+":"+ e.toString());
@@ -1147,10 +1178,7 @@ public class DroidGap extends PhonegapActivity {
appView.setVisibility(View.VISIBLE); appView.setVisibility(View.VISIBLE);
// Stop "app loading" spinner if showing // Stop "app loading" spinner if showing
if (this.ctx.hideLoadingDialogOnPageLoad) { this.ctx.spinnerStop();
this.ctx.hideLoadingDialogOnPageLoad = false;
this.ctx.pluginManager.exec("Notification", "activityStop", null, "[]", false);
}
// Clear history, so that previous screen isn't there when Back button is pressed // Clear history, so that previous screen isn't there when Back button is pressed
if (this.ctx.clearHistory) { if (this.ctx.clearHistory) {
@@ -1183,7 +1211,7 @@ public class DroidGap extends PhonegapActivity {
this.ctx.loadUrlTimeout++; this.ctx.loadUrlTimeout++;
// Stop "app loading" spinner if showing // Stop "app loading" spinner if showing
this.ctx.pluginManager.exec("Notification", "activityStop", null, "[]", false); this.ctx.spinnerStop();
// Handle error // Handle error
this.ctx.onReceivedError(errorCode, description, failingUrl); this.ctx.onReceivedError(errorCode, description, failingUrl);
+29 -38
View File
@@ -18,8 +18,10 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
@@ -104,9 +106,6 @@ public class FileUtils extends Plugin {
else if (action.equals("readAsDataURL")) { else if (action.equals("readAsDataURL")) {
String s = this.readAsDataURL(args.getString(0)); String s = this.readAsDataURL(args.getString(0));
return new PluginResult(status, s); return new PluginResult(status, s);
}
else if (action.equals("writeAsText")) {
this.writeAsText(args.getString(0), args.getString(1), args.getBoolean(2));
} }
else if (action.equals("write")) { else if (action.equals("write")) {
long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2)); long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
@@ -231,22 +230,34 @@ public class FileUtils extends Plugin {
*/ */
private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException { private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
String decoded = URLDecoder.decode(url, "UTF-8"); String decoded = URLDecoder.decode(url, "UTF-8");
// Test to see if this is a valid URL first
@SuppressWarnings("unused") File fp = null;
URL testUrl = new URL(decoded);
// Handle the special case where you get an Android content:// uri.
if (decoded.startsWith("content:")) {
Cursor cursor = this.ctx.managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
// Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
fp = new File(cursor.getString(column_index));
} else {
// Test to see if this is a valid URL first
@SuppressWarnings("unused")
URL testUrl = new URL(decoded);
if (decoded.startsWith("file://")) {
fp = new File(decoded.substring(7, decoded.length()));
} else {
fp = new File(decoded);
}
}
File fp = null; if (!fp.exists()) {
if (decoded.startsWith("file://")) { throw new FileNotFoundException();
fp = new File(decoded.substring(7, decoded.length())); }
} else { if (!fp.canRead()) {
fp = new File(decoded); throw new IOException();
} }
if (!fp.exists()) {
throw new FileNotFoundException();
}
if (!fp.canRead()) {
throw new IOException();
}
return getEntry(fp); return getEntry(fp);
} }
@@ -914,26 +925,6 @@ public class FileUtils extends Plugin {
return map.getMimeTypeFromExtension(map.getFileExtensionFromUrl(filename)); return map.getMimeTypeFromExtension(map.getFileExtensionFromUrl(filename));
} }
/**
* Write contents of file.
*
* @param filename The name of the file.
* @param data The contents of the file.
* @param append T=append, F=overwrite
* @throws FileNotFoundException, IOException
*/
public void writeAsText(String filename, String data, boolean append) throws FileNotFoundException, IOException {
String FilePath= filename;
byte [] rawData = data.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(rawData);
FileOutputStream out= new FileOutputStream(FilePath, append);
byte buff[] = new byte[rawData.length];
in.read(buff, 0, buff.length);
out.write(buff, 0, rawData.length);
out.flush();
out.close();
}
/** /**
* Write contents of file. * Write contents of file.
* *
+11 -90
View File
@@ -7,10 +7,7 @@
*/ */
package com.phonegap; package com.phonegap;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.PhonegapActivity; import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin; import com.phonegap.api.Plugin;
@@ -102,32 +99,18 @@ public class NetworkManager extends Plugin {
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
String result = ""; String result = "Unsupported Operation: " + action;
try {
if (action.equals("isAvailable")) { if (action.equals("getConnectionInfo")) {
boolean b = this.isAvailable(); this.connectionCallbackId = callbackId;
return new PluginResult(status, b); NetworkInfo info = sockMan.getActiveNetworkInfo();
} PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
else if (action.equals("isWifiActive")) { pluginResult.setKeepCallback(true);
boolean b = this.isWifiActive(); return pluginResult;
return new PluginResult(status, b);
}
else if (action.equals("isReachable")) {
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);
} }
return new PluginResult(status, result);
} }
/** /**
@@ -236,66 +219,4 @@ public class NetworkManager extends Plugin {
} }
return TYPE_UNKNOWN; return TYPE_UNKNOWN;
} }
/**
* Determine if a network connection exists.
*
* @return
*/
public boolean isAvailable() {
NetworkInfo info = sockMan.getActiveNetworkInfo();
boolean conn = false;
if (info != null) {
conn = info.isConnected();
}
return conn;
}
/**
* Determine if a WIFI connection exists.
*
* @return
*/
public boolean isWifiActive() {
NetworkInfo info = sockMan.getActiveNetworkInfo();
if (info != null) {
String type = info.getTypeName();
return type.equals("WIFI");
}
return false;
}
/**
* Determine if a URI is reachable over the network.
*
* @param uri
* @param isIpAddress
* @return
*/
public int isReachable(String uri, boolean isIpAddress) {
int reachable = NOT_REACHABLE;
if (uri.indexOf("http://") == -1 && uri.indexOf("https://") == -1) {
uri = "http://" + uri;
}
if (this.isAvailable()) {
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(uri);
httpclient.execute(httpget);
if (this.isWifiActive()) {
reachable = REACHABLE_VIA_WIFI_NETWORK;
}
else {
reachable = REACHABLE_VIA_CARRIER_DATA_NETWORK;
}
} catch (Exception e) {
reachable = NOT_REACHABLE;
}
}
return reachable;
}
} }
@@ -49,7 +49,9 @@ public final class PluginManager {
* Load plugins from res/xml/plugins.xml * Load plugins from res/xml/plugins.xml
*/ */
public void loadPlugins() { public void loadPlugins() {
XmlResourceParser xml = ctx.getResources().getXml(com.phonegap.R.xml.plugins); int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
if (id == 0) { pluginConfigurationMissing(); }
XmlResourceParser xml = ctx.getResources().getXml(id);
int eventType = -1; int eventType = -1;
while (eventType != XmlResourceParser.END_DOCUMENT) { while (eventType != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) { if (eventType == XmlResourceParser.START_TAG) {
@@ -57,7 +59,7 @@ public final class PluginManager {
if (strNode.equals("plugin")) { if (strNode.equals("plugin")) {
String name = xml.getAttributeValue(null, "name"); String name = xml.getAttributeValue(null, "name");
String value = xml.getAttributeValue(null, "value"); String value = xml.getAttributeValue(null, "value");
System.out.println("Plugin: "+name+" => "+value); //System.out.println("Plugin: "+name+" => "+value);
this.addService(name, value); this.addService(name, value);
} }
} }
@@ -296,4 +298,11 @@ public final class PluginManager {
plugin.onNewIntent(intent); plugin.onNewIntent(intent);
} }
} }
private void pluginConfigurationMissing() {
System.err.println("=====================================================================================");
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");
System.err.println("https://raw.github.com/phonegap/phonegap-android/master/framework/res/xml/plugins.xml");
System.err.println("=====================================================================================");
}
} }
+2 -2
View File
@@ -93,7 +93,7 @@ class Classic
app_res_dir = File.join(@path, "res") app_res_dir = File.join(@path, "res")
# copies in the jar # copies in the jar
FileUtils.mkdir_p File.join(@path, "libs") FileUtils.mkdir_p File.join(@path, "libs")
FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs") FileUtils.cp File.join(@framework_dir, "phonegap-#{ version }.jar"), File.join(@path, "libs")
# copies in the strings.xml # copies in the strings.xml
FileUtils.mkdir_p File.join(app_res_dir, "values") 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") FileUtils.cp File.join(framework_res_dir, "values","strings.xml"), File.join(app_res_dir, "values", "strings.xml")
@@ -128,7 +128,7 @@ class Classic
phonegapjs << IO.read(File.join(js_dir, script)) phonegapjs << IO.read(File.join(js_dir, script))
phonegapjs << "\n\n" phonegapjs << "\n\n"
end end
File.open(File.join(@path, "assets", "www", @app_js_dir, "phonegap.#{ version }.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 end
# puts app name in strings # puts app name in strings
+2 -2
View File
@@ -35,7 +35,7 @@ class Update
puts "Copying over libraries and assets..." puts "Copying over libraries and assets..."
version = IO.read(File.join(@framework_dir, '../VERSION')) version = IO.read(File.join(@framework_dir, '../VERSION'))
FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs") 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 # 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") js_dir = File.join(@framework_dir, "assets", "js")
@@ -45,7 +45,7 @@ class Update
phonegapjs << IO.read(File.join(js_dir, script)) phonegapjs << IO.read(File.join(js_dir, script))
phonegapjs << "\n\n" phonegapjs << "\n\n"
end end
File.open(File.join(@path, "assets", "www", "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) } File.open(File.join(@path, "assets", "www", "phonegap-#{ version }.js"), 'w') {|f| f.write(phonegapjs) }
end end
# #
end end
-31
View File
@@ -1,31 +0,0 @@
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
View File
@@ -1,140 +0,0 @@
==============================================================================
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.
Binary file not shown.