Compare commits

..

75 Commits

Author SHA1 Message Date
Joe Bowser f3d7ce8fc3 VERSION: 2011-06-27 16:01:43 -07:00
Bryce Curtis 85dab52cf7 Handle errors when adding a service. 2011-06-27 13:49:24 -05:00
Bryce Curtis c96c9b00b9 Revert to polling if there are any errors with callback server. This addresses various problems with proxies set by carriers. 2011-06-27 13:48:02 -05:00
Joe Bowser b059a31787 Merge branch 'master' of github.com:phonegap/phonegap-android 2011-06-27 10:23:16 -07:00
Joe Bowser 8cb71673c2 Changing default target to the highest for maximum compatibility 2011-06-27 10:22:57 -07:00
macdonst 8ef93ff0e5 Issue 123: Fixing problem where name object is not specified 2011-06-28 00:34:11 +08:00
Joe Bowser 042c34192b Trying to merge 2011-06-24 14:09:34 -07:00
macdonst ac2e92321f Issue #121: Problem with resolveLocalFileSystemURI if file name has spaces 2011-06-24 14:08:46 -07:00
Bryce Curtis 05eacf4792 Always call plugin's onPause/onResume with multitasking flag when these lifecycle events occur in activity. It is up to the plugin to handle as necessary. 2011-06-24 14:08:46 -07:00
Kevin Griffin 435c903baf formatting - sigh 2011-06-24 14:08:46 -07:00
Bryce Curtis 53de070a41 Return true when handling key events, indicating that no further processing is necessary. 2011-06-24 14:08:46 -07:00
Bryce Curtis 54fdcbfd46 Urls with same path and file but different # or ? should compare to same url. 2011-06-24 14:08:46 -07:00
Joe Bowser 44aa0aeb0f Adding SSL dev code 2011-06-24 14:08:46 -07:00
Kevin Griffin 7d53eb8e3e formattage 2011-06-24 14:08:46 -07:00
Joe Bowser 7bc0d624ac Fixing conflict 2011-06-24 14:08:26 -07:00
Kevin Griffin a5039f021d made the mistake of opening anything in finder 2011-06-24 14:06:21 -07:00
Bryce Curtis 80e66d87a9 Issue 112: PhoneGap.Channel: replace instanceof Function with typeof === 'Function' 2011-06-24 14:06:21 -07:00
Bryce Curtis d35e8cd44b Fix security vulnerability - make sure any requests to run native code only come from url currently loaded into webview. 2011-06-24 14:06:20 -07:00
Benjamin Weingarten eb3b1f91d4 Fix bug where isreachable doesn't return correct results for https
(http secure) url protocol.
2011-06-24 14:06:20 -07:00
macdonst 8a1ab69235 Updating Network Connection API to match spec released on June 7th 2011-06-24 14:06:20 -07:00
Bryce Curtis 66f3018767 Set PhoneGap.UsePolling flag based upon result from CallbackServer. 2011-06-24 14:06:20 -07:00
macdonst ff7de25b62 Issue #106: Typo in LocalFileSystem.prototype._castDate 2011-06-24 14:06:20 -07:00
macdonst 85eb6e4997 Issue #104: Bug in FileUtils.copyDirectory & moveDirectory
Adding better test to see if a directory is being moved/copied into itself.

Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR
2011-06-24 14:06:20 -07:00
macdonst 0280d5dd82 Updating Connection object to conform with recently released spec
- Replacing currentNW and homeNW with networkName.
- Changing Connection constants to strings instead of ints.
- Firing online/offline events on network change.
2011-06-24 14:06:20 -07:00
Nitobi 3c90a9a23c Fixed droidgap update command 2011-06-24 14:06:20 -07:00
macdonst 088c342198 Improve performance of our encoding
Move from using String.replaceAll() to a modified version or URLEncoder.encode().
2011-06-24 14:06:20 -07:00
macdonst af18a8e1aa Issue #80: Unable to open large json files on android 2.2 + phonegap 0.9.5
I could not get rid of the url encoding and decoding without hampering some users ability to pass non-ascii characters back to JavaScript.  However, I was able to reduce the amount of data being passed from Java to JavaScript by 40% by decoding common characters that occur in JSON and XML.  These characters will survive the round trip just fine and don't need to be encoded.

This is the best solution I could come up with.  You won't be able to read files as large as you could in 0.9.4 but it will get close and it will support non-ascii characters.
2011-06-24 14:06:20 -07:00
Joe Bowser 11a29e11e1 Merge branch 'master' of github.com:phonegap/phonegap-android 2011-06-24 14:02:02 -07:00
macdonst 08c44f5c5d Issue #121: Problem with resolveLocalFileSystemURI if file name has spaces 2011-06-25 04:41:19 +08:00
Bryce Curtis 1c3ea54dcb Always call plugin's onPause/onResume with multitasking flag when these lifecycle events occur in activity. It is up to the plugin to handle as necessary. 2011-06-23 23:22:48 -05:00
Bryce Curtis a65638ab59 Merge pull request #118 from m00sey/master
Always fire onPause, onResume and onNewIntent events for Plugins.
2011-06-23 20:51:35 -07:00
Kevin Griffin c15971253f formatting - sigh 2011-06-22 11:05:33 -04:00
Bryce Curtis a67dfdb75e Return true when handling key events, indicating that no further processing is necessary. 2011-06-21 22:53:45 -05:00
Bryce Curtis 9b52827744 Urls with same path and file but different # or ? should compare to same url. 2011-06-21 22:50:53 -05:00
Fil Maj c5b268756b Merge pull request #103 from doggerelverse/droidgap_update
Fixed droidgap update command
2011-06-21 17:22:02 -07:00
Joe Bowser afa85a74b3 Adding SSL dev code 2011-06-21 10:08:42 -07:00
Kevin Griffin 517b5e0db9 formattage 2011-06-21 11:46:54 -04:00
Kevin Griffin 327bda49a0 Sending pause/resume notifcations to plugins regardless of 'keepRunning' state.
Not sure why you wouldn't want to send them

Added a OnNewIntent override for Plugins to use.
2011-06-21 11:32:22 -04:00
Kevin Griffin c978341d83 made the mistake of opening anything in finder 2011-06-21 11:32:18 -04:00
macdonst 939754e1c9 Merge pull request #110 from Worklight/isReachble_fix
Fix bug where isReachable doesn't return correct results for https
2011-06-20 09:48:55 -07:00
Bryce Curtis d1448e9073 Issue 112: PhoneGap.Channel: replace instanceof Function with typeof === 'Function' 2011-06-15 13:01:03 -05:00
Bryce Curtis 33bfb44f67 Fix security vulnerability - make sure any requests to run native code only come from url currently loaded into webview. 2011-06-13 15:16:08 -05:00
Benjamin Weingarten a89c8bf482 Fix bug where isreachable doesn't return correct results for https
(http secure) url protocol.
2011-06-12 13:50:49 +03:00
macdonst a67aeed571 Updating Network Connection API to match spec released on June 7th 2011-06-09 03:11:39 +08:00
Bryce Curtis 315b5a59b3 Set PhoneGap.UsePolling flag based upon result from CallbackServer. 2011-06-07 14:18:18 -05:00
macdonst 8da5ad8eca Issue #106: Typo in LocalFileSystem.prototype._castDate 2011-06-07 22:03:58 +08:00
macdonst 740e50ce61 Issue #104: Bug in FileUtils.copyDirectory & moveDirectory
Adding better test to see if a directory is being moved/copied into itself.

Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR
2011-06-07 03:12:55 +08:00
macdonst 3ce0fc4897 Updating Connection object to conform with recently released spec
- Replacing currentNW and homeNW with networkName.
- Changing Connection constants to strings instead of ints.
- Firing online/offline events on network change.
2011-06-07 02:36:01 +08:00
Nitobi 8d1722ad67 Fixed droidgap update command 2011-06-03 10:59:48 -07:00
macdonst 7d41646a35 Improve performance of our encoding
Move from using String.replaceAll() to a modified version or URLEncoder.encode().
2011-06-02 10:31:56 +08:00
macdonst 992ee0bca4 Issue #80: Unable to open large json files on android 2.2 + phonegap 0.9.5
I could not get rid of the url encoding and decoding without hampering some users ability to pass non-ascii characters back to JavaScript.  However, I was able to reduce the amount of data being passed from Java to JavaScript by 40% by decoding common characters that occur in JSON and XML.  These characters will survive the round trip just fine and don't need to be encoded.

This is the best solution I could come up with.  You won't be able to read files as large as you could in 0.9.4 but it will get close and it will support non-ascii characters.
2011-06-01 21:27:27 +08:00
Joe Bowser d00a9f33cd Merge branch 'master' of github.com:phonegap/phonegap-android into keyboard 2011-05-31 15:41:03 -07:00
Joe Bowser 431c80782e Changing the layout class so it has the screen dimensions to take into account Device Orientation 2011-05-31 15:38:03 -07:00
Bryce Curtis 39ec9c095d Need to unregister for network intent receiver on shutdown to prevent leaks. 2011-05-31 15:13:54 -05:00
Bryce Curtis 10e1808c56 Clean up CallbackServer when about:blank page has loaded. This fixes errors when shutting down. 2011-05-31 15:11:02 -05:00
macdonst 9036eb8fcc Issue #94: feature request: Event for Keyboard show/hide 2011-05-30 15:12:31 -04:00
Fil Maj 4280fdf252 Fix for ticket #58: Certain 1.5/1.6 devices would throw a FileNotFoundException when taking pictures. Patch submitted by Agustin of AVANTIC (thanks!). 2011-05-26 12:42:44 -07:00
macdonst ca5e141b5b Changing Media class to return seconds
The media commands getCurrentPosition() and getDuration() will now return seconds (float) instead of milliseconds to line up with iOS and the docs.
2011-05-27 01:54:48 +08:00
macdonst 1d79b6617b JavaScript cleanup to pass jsHint
I did my best to clean up the JavaScript so it would pass through jsHint more cleanly.  There still are issues but there are a lot fewer now.  This helped to make the JS code more consistent.
2011-05-21 02:31:24 +08:00
macdonst 6c3eefe6f9 Issue #85: window.openDatabase throws DOM Exception 18 on Android 3.1
Instead of checking the userAgent catch the exception.  If we do get an exception it will setup our version of Droid Db.
2011-05-21 02:13:03 +08:00
macdonst 2177cd0a39 Moving navigator.connection to navigator.device.connection
Android 2.2 introduces the navigation.connection interface but it does not work properly in WebView.  So in order to get the proper connection information we had to implement our own connection interface which is accessible at navigator.network.connection.
2011-05-18 03:26:31 +08:00
macdonst 6618015151 Fixing a number of issues in File API
Issue #82: The RandomAccessFile class in Android's version of Java does not write non-ASCII characters very well.  I've switched to using a FileOutputStream which seems to work just great.  Tested by myself and folks from Egypt and the Netherlands.

Issue #87: Fixed a problem where the file errors were being returned as evt.target.result.code.code.
2011-05-17 22:11:38 +08:00
macdonst e99f75d59b Issue #85: window.openDatabase throws DOM Exception 18 on Android 3.1
The way were were detecting we were on an Android 3.0 device was not applicable for Android 3.1.  I've made and update so that any Android 3.X device will use our implementation of web sql databases instead of the built in one which thows a security error.
2011-05-16 23:14:24 +08:00
macdonst ab8cfe01d0 Removing generated code from project
framework/gen/com/phonegap/R.java
2011-05-16 10:37:25 +08:00
macdonst e84c59d23c Merge pull request #78 from kernelsandirs/master
Added Media.seekTo(int milliseconds);

Merging this code in now and making some notes to enhance the Media class.
2011-05-15 19:32:02 -07:00
macdonst e81fc239a7 Setting defaults in Media Capture
Some tests of Media Capture were failing as the CaptureAudio/Image/VideoOptions objects did not have defaults set.
2011-05-14 01:10:18 +08:00
Bryce Curtis 839c577243 Need to use EclairClient for 3.x devices too. This fixes the HTML5 geolocation problem on Android 3.x. 2011-05-10 11:44:09 -05:00
macdonst 116169a4c5 Issue #79: FileWriter.seek() is broken in 0.9.5.
The FileEntry.createWriter() method passes in a FileEntry object instead of a File object. As a result the FileWriter.length was not being set properly so when you do a writer.seek(writer.length) it would go to 0, so your next write would overwrite your file.

In order to fix this issue the FileEntry.createWriter() method now makes a call to FileEntry.file() to get the correct file size.  The File object is now passed to the FileWriter constructor.
2011-05-07 00:41:57 +08:00
macdonst 346ed60f0d Android 2.2+ supports W3C Connection API
For Android version 2.2 or better the navigator.connection object already
exists. If this case we should immediately fire the onPhoneGapConnectionReady
event so we don't tie up the 'deviceready' event.
2011-05-06 04:22:38 +08:00
defrex bde59adc04 Add docs and fixed to pass through the Google Closure Compiler without warnings 2011-05-04 16:00:03 -07:00
kernelsandirs ffbc010d7b Added Media.seekTo(int milliseconds); 2011-05-04 11:51:26 -07:00
macdonst bdadbbc339 Implement W3C Network Information API
Adding a new object to navigator called 'connection'.  Users can query the
connection object to find out what type of network, if any, the device is
connected to.  The connection object will be updated each time there is a
connectivity change on the device.
2011-05-04 22:23:16 +08:00
kernelsandirs b94eedaf07 Added Media.seekTo(int milliseconds); 2011-05-03 21:27:08 -07:00
macdonst 58ecac335b Capture modifications:
Renaming supportedAudioFormats to supportedAudioModes.
Renaming supportedImageFormats to supportedImageModes.
Renaming supportedVideoFormats to supportedVideoModes.
Adding copywrite header to the Capture.java file.
2011-05-03 00:12:19 +08:00
macdonst fd8bb2f671 Issue 72: Contact.Save: onSuccess callback is called when contact is not saved. 2011-04-29 02:08:25 +08:00
40 changed files with 1435 additions and 855 deletions
+1
View File
@@ -5,3 +5,4 @@ local.properties
framework/phonegap.jar
framework/bin
framework/assets/www/.DS_Store
.DS_Store
+1 -1
View File
@@ -1 +1 @@
0.9.5
0.9.6
+2 -1
View File
@@ -14,15 +14,16 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
+7 -6
View File
@@ -3,24 +3,25 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("accelerometer")) {
PhoneGap.addResource("accelerometer");
Acceleration = function(x, y, z) {
/** @constructor */
var Acceleration = function(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
this.timestamp = new Date().getTime();
}
};
/**
* This class provides access to device accelerometer data.
* @constructor
*/
Accelerometer = function() {
var Accelerometer = function() {
/**
* The last known acceleration. type=Acceleration()
@@ -31,7 +32,7 @@ Accelerometer = function() {
* List of accelerometer watch timers
*/
this.timers = {};
}
};
Accelerometer.ERROR_MSG = ["Not running", "Starting", "", "Failed to start"];
@@ -122,4 +123,4 @@ PhoneGap.addConstructor(function() {
navigator.accelerometer = new Accelerometer();
}
});
};
}
+8 -7
View File
@@ -11,8 +11,9 @@ PhoneGap.addResource("app");
/**
* Constructor
* @constructor
*/
App = function() {};
var App = function() {};
/**
* Clear the resource cache.
@@ -23,7 +24,7 @@ App.prototype.clearCache = function() {
/**
* Load the url into the webview.
*
*
* @param url The URL to load
* @param props Properties that can be passed in to the activity:
* wait: int => wait msec before loading URL
@@ -33,7 +34,7 @@ App.prototype.clearCache = function() {
* loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error
* errorUrl: URL => URL to load if there's an error loading specified URL with loadUrl(). Should be a local URL such as file:///android_asset/www/error.html");
* keepRunning: boolean => enable app to keep running in background
*
*
* Example:
* App app = new App();
* app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
@@ -59,7 +60,7 @@ App.prototype.clearHistory = function() {
/**
* Add a class that implements a service.
*
*
* @param serviceType
* @param className
*/
@@ -70,10 +71,10 @@ App.prototype.addService = function(serviceType, className) {
/**
* Override the default behavior of the Android back button.
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
*
*
* Note: The user should not have to call this method. Instead, when the user
* registers for the "backbutton" event, this is automatically done.
*
*
* @param override T=override, F=cancel override
*/
App.prototype.overrideBackbutton = function(override) {
@@ -90,4 +91,4 @@ App.prototype.exitApp = function() {
PhoneGap.addConstructor(function() {
navigator.app = window.app = new App();
});
};
}
+3 -3
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("camera")) {
@@ -14,7 +14,7 @@ PhoneGap.addResource("camera");
*
* @constructor
*/
Camera = function() {
var Camera = function() {
this.successCallback = null;
this.errorCallback = null;
this.options = null;
@@ -94,4 +94,4 @@ PhoneGap.addConstructor(function() {
navigator.camera = new Camera();
}
});
};
}
+113 -109
View File
@@ -6,11 +6,58 @@
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("capture")) {
PhoneGap.addResource("capture");
/**
* Represents a single file.
*
* name {DOMString} name of the file, without path information
* fullPath {DOMString} the full path of the file, including the name
* type {DOMString} mime type
* lastModifiedDate {Date} last modified date
* size {Number} size of the file in bytes
*/
var MediaFile = function(name, fullPath, type, lastModifiedDate, size){
this.name = name || null;
this.fullPath = fullPath || null;
this.type = type || null;
this.lastModifiedDate = lastModifiedDate || null;
this.size = size || 0;
};
/**
* Launch device camera application for recording video(s).
*
* @param {Function} successCB
* @param {Function} errorCB
*/
MediaFile.prototype.getFormatData = function(successCallback, errorCallback){
PhoneGap.exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
};
/**
* MediaFileData encapsulates format information of a media file.
*
* @param {DOMString} codecs
* @param {long} bitrate
* @param {long} height
* @param {long} width
* @param {float} duration
*/
var MediaFileData = function(codecs, bitrate, height, width, duration){
this.codecs = codecs || null;
this.bitrate = bitrate || 0;
this.height = height || 0;
this.width = width || 0;
this.duration = duration || 0;
};
/**
* The CaptureError interface encapsulates all errors in the Capture API.
*/
function CaptureError() {
this.code = null;
var CaptureError = function(){
this.code = null;
};
// Capture error codes
@@ -23,165 +70,122 @@ CaptureError.CAPTURE_NOT_SUPPORTED = 20;
/**
* The Capture interface exposes an interface to the camera and microphone of the hosting device.
*/
function Capture() {
this.supportedAudioFormats = [];
this.supportedImageFormats = [];
this.supportedVideoFormats = [];
var Capture = function(){
this.supportedAudioModes = [];
this.supportedImageModes = [];
this.supportedVideoModes = [];
};
/**
* Launch audio recorder application for recording audio clip(s).
*
*
* @param {Function} successCB
* @param {Function} errorCB
* @param {CaptureAudioOptions} options
*/
Capture.prototype.captureAudio = function(successCallback, errorCallback, options) {
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureAudio", [options]);
Capture.prototype.captureAudio = function(successCallback, errorCallback, options){
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureAudio", [options]);
};
/**
* Launch camera application for taking image(s).
*
*
* @param {Function} successCB
* @param {Function} errorCB
* @param {CaptureImageOptions} options
*/
Capture.prototype.captureImage = function(successCallback, errorCallback, options) {
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureImage", [options]);
Capture.prototype.captureImage = function(successCallback, errorCallback, options){
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureImage", [options]);
};
/**
* Launch camera application for taking image(s).
*
*
* @param {Function} successCB
* @param {Function} errorCB
* @param {CaptureImageOptions} options
*/
Capture.prototype._castMediaFile = function(pluginResult) {
var mediaFiles = [];
var i;
for (i=0; i<pluginResult.message.length; i++) {
var mediaFile = new MediaFile();
mediaFile.name = pluginResult.message[i].name;
mediaFile.fullPath = pluginResult.message[i].fullPath;
mediaFile.type = pluginResult.message[i].type;
mediaFile.lastModifiedDate = pluginResult.message[i].lastModifiedDate;
mediaFile.size = pluginResult.message[i].size;
mediaFiles.push(mediaFile);
}
pluginResult.message = mediaFiles;
return pluginResult;
Capture.prototype._castMediaFile = function(pluginResult){
var mediaFiles = [];
var i;
for (i = 0; i < pluginResult.message.length; i++) {
var mediaFile = new MediaFile();
mediaFile.name = pluginResult.message[i].name;
mediaFile.fullPath = pluginResult.message[i].fullPath;
mediaFile.type = pluginResult.message[i].type;
mediaFile.lastModifiedDate = pluginResult.message[i].lastModifiedDate;
mediaFile.size = pluginResult.message[i].size;
mediaFiles.push(mediaFile);
}
pluginResult.message = mediaFiles;
return pluginResult;
};
/**
* Launch device camera application for recording video(s).
*
*
* @param {Function} successCB
* @param {Function} errorCB
* @param {CaptureVideoOptions} options
*/
Capture.prototype.captureVideo = function(successCallback, errorCallback, options) {
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureVideo", [options]);
Capture.prototype.captureVideo = function(successCallback, errorCallback, options){
PhoneGap.exec(successCallback, errorCallback, "Capture", "captureVideo", [options]);
};
/**
* Encapsulates a set of parameters that the capture device supports.
*/
function ConfigurationData() {
// The ASCII-encoded string in lower case representing the media type.
this.type;
// The height attribute represents height of the image or video in pixels.
// In the case of a sound clip this attribute has value 0.
this.height = 0;
// The width attribute represents width of the image or video in pixels.
// In the case of a sound clip this attribute has value 0
this.width = 0;
var ConfigurationData = function(){
// The ASCII-encoded string in lower case representing the media type.
this.type = null;
// The height attribute represents height of the image or video in pixels.
// In the case of a sound clip this attribute has value 0.
this.height = 0;
// The width attribute represents width of the image or video in pixels.
// In the case of a sound clip this attribute has value 0
this.width = 0;
};
/**
* Encapsulates all image capture operation configuration options.
*/
function CaptureImageOptions() {
// Upper limit of images user can take. Value must be equal or greater than 1.
this.limit = 1;
// The selected image mode. Must match with one of the elements in supportedImageModes array.
this.mode;
var CaptureImageOptions = function(){
// Upper limit of images user can take. Value must be equal or greater than 1.
this.limit = 1;
// The selected image mode. Must match with one of the elements in supportedImageModes array.
this.mode = null;
};
/**
* Encapsulates all video capture operation configuration options.
*/
function CaptureVideoOptions() {
// Upper limit of videos user can record. Value must be equal or greater than 1.
this.limit;
// Maximum duration of a single video clip in seconds.
this.duration;
// The selected video mode. Must match with one of the elements in supportedVideoModes array.
this.mode;
var CaptureVideoOptions = function(){
// Upper limit of videos user can record. Value must be equal or greater than 1.
this.limit = 1;
// Maximum duration of a single video clip in seconds.
this.duration = 0;
// The selected video mode. Must match with one of the elements in supportedVideoModes array.
this.mode = null;
};
/**
* Encapsulates all audio capture operation configuration options.
*/
function CaptureAudioOptions() {
// Upper limit of sound clips user can record. Value must be equal or greater than 1.
this.limit;
// Maximum duration of a single sound clip in seconds.
this.duration;
// The selected audio mode. Must match with one of the elements in supportedAudioModes array.
this.mode;
var CaptureAudioOptions = function(){
// Upper limit of sound clips user can record. Value must be equal or greater than 1.
this.limit = 1;
// Maximum duration of a single sound clip in seconds.
this.duration = 0;
// The selected audio mode. Must match with one of the elements in supportedAudioModes array.
this.mode = null;
};
/**
* Represents a single file.
*
* name {DOMString} name of the file, without path information
* fullPath {DOMString} the full path of the file, including the name
* type {DOMString} mime type
* lastModifiedDate {Date} last modified date
* size {Number} size of the file in bytes
*/
function MediaFile(name, fullPath, type, lastModifiedDate, size) {
this.name = name || null;
this.fullPath = fullPath || null;
this.type = type || null;
this.lastModifiedDate = lastModifiedDate || null;
this.size = size || 0;
}
/**
* Launch device camera application for recording video(s).
*
* @param {Function} successCB
* @param {Function} errorCB
*/
MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
};
/**
* MediaFileData encapsulates format information of a media file.
*
* @param {DOMString} codecs
* @param {long} bitrate
* @param {long} height
* @param {long} width
* @param {float} duration
*/
function MediaFileData(codecs, bitrate, height, width, duration) {
this.codecs = codecs || null;
this.bitrate = bitrate || 0;
this.height = height || 0;
this.width = width || 0;
this.duration = duration || 0;
}
PhoneGap.addConstructor(function() {
if (typeof navigator.device === "undefined") {
navigator.device = window.device = new Device();
}
if (typeof navigator.device.capture === "undefined") {
navigator.device.capture = window.device.capture = new Capture();
}
PhoneGap.addConstructor(function(){
if (typeof navigator.device === "undefined") {
navigator.device = window.device = new Device();
}
if (typeof navigator.device.capture === "undefined") {
navigator.device.capture = window.device.capture = new Capture();
}
});
}
+3 -3
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("compass")) {
@@ -13,7 +13,7 @@ PhoneGap.addResource("compass");
* This class provides access to device Compass data.
* @constructor
*/
Compass = function() {
var Compass = function() {
/**
* The last known Compass position.
*/
@@ -116,4 +116,4 @@ PhoneGap.addConstructor(function() {
navigator.compass = new Compass();
}
});
};
}
+22 -14
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("contact")) {
@@ -11,22 +11,23 @@ PhoneGap.addResource("contact");
/**
* Contains information about a single contact.
* @constructor
* @param {DOMString} id unique identifier
* @param {DOMString} displayName
* @param {ContactName} name
* @param {DOMString} nickname
* @param {ContactField[]} phoneNumbers array of phone numbers
* @param {ContactField[]} emails array of email addresses
* @param {ContactAddress[]} addresses array of addresses
* @param {ContactField[]} ims instant messaging user ids
* @param {ContactOrganization[]} organizations
* @param {Array.<ContactField>} phoneNumbers array of phone numbers
* @param {Array.<ContactField>} emails array of email addresses
* @param {Array.<ContactAddress>} addresses array of addresses
* @param {Array.<ContactField>} ims instant messaging user ids
* @param {Array.<ContactOrganization>} organizations
* @param {DOMString} revision date contact was last updated
* @param {DOMString} birthday contact's birthday
* @param {DOMString} gender contact's gender
* @param {DOMString} note user notes about contact
* @param {ContactField[]} photos
* @param {ContactField[]} categories
* @param {ContactField[]} urls contact's web sites
* @param {Array.<ContactField>} photos
* @param {Array.<ContactField>} categories
* @param {Array.<ContactField>} urls contact's web sites
* @param {DOMString} timezone the contacts time zone
*/
var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
@@ -53,7 +54,8 @@ var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, a
/**
* ContactError.
* An error code assigned by an implementation when an error has occurred
* An error code assigned by an implementation when an error has occurreds
* @constructor
*/
var ContactError = function() {
this.code=null;
@@ -152,6 +154,7 @@ Contact.prototype.save = function(successCB, errorCB) {
/**
* Contact name.
* @constructor
* @param formatted
* @param familyName
* @param givenName
@@ -170,6 +173,7 @@ var ContactName = function(formatted, familyName, givenName, middle, prefix, suf
/**
* Generic contact field.
* @constructor
* @param {DOMString} id unique identifier, should only be set by native code
* @param type
* @param value
@@ -184,6 +188,7 @@ var ContactField = function(type, value, pref) {
/**
* Contact address.
* @constructor
* @param {DOMString} id unique identifier, should only be set by native code
* @param formatted
* @param streetAddress
@@ -204,6 +209,7 @@ var ContactAddress = function(formatted, streetAddress, locality, region, postal
/**
* Contact organization.
* @constructor
* @param {DOMString} id unique identifier, should only be set by native code
* @param name
* @param dept
@@ -222,6 +228,7 @@ var ContactOrganization = function(name, dept, title) {
/**
* Represents a group of Contacts.
* @constructor
*/
var Contacts = function() {
this.inProgress = false;
@@ -258,10 +265,10 @@ Contacts.prototype.create = function(properties) {
};
/**
* 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
* This function returns and array of contacts. It is required as we need to convert raw
* JSON objects into concrete Contact objects. Currently this method is called after
* navigator.service.contacts.find but before the find methods success call back.
*
*
* @param jsonArray an array of JSON Objects that need to be converted to Contact objects.
* @returns an array of Contact objects
*/
@@ -277,6 +284,7 @@ Contacts.prototype.cast = function(pluginResult) {
/**
* ContactFindOptions.
* @constructor
* @param filter used to match contacts against
* @param multiple boolean used to determine if more than one contact should be returned
* @param updatedSince return only contact records that have been updated on or after the given time
@@ -298,4 +306,4 @@ PhoneGap.addConstructor(function() {
navigator.service.contacts = new Contacts();
}
});
};
}
+5 -2
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
// TODO: Needs to be commented
@@ -11,6 +11,9 @@
if (!PhoneGap.hasResource("crypto")) {
PhoneGap.addResource("crypto");
/**
* @constructor
*/
var Crypto = function() {
};
@@ -37,4 +40,4 @@ PhoneGap.addConstructor(function() {
navigator.Crypto = new Crypto();
}
});
};
}
+5 -5
View File
@@ -14,7 +14,7 @@ PhoneGap.addResource("device");
* phone, etc.
* @constructor
*/
Device = function() {
var Device = function() {
this.available = PhoneGap.available;
this.platform = null;
this.version = null;
@@ -72,7 +72,7 @@ Device.prototype.getInfo = function(successCallback, errorCallback) {
*/
Device.prototype.overrideBackButton = function() {
console.log("Device.overrideBackButton() is deprecated. Use App.overrideBackbutton(true).");
app.overrideBackbutton(true);
navigator.app.overrideBackbutton(true);
};
/*
@@ -83,7 +83,7 @@ Device.prototype.overrideBackButton = function() {
*/
Device.prototype.resetBackButton = function() {
console.log("Device.resetBackButton() is deprecated. Use App.overrideBackbutton(false).");
app.overrideBackbutton(false);
navigator.app.overrideBackbutton(false);
};
/*
@@ -94,7 +94,7 @@ Device.prototype.resetBackButton = function() {
*/
Device.prototype.exitApp = function() {
console.log("Device.exitApp() is deprecated. Use App.exitApp().");
app.exitApp();
navigator.app.exitApp();
};
PhoneGap.addConstructor(function() {
@@ -102,4 +102,4 @@ PhoneGap.addConstructor(function() {
navigator.device = window.device = new Device();
}
});
};
}
+231 -226
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("file")) {
@@ -11,10 +11,11 @@ PhoneGap.addResource("file");
/**
* This class provides some useful information about a file.
* This is the fields returned when navigator.fileMgr.getFileProperties()
* This is the fields returned when navigator.fileMgr.getFileProperties()
* is called.
* @constructor
*/
FileProperties = function(filePath) {
var FileProperties = function(filePath) {
this.filePath = filePath;
this.size = 0;
this.lastModifiedDate = null;
@@ -22,14 +23,15 @@ FileProperties = function(filePath) {
/**
* Represents a single file.
*
* name {DOMString} name of the file, without path information
* fullPath {DOMString} the full path of the file, including the name
* type {DOMString} mime type
* lastModifiedDate {Date} last modified date
* size {Number} size of the file in bytes
*
* @constructor
* @param name {DOMString} name of the file, without path information
* @param fullPath {DOMString} the full path of the file, including the name
* @param type {DOMString} mime type
* @param lastModifiedDate {Date} last modified date
* @param size {Number} size of the file in bytes
*/
File = function(name, fullPath, type, lastModifiedDate, size) {
var File = function(name, fullPath, type, lastModifiedDate, size) {
this.name = name || null;
this.fullPath = fullPath || null;
this.type = type || null;
@@ -37,7 +39,8 @@ File = function(name, fullPath, type, lastModifiedDate, size) {
this.size = size || 0;
};
FileError = function() {
/** @constructor */
var FileError = function() {
this.code = null;
};
@@ -62,7 +65,8 @@ FileError.PATH_EXISTS_ERR = 12;
// File manager
//-----------------------------------------------------------------------------
FileMgr = function() {
/** @constructor */
var FileMgr = function() {
};
FileMgr.prototype.getFileProperties = function(filePath) {
@@ -126,8 +130,9 @@ PhoneGap.addConstructor(function() {
* For Android:
* The root directory is the root of the file system.
* To read from the SD card, the file name is "sdcard/my_file.txt"
* @constructor
*/
FileReader = function() {
var FileReader = function() {
this.fileName = "";
this.readyState = 0;
@@ -164,7 +169,7 @@ FileReader.prototype.abort = function() {
var error = new FileError();
error.code = error.ABORT_ERR;
this.error = error;
// If error callback
if (typeof this.onerror === "function") {
this.onerror({"type":"error", "target":this});
@@ -244,9 +249,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
}
// Save error
var fileError = new FileError();
fileError.code = e;
me.error = fileError;
me.error = e;
// If onerror callback
if (typeof me.onerror === "function") {
@@ -328,9 +331,7 @@ FileReader.prototype.readAsDataURL = function(file) {
}
// Save error
var fileError = new FileError();
fileError.code = e;
me.error = fileError;
me.error = e;
// If onerror callback
if (typeof me.onerror === "function") {
@@ -378,11 +379,12 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
* For Android:
* The root directory is the root of the file system.
* To write to the SD card, the file name is "sdcard/my_file.txt"
*
*
* @constructor
* @param file {File} File object containing file properties
* @param append if true write to the end of the file, otherwise overwrite the file
*/
FileWriter = function(file) {
var FileWriter = function(file) {
this.fileName = "";
this.length = 0;
if (file) {
@@ -420,13 +422,13 @@ FileWriter.prototype.abort = function() {
// check for invalid state
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
throw FileError.INVALID_STATE_ERR;
}
}
// set error
var error = new FileError(), evt;
error.code = error.ABORT_ERR;
this.error = error;
// If error callback
if (typeof this.onerror === "function") {
this.onerror({"type":"error", "target":this});
@@ -435,7 +437,7 @@ FileWriter.prototype.abort = function() {
if (typeof this.onabort === "function") {
this.oneabort({"type":"abort", "target":this});
}
this.readyState = FileWriter.DONE;
// If write end callback
@@ -446,7 +448,7 @@ FileWriter.prototype.abort = function() {
/**
* Writes data to the file
*
*
* @param text to be written
*/
FileWriter.prototype.write = function(text) {
@@ -476,10 +478,10 @@ FileWriter.prototype.write = function(text) {
return;
}
// So if the user wants to keep appending to the file
me.length = Math.max(me.length, me.position + r);
// position always increases by bytes written because file would be extended
me.position += r;
// The length of the file is now where we are done writing.
me.length = me.position;
// If onwrite callback
if (typeof me.onwrite === "function") {
@@ -505,9 +507,7 @@ FileWriter.prototype.write = function(text) {
}
// Save error
var fileError = new FileError();
fileError.code = e;
me.error = fileError;
me.error = e;
// If onerror callback
if (typeof me.onerror === "function") {
@@ -526,13 +526,13 @@ FileWriter.prototype.write = function(text) {
};
/**
/**
* Moves the file pointer to the location specified.
*
* If the offset is a negative number the position of the file
* pointer is rewound. If the offset is greater than the file
* size the position is set to the end of the file.
*
*
* If the offset is a negative number the position of the file
* pointer is rewound. If the offset is greater than the file
* size the position is set to the end of the file.
*
* @param offset is the location to move the file pointer to.
*/
FileWriter.prototype.seek = function(offset) {
@@ -544,12 +544,12 @@ FileWriter.prototype.seek = function(offset) {
if (!offset) {
return;
}
// See back from end of file.
if (offset < 0) {
this.position = Math.max(offset + this.length, 0);
}
// Offset is bigger then file size so set position
// Offset is bigger then file size so set position
// to the end of the file.
else if (offset > this.length) {
this.position = this.length;
@@ -558,12 +558,12 @@ FileWriter.prototype.seek = function(offset) {
// to start writing.
else {
this.position = offset;
}
}
};
/**
/**
* Truncates the file to the size specified.
*
*
* @param size to chop the file at.
*/
FileWriter.prototype.truncate = function(size) {
@@ -620,9 +620,7 @@ FileWriter.prototype.truncate = function(size) {
}
// Save error
var fileError = new FileError();
fileError.code = e;
me.error = fileError;
me.error = e;
// If onerror callback
if (typeof me.onerror === "function") {
@@ -640,169 +638,69 @@ FileWriter.prototype.truncate = function(size) {
);
};
LocalFileSystem = function() {
};
// File error codes
LocalFileSystem.TEMPORARY = 0;
LocalFileSystem.PERSISTENT = 1;
LocalFileSystem.RESOURCE = 2;
LocalFileSystem.APPLICATION = 3;
/**
* Requests a filesystem in which to store application data.
*
* @param {int} type of file system being requested
* @param {Function} successCallback is called with the new FileSystem
* @param {Function} errorCallback is called with a FileError
*/
LocalFileSystem.prototype.requestFileSystem = function(type, size, successCallback, errorCallback) {
if (type < 0 || type > 3) {
if (typeof errorCallback == "function") {
errorCallback({
"code": FileError.SYNTAX_ERR
});
}
}
else {
PhoneGap.exec(successCallback, errorCallback, "File", "requestFileSystem", [type, size]);
}
};
/**
*
* @param {DOMString} uri referring to a local file in a filesystem
* @param {Function} successCallback is called with the new entry
* @param {Function} errorCallback is called with a FileError
*/
LocalFileSystem.prototype.resolveLocalFileSystemURI = function(uri, successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "resolveLocalFileSystemURI", [uri]);
};
/**
* This function returns and array of contacts. It is required as we need to convert raw
* JSON objects into concrete Contact objects. Currently this method is called after
* navigator.service.contacts.find but before the find methods success call back.
*
* @param a JSON Objects that need to be converted to DirectoryEntry or FileEntry objects.
* @returns an entry
*/
LocalFileSystem.prototype._castFS = function(pluginResult) {
var entry = null;
entry = new DirectoryEntry();
entry.isDirectory = pluginResult.message.root.isDirectory;
entry.isFile = pluginResult.message.root.isFile;
entry.name = pluginResult.message.root.name;
entry.fullPath = pluginResult.message.root.fullPath;
pluginResult.message.root = entry;
return pluginResult;
}
LocalFileSystem.prototype._castEntry = function(pluginResult) {
var entry = null;
if (pluginResult.message.isDirectory) {
console.log("This is a dir");
entry = new DirectoryEntry();
}
else if (pluginResult.message.isFile) {
console.log("This is a file");
entry = new FileEntry();
}
entry.isDirectory = pluginResult.message.isDirectory;
entry.isFile = pluginResult.message.isFile;
entry.name = pluginResult.message.name;
entry.fullPath = pluginResult.message.fullPath;
pluginResult.message = entry;
return pluginResult;
}
LocalFileSystem.prototype._castEntries = function(pluginResult) {
var entries = pluginResult.message;
var retVal = [];
for (i=0; i<entries.length; i++) {
retVal.push(window.localFileSystem._createEntry(entries[i]));
}
pluginResult.message = retVal;
return pluginResult;
}
LocalFileSystem.prototype._createEntry = function(castMe) {
var entry = null;
if (castMe.isDirectory) {
console.log("This is a dir");
entry = new DirectoryEntry();
}
else if (castMe.isFile) {
console.log("This is a file");
entry = new FileEntry();
}
entry.isDirectory = castMe.isDirectory;
entry.isFile = castMe.isFile;
entry.name = castMe.name;
entry.fullPath = castMe.fullPath;
return entry;
}
LocalFileSystem.prototype._castDate = function(pluginResult) {
if (pluginResult.message.modificationTime) {
var modTime = new Date(pluginResult.message.modificationTime);
pluginResult.message.modificationTime = modTime;
}
else if (pluginResult.message.lastModifiedDate) {
var file = new File();
file.size = pluginResult.message.size;
file.type = pluginResult.message.type;
file.name = pluginResult.message.name;
file.fullPath = pluginResult.message.fullPath;
file.lastModifedDate = new Date(pluginResult.message.lastModifiedDate);
pluginResult.message = file;
}
return pluginResult;
}
/**
* Information about the state of the file or directory
*
*
* @constructor
* {Date} modificationTime (readonly)
*/
Metadata = function() {
var Metadata = function() {
this.modificationTime=null;
};
/**
* Supplies arguments to methods that lookup or create files and directories
*
* @param {boolean} create file or directory if it doesn't exist
*
* @constructor
* @param {boolean} create file or directory if it doesn't exist
* @param {boolean} exclusive if true the command will fail if the file or directory exists
*/
Flags = function(create, exclusive) {
var Flags = function(create, exclusive) {
this.create = create || false;
this.exclusive = exclusive || false;
};
/**
* An interface representing a file system
*
*
* @constructor
* {DOMString} name the unique name of the file system (readonly)
* {DirectoryEntry} root directory of the file system (readonly)
*/
FileSystem = function() {
var FileSystem = function() {
this.name = null;
this.root = null;
};
/**
* An interface that lists the files and directories in a directory.
* @constructor
*/
var DirectoryReader = function(fullPath){
this.fullPath = fullPath || null;
};
/**
* Returns a list of entries from a directory.
*
* @param {Function} successCallback is called with a list of entries
* @param {Function} errorCallback is called with a FileError
*/
DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "readEntries", [this.fullPath]);
};
/**
* An interface representing a directory on the file system.
*
*
* @constructor
* {boolean} isFile always false (readonly)
* {boolean} isDirectory always true (readonly)
* {DOMString} name of the directory, excluding the path leading to it (readonly)
* {DOMString} fullPath the absolute full path to the directory (readonly)
* {FileSystem} filesystem on which the directory resides (readonly)
*/
DirectoryEntry = function() {
var DirectoryEntry = function() {
this.isFile = false;
this.isDirectory = true;
this.name = null;
@@ -812,7 +710,7 @@ DirectoryEntry = function() {
/**
* Copies a directory to a new location
*
*
* @param {DirectoryEntry} parent the directory to which to copy the entry
* @param {DOMString} newName the new name of the entry, defaults to the current name
* @param {Function} successCallback is called with the new entry
@@ -824,7 +722,7 @@ DirectoryEntry.prototype.copyTo = function(parent, newName, successCallback, err
/**
* Looks up the metadata of the entry
*
*
* @param {Function} successCallback is called with a Metadata object
* @param {Function} errorCallback is called with a FileError
*/
@@ -834,7 +732,7 @@ DirectoryEntry.prototype.getMetadata = function(successCallback, errorCallback)
/**
* Gets the parent of the entry
*
*
* @param {Function} successCallback is called with a parent entry
* @param {Function} errorCallback is called with a FileError
*/
@@ -844,7 +742,7 @@ DirectoryEntry.prototype.getParent = function(successCallback, errorCallback) {
/**
* Moves a directory to a new location
*
*
* @param {DirectoryEntry} parent the directory to which to move the entry
* @param {DOMString} newName the new name of the entry, defaults to the current name
* @param {Function} successCallback is called with the new entry
@@ -856,7 +754,7 @@ DirectoryEntry.prototype.moveTo = function(parent, newName, successCallback, err
/**
* Removes the entry
*
*
* @param {Function} successCallback is called with no parameters
* @param {Function} errorCallback is called with a FileError
*/
@@ -866,7 +764,7 @@ DirectoryEntry.prototype.remove = function(successCallback, errorCallback) {
/**
* Returns a URI that can be used to identify this entry.
*
*
* @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
* @return uri
*/
@@ -883,7 +781,7 @@ DirectoryEntry.prototype.createReader = function(successCallback, errorCallback)
/**
* Creates or looks up a directory
*
*
* @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
* @param {Flags} options to create or excluively create the directory
* @param {Function} successCallback is called with the new entry
@@ -895,7 +793,7 @@ DirectoryEntry.prototype.getDirectory = function(path, options, successCallback,
/**
* Creates or looks up a file
*
*
* @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
* @param {Flags} options to create or excluively create the file
* @param {Function} successCallback is called with the new entry
@@ -907,7 +805,7 @@ DirectoryEntry.prototype.getFile = function(path, options, successCallback, erro
/**
* Deletes a directory and all of it's contents
*
*
* @param {Function} successCallback is called with no parameters
* @param {Function} errorCallback is called with a FileError
*/
@@ -915,33 +813,17 @@ DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCall
PhoneGap.exec(successCallback, errorCallback, "File", "removeRecursively", [this.fullPath]);
};
/**
* An interface that lists the files and directories in a directory.
*/
DirectoryReader = function(fullPath){
this.fullPath = fullPath || null;
};
/**
* Returns a list of entries from a directory.
*
* @param {Function} successCallback is called with a list of entries
* @param {Function} errorCallback is called with a FileError
*/
DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "readEntries", [this.fullPath]);
}
/**
* An interface representing a directory on the file system.
*
*
* @constructor
* {boolean} isFile always true (readonly)
* {boolean} isDirectory always false (readonly)
* {DOMString} name of the file, excluding the path leading to it (readonly)
* {DOMString} fullPath the absolute full path to the file (readonly)
* {FileSystem} filesystem on which the directory resides (readonly)
*/
FileEntry = function() {
var FileEntry = function() {
this.isFile = true;
this.isDirectory = false;
this.name = null;
@@ -951,7 +833,7 @@ FileEntry = function() {
/**
* Copies a file to a new location
*
*
* @param {DirectoryEntry} parent the directory to which to copy the entry
* @param {DOMString} newName the new name of the entry, defaults to the current name
* @param {Function} successCallback is called with the new entry
@@ -963,7 +845,7 @@ FileEntry.prototype.copyTo = function(parent, newName, successCallback, errorCal
/**
* Looks up the metadata of the entry
*
*
* @param {Function} successCallback is called with a Metadata object
* @param {Function} errorCallback is called with a FileError
*/
@@ -973,7 +855,7 @@ FileEntry.prototype.getMetadata = function(successCallback, errorCallback) {
/**
* Gets the parent of the entry
*
*
* @param {Function} successCallback is called with a parent entry
* @param {Function} errorCallback is called with a FileError
*/
@@ -983,7 +865,7 @@ FileEntry.prototype.getParent = function(successCallback, errorCallback) {
/**
* Moves a directory to a new location
*
*
* @param {DirectoryEntry} parent the directory to which to move the entry
* @param {DOMString} newName the new name of the entry, defaults to the current name
* @param {Function} successCallback is called with the new entry
@@ -995,7 +877,7 @@ FileEntry.prototype.moveTo = function(parent, newName, successCallback, errorCal
/**
* Removes the entry
*
*
* @param {Function} successCallback is called with no parameters
* @param {Function} errorCallback is called with a FileError
*/
@@ -1005,7 +887,7 @@ FileEntry.prototype.remove = function(successCallback, errorCallback) {
/**
* Returns a URI that can be used to identify this entry.
*
*
* @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
* @return uri
*/
@@ -1015,29 +897,31 @@ FileEntry.prototype.toURI = function(mimeType) {
/**
* Creates a new FileWriter associated with the file that this FileEntry represents.
*
*
* @param {Function} successCallback is called with the new FileWriter
* @param {Function} errorCallback is called with a FileError
*/
FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
var writer = new FileWriter(this.fullPath);
if (writer.fileName == null || writer.fileName == "") {
if (typeof errorCallback == "function") {
errorCallback({
"code": FileError.INVALID_STATE_ERR
});
}
}
if (typeof successCallback == "function") {
successCallback(writer);
}
this.file(function(filePointer) {
var writer = new FileWriter(filePointer);
if (writer.fileName === null || writer.fileName === "") {
if (typeof errorCallback == "function") {
errorCallback({
"code": FileError.INVALID_STATE_ERR
});
}
}
if (typeof successCallback == "function") {
successCallback(writer);
}
}, errorCallback);
};
/**
* Returns a File that represents the current state of the file that this FileEntry represents.
*
*
* @param {Function} successCallback is called with the new File object
* @param {Function} errorCallback is called with a FileError
*/
@@ -1045,6 +929,127 @@ FileEntry.prototype.file = function(successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "getFileMetadata", [this.fullPath]);
};
/** @constructor */
var LocalFileSystem = function() {
};
// File error codes
LocalFileSystem.TEMPORARY = 0;
LocalFileSystem.PERSISTENT = 1;
LocalFileSystem.RESOURCE = 2;
LocalFileSystem.APPLICATION = 3;
/**
* Requests a filesystem in which to store application data.
*
* @param {int} type of file system being requested
* @param {Function} successCallback is called with the new FileSystem
* @param {Function} errorCallback is called with a FileError
*/
LocalFileSystem.prototype.requestFileSystem = function(type, size, successCallback, errorCallback) {
if (type < 0 || type > 3) {
if (typeof errorCallback == "function") {
errorCallback({
"code": FileError.SYNTAX_ERR
});
}
}
else {
PhoneGap.exec(successCallback, errorCallback, "File", "requestFileSystem", [type, size]);
}
};
/**
*
* @param {DOMString} uri referring to a local file in a filesystem
* @param {Function} successCallback is called with the new entry
* @param {Function} errorCallback is called with a FileError
*/
LocalFileSystem.prototype.resolveLocalFileSystemURI = function(uri, successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, "File", "resolveLocalFileSystemURI", [uri]);
};
/**
* This function returns and array of contacts. It is required as we need to convert raw
* JSON objects into concrete Contact objects. Currently this method is called after
* navigator.service.contacts.find but before the find methods success call back.
*
* @param a JSON Objects that need to be converted to DirectoryEntry or FileEntry objects.
* @returns an entry
*/
LocalFileSystem.prototype._castFS = function(pluginResult) {
var entry = null;
entry = new DirectoryEntry();
entry.isDirectory = pluginResult.message.root.isDirectory;
entry.isFile = pluginResult.message.root.isFile;
entry.name = pluginResult.message.root.name;
entry.fullPath = pluginResult.message.root.fullPath;
pluginResult.message.root = entry;
return pluginResult;
};
LocalFileSystem.prototype._castEntry = function(pluginResult) {
var entry = null;
if (pluginResult.message.isDirectory) {
console.log("This is a dir");
entry = new DirectoryEntry();
}
else if (pluginResult.message.isFile) {
console.log("This is a file");
entry = new FileEntry();
}
entry.isDirectory = pluginResult.message.isDirectory;
entry.isFile = pluginResult.message.isFile;
entry.name = pluginResult.message.name;
entry.fullPath = pluginResult.message.fullPath;
pluginResult.message = entry;
return pluginResult;
};
LocalFileSystem.prototype._castEntries = function(pluginResult) {
var entries = pluginResult.message;
var retVal = [];
for (var i=0; i<entries.length; i++) {
retVal.push(window.localFileSystem._createEntry(entries[i]));
}
pluginResult.message = retVal;
return pluginResult;
};
LocalFileSystem.prototype._createEntry = function(castMe) {
var entry = null;
if (castMe.isDirectory) {
console.log("This is a dir");
entry = new DirectoryEntry();
}
else if (castMe.isFile) {
console.log("This is a file");
entry = new FileEntry();
}
entry.isDirectory = castMe.isDirectory;
entry.isFile = castMe.isFile;
entry.name = castMe.name;
entry.fullPath = castMe.fullPath;
return entry;
};
LocalFileSystem.prototype._castDate = function(pluginResult) {
if (pluginResult.message.modificationTime) {
var modTime = new Date(pluginResult.message.modificationTime);
pluginResult.message.modificationTime = modTime;
}
else if (pluginResult.message.lastModifiedDate) {
var file = new File();
file.size = pluginResult.message.size;
file.type = pluginResult.message.type;
file.name = pluginResult.message.name;
file.fullPath = pluginResult.message.fullPath;
file.lastModifiedDate = new Date(pluginResult.message.lastModifiedDate);
pluginResult.message = file;
}
return pluginResult;
};
/**
* Add the FileSystem interface into the browser.
*/
@@ -1055,4 +1060,4 @@ PhoneGap.addConstructor(function() {
if(typeof window.requestFileSystem == "undefined") window.requestFileSystem = pgLocalFileSystem.requestFileSystem;
if(typeof window.resolveLocalFileSystemURI == "undefined") window.resolveLocalFileSystemURI = pgLocalFileSystem.resolveLocalFileSystemURI;
});
};
}
+14 -10
View File
@@ -1,9 +1,9 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("filetransfer")) {
@@ -11,13 +11,15 @@ PhoneGap.addResource("filetransfer");
/**
* FileTransfer uploads a file to a remote server.
* @constructor
*/
FileTransfer = function() {};
var FileTransfer = function() {};
/**
* FileUploadResult
* @constructor
*/
FileUploadResult = function() {
var FileUploadResult = function() {
this.bytesSent = 0;
this.responseCode = null;
this.response = null;
@@ -25,8 +27,9 @@ FileUploadResult = function() {
/**
* FileTransferError
* @constructor
*/
FileTransferError = function() {
var FileTransferError = function() {
this.code = null;
};
@@ -35,13 +38,13 @@ FileTransferError.INVALID_URL_ERR = 2;
FileTransferError.CONNECTION_ERR = 3;
/**
* Given an absolute file path, uploads a file on the device to a remote server
* Given an absolute file path, uploads a file on the device to a remote server
* using a multipart HTTP request.
* @param filePath {String} Full path of the file on the device
* @param server {String} URL of the server to receive the file
* @param successCallback (Function} Callback to be invoked when upload has completed
* @param errorCallback {Function} Callback to be invoked upon error
* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
*/
FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, debug) {
@@ -61,21 +64,22 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
params = {};
}
}
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug]);
};
/**
* Options to customize the HTTP request used to upload files.
* @constructor
* @param fileKey {String} Name of file request parameter.
* @param fileName {String} Filename to be used by the server. Defaults to image.jpg.
* @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg.
* @param params {Object} Object with key: value params to send to the server.
*/
FileUploadOptions = function(fileKey, fileName, mimeType, params) {
var FileUploadOptions = function(fileKey, fileName, mimeType, params) {
this.fileKey = fileKey || null;
this.fileName = fileName || null;
this.mimeType = mimeType || null;
this.params = params || null;
};
};
}
+5 -4
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("geolocation")) {
@@ -13,7 +13,7 @@ PhoneGap.addResource("geolocation");
* This class provides access to device GPS data.
* @constructor
*/
Geolocation = function() {
var Geolocation = function() {
// The last known GPS position.
this.lastPosition = null;
@@ -25,10 +25,11 @@ Geolocation = function() {
/**
* Position error object
*
* @constructor
* @param code
* @param message
*/
PositionError = function(code, message) {
var PositionError = function(code, message) {
this.code = code;
this.message = message;
};
@@ -194,4 +195,4 @@ PhoneGap.addConstructor(function() {
Geolocation.usingPhoneGap = true;
}
});
};
}
+66 -59
View File
@@ -3,69 +3,16 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("media")) {
PhoneGap.addResource("media");
/**
* List of media objects.
* PRIVATE
*/
PhoneGap.mediaObjects = {};
/**
* Object that receives native callbacks.
* PRIVATE
*/
PhoneGap.Media = function() {};
/**
* Get the media object.
* PRIVATE
*
* @param id The media object id (string)
*/
PhoneGap.Media.getMediaObject = function(id) {
return PhoneGap.mediaObjects[id];
};
/**
* Audio has status update.
* PRIVATE
*
* @param id The media object id (string)
* @param status The status code (int)
* @param msg The status message (string)
*/
PhoneGap.Media.onStatus = function(id, msg, value) {
var media = PhoneGap.mediaObjects[id];
// If state update
if (msg === Media.MEDIA_STATE) {
if (value === Media.MEDIA_STOPPED) {
if (media.successCallback) {
media.successCallback();
}
}
if (media.statusCallback) {
media.statusCallback(value);
}
}
else if (msg === Media.MEDIA_DURATION) {
media._duration = value;
}
else if (msg === Media.MEDIA_ERROR) {
if (media.errorCallback) {
media.errorCallback(value);
}
}
};
/**
* This class provides access to the device media, interfaces to both sound and video
*
* @constructor
* @param src The file name or url to play
* @param successCallback The callback to be called when the file is done playing or recording.
* successCallback() - OPTIONAL
@@ -76,7 +23,7 @@ PhoneGap.Media.onStatus = function(id, msg, value) {
* @param positionCallback The callback to be called when media position has changed.
* positionCallback(long position) - OPTIONAL
*/
Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
var Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
// successCallback optional
if (successCallback && (typeof successCallback !== "function")) {
@@ -131,7 +78,7 @@ Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
* This class contains information about any Media errors.
* @constructor
*/
MediaError = function() {
var MediaError = function() {
this.code = null;
this.message = "";
};
@@ -155,6 +102,13 @@ Media.prototype.stop = function() {
return PhoneGap.exec(null, null, "Media", "stopPlayingAudio", [this.id]);
};
/**
* Seek or jump to a new time in the track..
*/
Media.prototype.seekTo = function(milliseconds) {
PhoneGap.exec(null, null, "Media", "seekToAudio", [this.id, milliseconds]);
};
/**
* Pause playing audio file.
*/
@@ -174,8 +128,6 @@ Media.prototype.getDuration = function() {
/**
* Get position of audio.
*
* @return
*/
Media.prototype.getCurrentPosition = function(success, fail) {
PhoneGap.exec(success, fail, "Media", "getCurrentPositionAudio", [this.id]);
@@ -201,4 +153,59 @@ Media.prototype.stopRecord = function() {
Media.prototype.release = function() {
PhoneGap.exec(null, null, "Media", "release", [this.id]);
};
/**
* List of media objects.
* PRIVATE
*/
PhoneGap.mediaObjects = {};
/**
* Object that receives native callbacks.
* PRIVATE
* @constructor
*/
PhoneGap.Media = function() {};
/**
* Get the media object.
* PRIVATE
*
* @param id The media object id (string)
*/
PhoneGap.Media.getMediaObject = function(id) {
return PhoneGap.mediaObjects[id];
};
/**
* Audio has status update.
* PRIVATE
*
* @param id The media object id (string)
* @param status The status code (int)
* @param msg The status message (string)
*/
PhoneGap.Media.onStatus = function(id, msg, value) {
var media = PhoneGap.mediaObjects[id];
// If state update
if (msg === Media.MEDIA_STATE) {
if (value === Media.MEDIA_STOPPED) {
if (media.successCallback) {
media.successCallback();
}
}
if (media.statusCallback) {
media.statusCallback(value);
}
}
else if (msg === Media.MEDIA_DURATION) {
media._duration = value;
}
else if (msg === Media.MEDIA_ERROR) {
if (media.errorCallback) {
media.errorCallback(value);
}
}
};
}
+69 -4
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("network")) {
@@ -13,7 +13,7 @@ PhoneGap.addResource("network");
* This class contains information about any NetworkStatus.
* @constructor
*/
NetworkStatus = function() {
var NetworkStatus = function() {
//this.code = null;
//this.message = "";
};
@@ -26,7 +26,7 @@ NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
* This class provides access to device Network data (reachability).
* @constructor
*/
Network = function() {
var Network = function() {
/**
* The last known Network status.
* { hostName: string, ipAddress: string,
@@ -59,9 +59,74 @@ Network.prototype.isReachable = function(uri, callback, options) {
PhoneGap.exec(callback, null, "Network Status", "isReachable", [uri, isIpAddress]);
};
/**
* This class contains information about the current network Connection.
* @constructor
*/
var Connection = function() {
this.type = null;
this._firstRun = true;
this._timer = null;
this.timeout = 500;
var me = this;
this.getInfo(
function(type) {
// Need to send events if we are on or offline
if (type == "none") {
// set a timer if still offline at the end of timer send the offline event
me._timer = setTimeout(function(){
me.type = type;
PhoneGap.fireEvent('offline');
me._timer = null;
}, me.timeout);
} else {
// If there is a current offline event pending clear it
if (me._timer != null) {
clearTimeout(me._timer);
me._timer = null;
}
me.type = type;
PhoneGap.fireEvent('online');
}
// should only fire this once
if (me._firstRun) {
me._firstRun = false;
PhoneGap.onPhoneGapConnectionReady.fire();
}
},
function(e) {
console.log("Error initializing Network Connection: " + e);
});
};
Connection.UNKNOWN = "unknown";
Connection.ETHERNET = "ethernet";
Connection.WIFI = "wifi";
Connection.CELL_2G = "2g";
Connection.CELL_3G = "3g";
Connection.CELL_4G = "4g";
Connection.NONE = "none";
/**
* Get connection info
*
* @param {Function} successCallback The function to call when the Connection data is available
* @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL)
*/
Connection.prototype.getInfo = function(successCallback, errorCallback) {
// Get info
PhoneGap.exec(successCallback, errorCallback, "Network Status", "getConnectionInfo", []);
};
PhoneGap.addConstructor(function() {
if (typeof navigator.network === "undefined") {
navigator.network = new Network();
}
if (typeof navigator.network.connection === "undefined") {
navigator.network.connection = new Connection();
}
});
};
}
+4 -3
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("notification")) {
@@ -11,8 +11,9 @@ PhoneGap.addResource("notification");
/**
* This class provides access to notifications on the device.
* @constructor
*/
Notification = function() {
var Notification = function() {
};
/**
@@ -118,4 +119,4 @@ PhoneGap.addConstructor(function() {
navigator.notification = new Notification();
}
});
};
}
+86 -74
View File
@@ -1,7 +1,7 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010-2011, IBM Corporation
*/
@@ -33,7 +33,7 @@ if (typeof PhoneGap === "undefined") {
*/
if (typeof(DeviceInfo) !== 'object') {
DeviceInfo = {};
var DeviceInfo = {};
}
/**
@@ -76,6 +76,7 @@ PhoneGap.addResource = function(name) {
/**
* Custom pub-sub channel that can have functions subscribed to it
* @constructor
*/
PhoneGap.Channel = function (type)
{
@@ -87,7 +88,7 @@ PhoneGap.Channel = function (type)
};
/**
* Subscribes the given function to the channel. Any time that
* Subscribes the given function to the channel. Any time that
* Channel.fire is called so too will the function.
* Optionally specify an execution context for the function
* and a guid that can be used to stop subscribing to the channel.
@@ -98,7 +99,7 @@ PhoneGap.Channel.prototype.subscribe = function(f, c, g) {
if (f === null) { return; }
var func = f;
if (typeof c === "object" && f instanceof Function) { func = PhoneGap.close(c, f); }
if (typeof c === "object" && typeof f === "function") { func = PhoneGap.close(c, f); }
g = g || func.observer_guid || f.observer_guid || this.guid++;
func.observer_guid = g;
@@ -119,7 +120,7 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
_this.unsubscribe(g);
};
if (this.fired) {
if (typeof c === "object" && f instanceof Function) { f = PhoneGap.close(c, f); }
if (typeof c === "object" && typeof f === "function") { f = PhoneGap.close(c, f); }
f.apply(this, this.fireArgs);
} else {
g = this.subscribe(m);
@@ -127,16 +128,16 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
return g;
};
/**
/**
* Unsubscribes the function with the given guid from the channel.
*/
PhoneGap.Channel.prototype.unsubscribe = function(g) {
if (g instanceof Function) { g = g.observer_guid; }
if (typeof g === "function") { g = g.observer_guid; }
this.handlers[g] = null;
delete this.handlers[g];
};
/**
/**
* Calls all functions subscribed to this channel.
*/
PhoneGap.Channel.prototype.fire = function(e) {
@@ -146,7 +147,7 @@ PhoneGap.Channel.prototype.fire = function(e) {
for (item in this.handlers) {
if (this.handlers.hasOwnProperty(item)) {
handler = this.handlers[item];
if (handler instanceof Function) {
if (typeof handler === "function") {
rv = (handler.apply(this, arguments) === false);
fail = fail || rv;
}
@@ -229,7 +230,7 @@ PhoneGap.addPlugin = function(name, obj) {
};
/**
* onDOMContentLoaded channel is fired when the DOM content
* onDOMContentLoaded channel is fired when the DOM content
* of the page has been parsed.
*/
PhoneGap.onDOMContentLoaded = new PhoneGap.Channel('onDOMContentLoaded');
@@ -257,6 +258,12 @@ PhoneGap.onPhoneGapReady = new PhoneGap.Channel('onPhoneGapReady');
*/
PhoneGap.onPhoneGapInfoReady = new PhoneGap.Channel('onPhoneGapInfoReady');
/**
* onPhoneGapConnectionReady channel is fired when the PhoneGap connection properties
* has been set.
*/
PhoneGap.onPhoneGapConnectionReady = new PhoneGap.Channel('onPhoneGapConnectionReady');
/**
* onResume channel is fired when the PhoneGap native code
* resumes.
@@ -271,7 +278,7 @@ PhoneGap.onPause = new PhoneGap.Channel('onPause');
/**
* onDestroy channel is fired when the PhoneGap native code
* is destroyed. It is used internally.
* is destroyed. It is used internally.
* Window.onunload should be used by the user.
*/
PhoneGap.onDestroy = new PhoneGap.Channel('onDestroy');
@@ -281,7 +288,7 @@ PhoneGap.onDestroy.subscribeOnce(function() {
PhoneGap.shuttingDown = false;
// _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
// to signify that the native code is ready. It is a global since
// it may be called before any PhoneGap JS is ready.
if (typeof _nativeReady !== 'undefined') { PhoneGap.onNativeReady.fire(); }
@@ -293,7 +300,7 @@ PhoneGap.onDeviceReady = new PhoneGap.Channel('onDeviceReady');
// Array of channels that must fire before "deviceready" is fired
PhoneGap.deviceReadyChannelsArray = [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady];
PhoneGap.deviceReadyChannelsArray = [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady, PhoneGap.onPhoneGapConnectionReady];
// Hashtable of user defined channels that must also fire before "deviceready" is fired
PhoneGap.deviceReadyChannelsMap = {};
@@ -317,7 +324,7 @@ PhoneGap.waitForInitialization = function(feature) {
* Indicate that initialization code has completed and the feature is ready to be used.
*
* @param feature {String} The unique feature name
*/
*/
PhoneGap.initializationComplete = function(feature) {
var channel = PhoneGap.deviceReadyChannelsMap[feature];
if (channel) {
@@ -337,10 +344,13 @@ PhoneGap.Channel.join(function() {
}
else {
var polling = prompt("usePolling", "gap_callbackServer:");
PhoneGap.UsePolling = polling;
if (polling == "true") {
PhoneGap.UsePolling = true;
PhoneGap.JSCallbackPolling();
}
else {
PhoneGap.UsePolling = false;
PhoneGap.JSCallback();
}
}
@@ -355,7 +365,7 @@ PhoneGap.Channel.join(function() {
// Fire onDeviceReady event once all constructors have run and PhoneGap info has been
// received from native side, and any user defined initialization channels.
PhoneGap.Channel.join(function() {
// Turn off app loading dialog
navigator.notification.activityStop();
@@ -386,18 +396,18 @@ document.addEventListener = function(evt, handler, capture) {
}
} else if (e === 'pause') {
PhoneGap.onPause.subscribe(handler);
}
}
else {
// If subscribing to Android backbutton
if (e === 'backbutton') {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [true]);
}
}
PhoneGap.m_document_addEventListener.call(document, evt, handler, capture);
}
};
// Intercept calls to document.removeEventListener and watch for events that
// Intercept calls to document.removeEventListener and watch for events that
// are generated by PhoneGap native code
PhoneGap.m_document_removeEventListener = document.removeEventListener;
@@ -407,7 +417,7 @@ document.removeEventListener = function(evt, handler, capture) {
// If unsubscribing to Android backbutton
if (e === 'backbutton') {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [false]);
}
}
PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
};
@@ -426,14 +436,14 @@ PhoneGap.fireEvent = function(type) {
* The restriction on ours is that it must be an array of simple types.
*
* @param args
* @return
* @return {String}
*/
PhoneGap.stringify = function(args) {
if (typeof JSON === "undefined") {
var s = "[";
var i, type, start, name, nameType, a;
for (i = 0; i < args.length; i++) {
if (args[i] != null) {
if (args[i] !== null) {
if (i > 0) {
s = s + ",";
}
@@ -458,7 +468,7 @@ PhoneGap.stringify = function(args) {
// don't copy the functions
s = s + '""';
} else if (args[i][name] instanceof Object) {
s = s + this.stringify(args[i][name]);
s = s + PhoneGap.stringify(args[i][name]);
} else {
s = s + '"' + args[i][name] + '"';
}
@@ -484,41 +494,41 @@ PhoneGap.stringify = function(args) {
* Does a deep clone of the object.
*
* @param obj
* @return
* @return {Object}
*/
PhoneGap.clone = function(obj) {
var i, retVal;
if(!obj) {
return obj;
}
if(obj instanceof Array){
retVal = [];
for(i = 0; i < obj.length; ++i){
retVal.push(PhoneGap.clone(obj[i]));
}
return retVal;
}
if (obj instanceof Function) {
return obj;
}
if(!(obj instanceof Object)){
return obj;
}
if(!obj) {
return obj;
}
if(obj instanceof Array){
retVal = [];
for(i = 0; i < obj.length; ++i){
retVal.push(PhoneGap.clone(obj[i]));
}
return retVal;
}
if (typeof obj === "function") {
return obj;
}
if(!(obj instanceof Object)){
return obj;
}
if (obj instanceof Date) {
return obj;
}
retVal = {};
for(i in obj){
if(!(i in retVal) || retVal[i] !== obj[i]) {
retVal[i] = PhoneGap.clone(obj[i]);
}
}
return retVal;
retVal = {};
for(i in obj){
if(!(i in retVal) || retVal[i] !== obj[i]) {
retVal[i] = PhoneGap.clone(obj[i]);
}
}
return retVal;
};
PhoneGap.callbackId = 0;
@@ -538,7 +548,7 @@ PhoneGap.callbackStatus = {
/**
* Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
* Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
* The native side can return:
* Synchronous: PluginResult object as a JSON string
* Asynchrounous: Empty string ""
@@ -549,7 +559,7 @@ PhoneGap.callbackStatus = {
* @param {Function} fail The fail callback
* @param {String} service The name of the service to use
* @param {String} action Action to be run in PhoneGap
* @param {String[]} [args] Zero or more arguments to pass to the method
* @param {Array.<String>} [args] Zero or more arguments to pass to the method
*/
PhoneGap.exec = function(success, fail, service, action, args) {
try {
@@ -557,13 +567,13 @@ PhoneGap.exec = function(success, fail, service, action, args) {
if (success || fail) {
PhoneGap.callbacks[callbackId] = {success:success, fail:fail};
}
var r = prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
var r = prompt(PhoneGap.stringify(args), "gap:"+PhoneGap.stringify([service, action, callbackId, true]));
// If a result was returned
if (r.length > 0) {
eval("var v="+r+";");
// If status is OK, then return value back to caller
if (v.status === PhoneGap.callbackStatus.OK) {
@@ -586,7 +596,7 @@ PhoneGap.exec = function(success, fail, service, action, args) {
// If no result
else if (v.status === PhoneGap.callbackStatus.NO_RESULT) {
// Clear callback if not expecting any more results
if (!v.keepCallback) {
delete PhoneGap.callbacks[callbackId];
@@ -639,7 +649,7 @@ PhoneGap.callbackSuccess = function(callbackId, args) {
console.log("Error in success callback: "+callbackId+" = "+e);
}
}
// Clear callback if not expecting any more results
if (!args.keepCallback) {
delete PhoneGap.callbacks[callbackId];
@@ -663,7 +673,7 @@ PhoneGap.callbackError = function(callbackId, args) {
catch (e) {
console.log("Error in error callback: "+callbackId+" = "+e);
}
// Clear callback if not expecting any more results
if (!args.keepCallback) {
delete PhoneGap.callbacks[callbackId];
@@ -729,7 +739,7 @@ PhoneGap.JSCallbackToken = null;
/**
* This is only for Android.
*
* Internal function that uses XHR to call into PhoneGap Java code and retrieve
* Internal function that uses XHR to call into PhoneGap Java code and retrieve
* any JavaScript code that needs to be run. This is used for callbacks from
* Java to JavaScript.
*/
@@ -751,7 +761,7 @@ PhoneGap.JSCallback = function() {
// Callback function when XMLHttpRequest is ready
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState === 4){
// Exit if shutting down app
if (PhoneGap.shuttingDown) {
return;
@@ -760,8 +770,8 @@ PhoneGap.JSCallback = function() {
// If callback has JavaScript statement to execute
if (xmlhttp.status === 200) {
// Need to url decode the response and replace %20 with a space
var msg = decodeURIComponent(xmlhttp.responseText.replace(/\+/g, '%20'));
// Need to url decode the response
var msg = decodeURIComponent(xmlhttp.responseText);
setTimeout(function() {
try {
var t = eval(msg);
@@ -795,13 +805,11 @@ PhoneGap.JSCallback = function() {
console.log("JSCallback Error: Bad request. Stopping callbacks.");
}
// If error, restart callback server
// If error, revert to polling
else {
console.log("JSCallback Error: Request failed.");
prompt("restartServer", "gap_callbackServer:");
PhoneGap.JSCallbackPort = null;
PhoneGap.JSCallbackToken = null;
setTimeout(PhoneGap.JSCallback, 100);
PhoneGap.UsePolling = true;
PhoneGap.JSCallbackPolling();
}
}
};
@@ -830,7 +838,7 @@ PhoneGap.UsePolling = false; // T=use polling, F=use XHR
/**
* This is only for Android.
*
* Internal function that uses polling to call into PhoneGap Java code and retrieve
* Internal function that uses polling to call into PhoneGap Java code and retrieve
* any JavaScript code that needs to be run. This is used for callbacks from
* Java to JavaScript.
*/
@@ -868,7 +876,7 @@ PhoneGap.JSCallbackPolling = function() {
/**
* Create a UUID
*
* @return
* @return {String}
*/
PhoneGap.createUUID = function() {
return PhoneGap.UUIDcreatePart(4) + '-' +
@@ -910,7 +918,7 @@ PhoneGap.close = function(context, func, params) {
* @param {Function} successCallback The callback to call when the file has been loaded.
*/
PhoneGap.includeJavascript = function(jsfile, successCallback) {
var id = document.getElementsByTagName("head")[0];
var id = document.getElementsByTagName("head")[0];
var el = document.createElement('script');
el.type = 'text/javascript';
if (typeof successCallback === 'function') {
@@ -928,8 +936,12 @@ PhoneGap.includeJavascript = function(jsfile, successCallback) {
*/
var PluginManager = {
addService: function(serviceType, className) {
navigator.app.addService(serviceType, className);
try {
navigator.app.addService(serviceType, className);
} catch (e) {
console.log("Error adding service "+serviceType+": "+e);
}
}
};
};
}
+8 -7
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("position")) {
@@ -20,12 +20,13 @@ PhoneGap.addResource("position");
* @param {Object} vel
* @constructor
*/
Position = function(coords, timestamp) {
var Position = function(coords, timestamp) {
this.coords = coords;
this.timestamp = (timestamp !== 'undefined') ? timestamp : new Date().getTime();
};
Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
/** @constructor */
var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
/**
* The latitude of the position.
*/
@@ -53,14 +54,14 @@ Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
/**
* The altitude accuracy of the position.
*/
this.altitudeAccuracy = (altacc !== 'undefined') ? altacc : null;
this.altitudeAccuracy = (altacc !== 'undefined') ? altacc : null;
};
/**
* This class specifies the options for requesting position data.
* @constructor
*/
PositionOptions = function() {
var PositionOptions = function() {
/**
* Specifies the desired position accuracy.
*/
@@ -76,7 +77,7 @@ PositionOptions = function() {
* This class contains information about any GSP errors.
* @constructor
*/
PositionError = function() {
var PositionError = function() {
this.code = null;
this.message = "";
};
@@ -85,4 +86,4 @@ PositionError.UNKNOWN_ERROR = 0;
PositionError.PERMISSION_DENIED = 1;
PositionError.POSITION_UNAVAILABLE = 2;
PositionError.TIMEOUT = 3;
};
}
+114 -96
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
/*
@@ -15,9 +15,39 @@
if (!PhoneGap.hasResource("storage")) {
PhoneGap.addResource("storage");
/**
* SQL result set object
* PRIVATE METHOD
* @constructor
*/
var DroidDB_Rows = function() {
this.resultSet = []; // results array
this.length = 0; // number of rows
};
/**
* Get item from SQL result set
*
* @param row The row number to return
* @return The row object
*/
DroidDB_Rows.prototype.item = function(row) {
return this.resultSet[row];
};
/**
* SQL result set that is returned to user.
* PRIVATE METHOD
* @constructor
*/
var DroidDB_Result = function() {
this.rows = new DroidDB_Rows();
};
/**
* Storage object that is called by native code when performing queries.
* PRIVATE METHOD
* @constructor
*/
var DroidDB = function() {
this.queryQueue = {};
@@ -102,9 +132,40 @@ DroidDB.prototype.fail = function(reason, id) {
}
};
/**
* SQL query object
* PRIVATE METHOD
*
* @constructor
* @param tx The transaction object that this query belongs to
*/
var DroidDB_Query = function(tx) {
// Set the id of the query
this.id = PhoneGap.createUUID();
// Add this query to the queue
droiddb.queryQueue[this.id] = this;
// Init result
this.resultSet = [];
// Set transaction that this query belongs to
this.tx = tx;
// Add this query to transaction list
this.tx.queryList[this.id] = this;
// Callbacks
this.successCallback = null;
this.errorCallback = null;
};
/**
* Transaction object
* PRIVATE METHOD
* @constructor
*/
var DroidDB_Tx = function() {
@@ -119,37 +180,6 @@ var DroidDB_Tx = function() {
this.queryList = {};
};
var DatabaseShell = function() {
};
/**
* Start a transaction.
* Does not support rollback in event of failure.
*
* @param process {Function} The transaction function
* @param successCallback {Function}
* @param errorCallback {Function}
*/
DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
var tx = new DroidDB_Tx();
tx.successCallback = successCallback;
tx.errorCallback = errorCallback;
try {
process(tx);
} catch (e) {
console.log("Transaction error: "+e);
if (tx.errorCallback) {
try {
tx.errorCallback(e);
} catch (ex) {
console.log("Transaction error calling user error callback: "+e);
}
}
}
};
/**
* Mark query in transaction as complete.
* If all queries are complete, call the user's transaction success callback.
@@ -165,7 +195,7 @@ DroidDB_Tx.prototype.queryComplete = function(id) {
var i;
for (i in this.queryList) {
if (this.queryList.hasOwnProperty(i)) {
count++;
count++;
}
}
if (count === 0) {
@@ -201,35 +231,6 @@ DroidDB_Tx.prototype.queryFailed = function(id, reason) {
}
};
/**
* SQL query object
* PRIVATE METHOD
*
* @param tx The transaction object that this query belongs to
*/
var DroidDB_Query = function(tx) {
// Set the id of the query
this.id = PhoneGap.createUUID();
// Add this query to the queue
droiddb.queryQueue[this.id] = this;
// Init result
this.resultSet = [];
// Set transaction that this query belongs to
this.tx = tx;
// Add this query to transaction list
this.tx.queryList[this.id] = this;
// Callbacks
this.successCallback = null;
this.errorCallback = null;
};
/**
* Execute SQL statement
*
@@ -257,31 +258,33 @@ DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCa
PhoneGap.exec(null, null, "Storage", "executeSql", [sql, params, query.id]);
};
/**
* SQL result set that is returned to user.
* PRIVATE METHOD
*/
DroidDB_Result = function() {
this.rows = new DroidDB_Rows();
var DatabaseShell = function() {
};
/**
* SQL result set object
* PRIVATE METHOD
*/
DroidDB_Rows = function() {
this.resultSet = []; // results array
this.length = 0; // number of rows
};
/**
* Get item from SQL result set
* Start a transaction.
* Does not support rollback in event of failure.
*
* @param row The row number to return
* @return The row object
* @param process {Function} The transaction function
* @param successCallback {Function}
* @param errorCallback {Function}
*/
DroidDB_Rows.prototype.item = function(row) {
return this.resultSet[row];
DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
var tx = new DroidDB_Tx();
tx.successCallback = successCallback;
tx.errorCallback = errorCallback;
try {
process(tx);
} catch (e) {
console.log("Transaction error: "+e);
if (tx.errorCallback) {
try {
tx.errorCallback(e);
} catch (ex) {
console.log("Transaction error calling user error callback: "+e);
}
}
}
};
/**
@@ -293,22 +296,24 @@ DroidDB_Rows.prototype.item = function(row) {
* @param size Database size in bytes
* @return Database object
*/
DroidDB_openDatabase = function(name, version, display_name, size) {
var DroidDB_openDatabase = function(name, version, display_name, size) {
PhoneGap.exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
var db = new DatabaseShell();
return db;
};
/**
* For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
* TODO: Do similar for sessionStorage.
* For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
* TODO: Do similar for sessionStorage.
*/
/**
* @constructor
*/
var CupcakeLocalStorage = function() {
try {
this.db = openDatabase('localStorage', '1.0', 'localStorage', 2621440);
this.db = openDatabase('localStorage', '1.0', 'localStorage', 2621440);
var storage = {};
this.length = 0;
function setLength (length) {
@@ -326,8 +331,8 @@ var CupcakeLocalStorage = function() {
setLength(result.rows.length);
PhoneGap.initializationComplete("cupcakeStorage");
});
},
},
function (err) {
alert(err.message);
}
@@ -344,7 +349,7 @@ var CupcakeLocalStorage = function() {
}
);
};
this.getItem = function(key) {
this.getItem = function(key) {
return storage[key];
};
this.removeItem = function(key) {
@@ -377,28 +382,41 @@ var CupcakeLocalStorage = function() {
}
}
return null;
}
};
} catch(e) {
alert("Database error "+e+".");
return;
}
};
PhoneGap.addConstructor(function() {
var setupDroidDB = function() {
navigator.openDatabase = window.openDatabase = DroidDB_openDatabase;
window.droiddb = new DroidDB();
}
if ((typeof window.openDatabase === "undefined") || (navigator.userAgent.indexOf("Android 3.0") != -1)) {
if (typeof window.openDatabase === "undefined") {
setupDroidDB();
} else {
window.openDatabase_orig = window.openDatabase;
window.openDatabase = function(name, version, desc, size) {
var db = window.openDatabase_orig(name, version, desc, size);
window.openDatabase = function(name, version, desc, size){
// Some versions of Android will throw a SECURITY_ERR so we need
// to catch the exception and seutp our own DB handling.
var db = null;
try {
db = window.openDatabase_orig(name, version, desc, size);
}
catch (ex) {
db = null;
}
if (db == null) {
setupDroidDB();
return DroidDB_openDatabase(name, version, desc, size);
} else return db;
}
else {
return db;
}
}
}
@@ -407,4 +425,4 @@ PhoneGap.addConstructor(function() {
PhoneGap.waitForInitialization("cupcakeStorage");
}
});
};
}
+1 -1
View File
@@ -10,5 +10,5 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-8
target=android-12
apk-configurations=
-27
View File
@@ -1,27 +0,0 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.phonegap;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
public static final int splash=0x7f020001;
}
public static final class id {
public static final int appView=0x7f050000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040000;
public static final int go=0x7f040001;
}
}
+24 -7
View File
@@ -63,6 +63,9 @@ public class AudioHandler extends Plugin {
else if (action.equals("startPlayingAudio")) {
this.startPlayingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("seekToAudio")) {
this.seekToAudio(args.getString(0), args.getInt(1));
}
else if (action.equals("pausePlayingAudio")) {
this.pausePlayingAudio(args.getString(0));
}
@@ -70,12 +73,12 @@ public class AudioHandler extends Plugin {
this.stopPlayingAudio(args.getString(0));
}
else if (action.equals("getCurrentPositionAudio")) {
long l = this.getCurrentPositionAudio(args.getString(0));
return new PluginResult(status, l);
float f = this.getCurrentPositionAudio(args.getString(0));
return new PluginResult(status, f);
}
else if (action.equals("getDurationAudio")) {
long l = this.getDurationAudio(args.getString(0), args.getString(1));
return new PluginResult(status, l);
float f = this.getDurationAudio(args.getString(0), args.getString(1));
return new PluginResult(status, f);
}
else if (action.equals("release")) {
boolean b = this.release(args.getString(0));
@@ -181,6 +184,20 @@ public class AudioHandler extends Plugin {
audio.startPlaying(file);
}
/**
* Seek to a location.
*
*
* @param id The id of the audio player
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
*/
public void seekToAudio(String id, int milliseconds) {
AudioPlayer audio = this.players.get(id);
if (audio != null) {
audio.seekToPlaying(milliseconds);
}
}
/**
* Pause playing.
*
@@ -213,10 +230,10 @@ public class AudioHandler extends Plugin {
* @param id The id of the audio player
* @return position in msec
*/
public long getCurrentPositionAudio(String id) {
public float getCurrentPositionAudio(String id) {
AudioPlayer audio = this.players.get(id);
if (audio != null) {
return(audio.getCurrentPosition());
return(audio.getCurrentPosition()/1000.0f);
}
return -1;
}
@@ -228,7 +245,7 @@ public class AudioHandler extends Plugin {
* @param file The name of the audio file.
* @return The duration in msec.
*/
public long getDurationAudio(String id, String file) {
public float getDurationAudio(String id, String file) {
// Get audio file
AudioPlayer audio = this.players.get(id);
+24 -8
View File
@@ -15,6 +15,7 @@ import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaRecorder;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Environment;
/**
* This class implements the audio playback and recording capabilities used by PhoneGap.
@@ -53,7 +54,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
private String id; // The id of this player (used to identify Media object in JavaScript)
private int state = MEDIA_NONE; // State of recording or playback
private String audioFile = null; // File name to play or record to
private long duration = -1; // Duration of audio
private float duration = -1; // Duration of audio
private MediaRecorder recorder = null; // Audio recording object
private String tempFile = null; // Temporary recording file name
@@ -70,10 +71,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public AudioPlayer(AudioHandler handler, String id) {
this.handler = handler;
this.id = id;
// YES, I know this is bad, but I can't do it the right way because Google didn't have the
// foresight to add android.os.environment.getExternalDataDirectory until Android 2.2
this.tempFile = "/sdcard/tmprecording.mp3";
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
}
/**
@@ -209,7 +207,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.mPlayer.prepare();
// Get duration
this.duration = this.mPlayer.getDuration();
this.duration = getDurationInSeconds();
}
}
catch (Exception e) {
@@ -233,6 +231,15 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
}
}
/**
* Seek or jump to a new time in the track.
*/
public void seekToPlaying(int milliseconds) {
if (this.mPlayer != null) {
this.mPlayer.seekTo(milliseconds);
}
}
/**
* Pause playing.
*/
@@ -310,7 +317,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* -1=can't be determined
* -2=not allowed
*/
public long getDuration(String file) {
public float getDuration(String file) {
// Can't get duration of recording
if (this.recorder != null) {
@@ -353,7 +360,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
}
// Save off duration
this.duration = this.mPlayer.getDuration();
this.duration = getDurationInSeconds();
this.prepareOnly = false;
// Send status notification to JavaScript
@@ -361,6 +368,15 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
}
/**
* By default Android returns the length of audio in mills but we want seconds
*
* @return length of clip in seconds
*/
private float getDurationInSeconds() {
return (this.mPlayer.getDuration() / 1000.0f);
}
/**
* Callback to be invoked when there has been an error during an asynchronous operation
* (other errors will throw exceptions at method call time).
+85 -2
View File
@@ -11,11 +11,14 @@ import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLEncoder;
import java.util.LinkedList;
import android.util.Log;
/**
* This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap.
* The CallbackServer class implements an XHR server and a polling server with a list of JavaScript
@@ -42,6 +45,8 @@ import java.util.LinkedList;
*/
public class CallbackServer implements Runnable {
private static final String LOG_TAG = "CallbackServer";
/**
* The list of JavaScript statements to be sent to JavaScript.
*/
@@ -224,8 +229,9 @@ public class CallbackServer implements Runnable {
//System.out.println("CallbackServer -- sending item");
response = "HTTP/1.1 200 OK\r\n\r\n";
String js = this.getJavascript();
if (js != null)
response += URLEncoder.encode(js, "UTF-8");
if (js != null) {
response += encode(js, "UTF-8");
}
}
}
else {
@@ -321,4 +327,81 @@ public class CallbackServer implements Runnable {
}
}
/* The Following code has been modified from original implementation of URLEncoder */
/* start */
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
static final String digits = "0123456789ABCDEF";
/**
* This will encode the return value to JavaScript. We revert the encoding for
* common characters that don't require encoding to reduce the size of the string
* being passed to JavaScript.
*
* @param s to be encoded
* @param enc encoding type
* @return encoded string
*/
public static String encode(String s, String enc) throws UnsupportedEncodingException {
if (s == null || enc == null) {
throw new NullPointerException();
}
// check for UnsupportedEncodingException
"".getBytes(enc);
// Guess a bit bigger for encoded form
StringBuilder buf = new StringBuilder(s.length() + 16);
int start = -1;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| " .-*_'(),<>=?@[]{}:~\"\\/;!".indexOf(ch) > -1) {
if (start >= 0) {
convert(s.substring(start, i), buf, enc);
start = -1;
}
if (ch != ' ') {
buf.append(ch);
} else {
buf.append(' ');
}
} else {
if (start < 0) {
start = i;
}
}
}
if (start >= 0) {
convert(s.substring(start, s.length()), buf, enc);
}
return buf.toString();
}
private static void convert(String s, StringBuilder buf, String enc) throws UnsupportedEncodingException {
byte[] bytes = s.getBytes(enc);
for (int j = 0; j < bytes.length; j++) {
buf.append('%');
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
buf.append(digits.charAt(bytes[j] & 0xf));
}
}
/* end */
}
@@ -166,7 +166,14 @@ public class CameraLauncher extends Plugin {
if (resultCode == Activity.RESULT_OK) {
try {
// Read in bitmap of captured image
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
} catch (FileNotFoundException e) {
Uri uri = intent.getData();
android.content.ContentResolver resolver = this.ctx.getContentResolver();
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
}
// If sending base64 image back
if (destType == DATA_URL) {
+7
View File
@@ -1,3 +1,10 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2011, IBM Corporation
*/
package com.phonegap;
import java.io.File;
@@ -178,11 +178,13 @@ public abstract class ContactAccessor {
protected String getJsonString(JSONObject obj, String property) {
String value = null;
try {
if (obj != null) {
value = obj.getString(property);
if (value.equals("null")) {
Log.d(LOG_TAG, property + " is string called 'null'");
value = null;
}
if (value.equals("null")) {
Log.d(LOG_TAG, property + " is string called 'null'");
value = null;
}
}
}
catch (JSONException e) {
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
@@ -1420,7 +1420,6 @@ public class ContactAccessorSdk5 extends ContactAccessor {
.build());
}
// Add urls
JSONArray websites = null;
try {
@@ -1473,7 +1472,6 @@ public class ContactAccessorSdk5 extends ContactAccessor {
Log.e(LOG_TAG, e.getMessage(), e);
retVal = false;
}
return retVal;
}
@@ -46,7 +46,14 @@ public class ContactManager extends Plugin {
return new PluginResult(status, res, "navigator.service.contacts.cast");
}
else if (action.equals("save")) {
return new PluginResult(status, contactAccessor.save(args.getJSONObject(0)));
if (contactAccessor.save(args.getJSONObject(0))) {
return new PluginResult(status, result);
}
else {
JSONObject r = new JSONObject();
r.put("code", 0);
return new PluginResult(PluginResult.Status.ERROR, r);
}
}
else if (action.equals("remove")) {
if (contactAccessor.remove(args.getString(0))) {
+4 -28
View File
@@ -14,9 +14,7 @@ import org.json.JSONObject;
import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import android.content.Context;
import android.provider.Settings;
import android.telephony.TelephonyManager;
public class Device extends Plugin {
@@ -116,34 +114,13 @@ public class Device extends Plugin {
public String getPhonegapVersion() {
return Device.phonegapVersion;
}
public String getLine1Number(){
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
return operator.getLine1Number();
}
public String getDeviceId(){
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
return operator.getDeviceId();
}
public String getSimSerialNumber(){
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
return operator.getSimSerialNumber();
}
public String getSubscriberId(){
TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE);
return operator.getSubscriberId();
}
public String getModel()
{
public String getModel() {
String model = android.os.Build.MODEL;
return model;
}
public String getProductName()
{
public String getProductName() {
String productname = android.os.Build.PRODUCT;
return productname;
}
@@ -158,8 +135,7 @@ public class Device extends Plugin {
return osversion;
}
public String getSDKVersion()
{
public String getSDKVersion() {
String sdkversion = android.os.Build.VERSION.SDK;
return sdkversion;
}
+205 -38
View File
@@ -9,36 +9,45 @@ package com.phonegap;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.app.AlertDialog;
import android.widget.EditText;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginManager;
import com.phonegap.api.PhonegapActivity;
/**
* This class is the main Android activity that represents the PhoneGap
@@ -119,14 +128,19 @@ public class DroidGap extends PhonegapActivity {
protected boolean clearHistory = false;
// The initial URL for our app
// ie http://server/path/index.html#abc?query
private String url;
// The initial URL for our app up to and including the file name
// ie http://server/path/index.html
private String urlFile;
// The base of the initial URL for our app
private String baseUrl;
// Plugin to call when activity result is received
private Plugin activityResultCallback = null;
private boolean activityResultKeepRunning;
protected Plugin activityResultCallback = null;
protected boolean activityResultKeepRunning;
// Flag indicates that a loadUrl timeout occurred
private int loadUrlTimeout = 0;
@@ -168,7 +182,11 @@ public class DroidGap extends PhonegapActivity {
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
root = new LinearLayout(this);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
root = new LinearLayoutSoftKeyboardDetect(this, width, height);
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(Color.BLACK);
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
@@ -202,11 +220,11 @@ public class DroidGap extends PhonegapActivity {
WebViewReflect.checkCompatibility();
if (android.os.Build.VERSION.RELEASE.startsWith("2.")) {
this.appView.setWebChromeClient(new EclairClient(DroidGap.this));
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
this.appView.setWebChromeClient(new GapClient(DroidGap.this));
}
else {
this.appView.setWebChromeClient(new GapClient(DroidGap.this));
this.appView.setWebChromeClient(new EclairClient(DroidGap.this));
}
this.setWebViewClient(this.appView, new GapViewClient(this));
@@ -330,6 +348,7 @@ public class DroidGap extends PhonegapActivity {
*/
public void loadUrl(final String url) {
System.out.println("loadUrl("+url+")");
this.urlFile = this.getUrlFile(url);
this.url = url;
int i = url.lastIndexOf('/');
if (i > 0) {
@@ -608,17 +627,28 @@ public class DroidGap extends PhonegapActivity {
// Send pause event to JavaScript
this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
// Forward to plugins
this.pluginManager.onPause(this.keepRunning);
// If app doesn't want to run in background
if (!this.keepRunning) {
// Forward to plugins
this.pluginManager.onPause();
// Pause JavaScript timers (including setInterval)
this.appView.pauseTimers();
}
}
@Override
/**
* Called when the activity receives a new intent
**/
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//Forward to plugins
this.pluginManager.onNewIntent(intent);
}
@Override
/**
* Called when the activity will start interacting with the user.
@@ -632,6 +662,9 @@ public class DroidGap extends PhonegapActivity {
// Send resume event to JavaScript
this.appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};");
// Forward to plugins
this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
// If app doesn't want to run in background
if (!this.keepRunning || this.activityResultKeepRunning) {
@@ -641,9 +674,6 @@ public class DroidGap extends PhonegapActivity {
this.activityResultKeepRunning = false;
}
// Forward to plugins
this.pluginManager.onResume();
// Resume JavaScript timers (including setInterval)
this.appView.resumeTimers();
}
@@ -658,21 +688,18 @@ public class DroidGap extends PhonegapActivity {
if (this.appView != null) {
// Make sure pause event is sent if onPause hasn't been called before onDestroy
this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
// Make sure pause event is sent if onPause hasn't been called before onDestroy
this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
// Send destroy event to JavaScript
this.appView.loadUrl("javascript:try{PhoneGap.onDestroy.fire();}catch(e){};");
// Send destroy event to JavaScript
this.appView.loadUrl("javascript:try{PhoneGap.onDestroy.fire();}catch(e){};");
// Load blank page so that JavaScript onunload is called
this.appView.loadUrl("about:blank");
// Load blank page so that JavaScript onunload is called
this.appView.loadUrl("about:blank");
// Forward to plugins
this.pluginManager.onDestroy();
// Forward to plugins
this.pluginManager.onDestroy();
if (this.callbackServer != null) {
this.callbackServer.destroy();
}
}
}
@@ -696,13 +723,29 @@ public class DroidGap extends PhonegapActivity {
this.callbackServer.sendJavascript(statement);
}
/**
* Return up to file part of url.
* If url = http://server/page.html#abc, then return http://server/page.html
*
* @param url
* @return
*/
private String getUrlFile(String url) {
int p1 = url.indexOf("#");
int p2 = url.indexOf("?");
if (p1 < 0) p1 = url.length();
if (p2 < 0) p2 = url.length();
int p3 = (p1 < p2) ? p1 : p2;
return url.substring(0, p3);
}
/**
* Provides a hook for calling "alert" from javascript. Useful for
* debugging your javascript.
*/
public class GapClient extends WebChromeClient {
private Context ctx;
private DroidGap ctx;
/**
* Constructor.
@@ -710,7 +753,7 @@ public class DroidGap extends PhonegapActivity {
* @param ctx
*/
public GapClient(Context ctx) {
this.ctx = ctx;
this.ctx = (DroidGap)ctx;
}
/**
@@ -782,10 +825,14 @@ public class DroidGap extends PhonegapActivity {
*/
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
boolean reqOk = false;
if (this.ctx.urlFile.equals(this.ctx.getUrlFile(url))) {
reqOk = true;
}
// Calling PluginManager.exec() to call a native service using
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
if (defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
JSONArray array;
try {
array = new JSONArray(defaultValue.substring(4));
@@ -801,13 +848,13 @@ public class DroidGap extends PhonegapActivity {
}
// Polling for JavaScript messages
else if (defaultValue.equals("gap_poll:")) {
else if (reqOk && defaultValue.equals("gap_poll:")) {
String r = callbackServer.getJavascript();
result.confirm(r);
}
// Calling into CallbackServer
else if (defaultValue.equals("gap_callbackServer:")) {
else if (reqOk && defaultValue.equals("gap_callbackServer:")) {
String r = "";
if (message.equals("usePolling")) {
r = ""+callbackServer.usePolling();
@@ -850,13 +897,13 @@ public class DroidGap extends PhonegapActivity {
}
return true;
}
}
/**
* WebChromeClient that extends GapClient with additional support for Android 2.X
*/
public final class EclairClient extends GapClient {
public class EclairClient extends GapClient {
private String TAG = "PhoneGapLog";
private long MAX_QUOTA = 100 * 1024 * 1024;
@@ -910,6 +957,12 @@ public class DroidGap extends PhonegapActivity {
}
@Override
/**
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
*
* @param origin
* @param callback
*/
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
// TODO Auto-generated method stub
super.onGeolocationPermissionsShowPrompt(origin, callback);
@@ -1059,7 +1112,9 @@ public class DroidGap extends PhonegapActivity {
// Try firing the onNativeReady event in JS. If it fails because the JS is
// not loaded yet then just set a flag so that the onNativeReady can be fired
// from the JS side when the JS gets to that code.
appView.loadUrl("javascript:try{ PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}");
if (!url.equals("about:blank")) {
appView.loadUrl("javascript:try{ PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}");
}
// Make app view visible
appView.setVisibility(View.VISIBLE);
@@ -1075,6 +1130,13 @@ public class DroidGap extends PhonegapActivity {
this.ctx.clearHistory = false;
this.ctx.appView.clearHistory();
}
// Shutdown if blank loaded
if (url.equals("about:blank")) {
if (this.ctx.callbackServer != null) {
this.ctx.callbackServer.destroy();
}
}
}
/**
@@ -1099,6 +1161,27 @@ public class DroidGap extends PhonegapActivity {
// Handle error
this.ctx.onReceivedError(errorCode, description, failingUrl);
}
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
final String packageName = this.ctx.getPackageName();
final PackageManager pm = this.ctx.getPackageManager();
ApplicationInfo appInfo;
try {
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// debug = true
handler.proceed();
return;
} else {
// debug = false
super.onReceivedSslError(view, handler, error);
}
} catch (NameNotFoundException e) {
// When it doubt, lock it out!
super.onReceivedSslError(view, handler, error);
}
}
}
/**
@@ -1119,6 +1202,7 @@ public class DroidGap extends PhonegapActivity {
// If back key is bound, then send event to JavaScript
if (this.bound) {
this.appView.loadUrl("javascript:PhoneGap.fireEvent('backbutton');");
return true;
}
// If not bound
@@ -1127,6 +1211,7 @@ public class DroidGap extends PhonegapActivity {
// Go to previous page in webview if it is possible to go back
if (this.appView.canGoBack()) {
this.appView.goBack();
return true;
}
// If not, then invoke behavior of super class
@@ -1139,11 +1224,13 @@ public class DroidGap extends PhonegapActivity {
// If menu key
else if (keyCode == KeyEvent.KEYCODE_MENU) {
this.appView.loadUrl("javascript:PhoneGap.fireEvent('menubutton');");
return true;
}
// If search key
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
this.appView.loadUrl("javascript:PhoneGap.fireEvent('searchbutton');");
return true;
}
return false;
@@ -1270,4 +1357,84 @@ public class DroidGap extends PhonegapActivity {
}
});
}
/**
* We are providing this class to detect when the soft keyboard is shown
* and hidden in the web view.
*/
class LinearLayoutSoftKeyboardDetect extends LinearLayout {
private static final String LOG_TAG = "SoftKeyboardDetect";
private int oldHeight = 0; // Need to save the old height as not to send redundant events
private int oldWidth = 0; // Need to save old width for orientation change
private int screenWidth = 0;
private int screenHeight = 0;
public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
super(context);
screenWidth = width;
screenHeight = height;
}
@Override
/**
* Start listening to new measurement events. Fire events when the height
* gets smaller fire a show keyboard event and when height gets bigger fire
* a hide keyboard event.
*
* Note: We are using callbackServer.sendJavascript() instead of
* this.appView.loadUrl() as changing the URL of the app would cause the
* soft keyboard to go away.
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(LOG_TAG, "We are in our onMeasure method");
// Get the current height of the visible part of the screen.
// This height will not included the status bar.
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
Log.d(LOG_TAG, "Old Height = " + oldHeight);
Log.d(LOG_TAG, "Height = " + height);
Log.d(LOG_TAG, "Old Width = " + oldWidth);
Log.d(LOG_TAG, "Width = " + width);
// If the oldHeight = 0 then this is the first measure event as the app starts up.
// If oldHeight == height then we got a measurement change that doesn't affect us.
if (oldHeight == 0 || oldHeight == height) {
Log.d(LOG_TAG, "Ignore this event");
}
// Account for orientation change and ignore this event/Fire orientation change
else if(screenHeight == width)
{
int tmp_var = screenHeight;
screenHeight = screenWidth;
screenWidth = tmp_var;
Log.d(LOG_TAG, "Orientation Change");
}
// If the height as gotten bigger then we will assume the soft keyboard has
// gone away.
else if (height > oldHeight) {
Log.d(LOG_TAG, "Throw hide keyboard event");
callbackServer.sendJavascript("PhoneGap.fireEvent('hidekeyboard');");
}
// If the height as gotten smaller then we will assume the soft keyboard has
// been displayed.
else if (height < oldHeight) {
Log.d(LOG_TAG, "Throw show keyboard event");
callbackServer.sendJavascript("PhoneGap.fireEvent('showkeyboard');");
}
// Update the old height for the next event
oldHeight = height;
oldWidth = width;
}
}
}
+56 -49
View File
@@ -10,6 +10,7 @@ package com.phonegap;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.channels.FileChannel;
import org.apache.commons.codec.binary.Base64;
@@ -97,48 +98,23 @@ public class FileUtils extends Plugin {
return new PluginResult(status, b);
}
else if (action.equals("readAsText")) {
try {
String s = this.readAsText(args.getString(0), args.getString(1));
return new PluginResult(status, s);
} catch (IOException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_READABLE_ERR);
}
String s = this.readAsText(args.getString(0), args.getString(1));
return new PluginResult(status, s);
}
else if (action.equals("readAsDataURL")) {
try {
String s = this.readAsDataURL(args.getString(0));
return new PluginResult(status, s);
} catch (IOException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_READABLE_ERR);
}
String s = this.readAsDataURL(args.getString(0));
return new PluginResult(status, s);
}
else if (action.equals("writeAsText")) {
try {
this.writeAsText(args.getString(0), args.getString(1), args.getBoolean(2));
} catch (IOException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_READABLE_ERR);
}
this.writeAsText(args.getString(0), args.getString(1), args.getBoolean(2));
}
else if (action.equals("write")) {
try {
long fileSize = this.write(args.getString(0), args.getString(1), args.getLong(2));
return new PluginResult(status, fileSize);
} catch (IOException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_READABLE_ERR);
}
long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
return new PluginResult(status, fileSize);
}
else if (action.equals("truncate")) {
try {
long fileSize = this.truncateFile(args.getString(0), args.getLong(1));
return new PluginResult(status, fileSize);
} catch (IOException e) {
e.printStackTrace();
return new PluginResult(PluginResult.Status.ERROR, FileUtils.NOT_READABLE_ERR);
}
long fileSize = this.truncateFile(args.getString(0), args.getLong(1));
return new PluginResult(status, fileSize);
}
else if (action.equals("requestFileSystem")) {
long size = args.optLong(1);
@@ -254,15 +230,16 @@ public class FileUtils extends Plugin {
* @throws JSONException
*/
private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
String decoded = URLDecoder.decode(url, "UTF-8");
// Test to see if this is a valid URL first
@SuppressWarnings("unused")
URL testUrl = new URL(url);
@SuppressWarnings("unused")
URL testUrl = new URL(decoded);
File fp = null;
if (url.startsWith("file://")) {
fp = new File(url.substring(7, url.length()));
if (decoded.startsWith("file://")) {
fp = new File(decoded.substring(7, decoded.length()));
} else {
fp = new File(url);
fp = new File(decoded);
}
if (!fp.exists()) {
throw new FileNotFoundException();
@@ -436,7 +413,7 @@ public class FileUtils extends Plugin {
}
// Check to make sure we are not copying the directory into itself
if (destinationDir.getAbsolutePath().startsWith(srcDir.getAbsolutePath())) {
if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
throw new InvalidModificationException("Can't copy itself into itself");
}
@@ -460,6 +437,26 @@ public class FileUtils extends Plugin {
return getEntry(destinationDir);
}
/**
* Check to see if the user attempted to copy an entry into its parent without changing its name,
* or attempted to copy a directory into a directory that it contains directly or indirectly.
*
* @param srcDir
* @param destinationDir
* @return
*/
private boolean isCopyOnItself(String src, String dest) {
// This weird test is to determine if we are copying or moving a directory into itself.
// Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
// Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR
if (dest.startsWith(src) && dest.indexOf(File.separator, src.length()-1) != -1) {
return true;
}
return false;
}
/**
* Move a file
*
@@ -505,8 +502,8 @@ public class FileUtils extends Plugin {
}
// Check to make sure we are not copying the directory into itself
if (destinationDir.getAbsolutePath().startsWith(srcDir.getAbsolutePath())) {
throw new InvalidModificationException("Can't copy itself into itself");
if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
throw new InvalidModificationException("Can't move itself into itself");
}
// If the destination directory already exists and is empty then delete it. This is according to spec.
@@ -945,16 +942,26 @@ public class FileUtils extends Plugin {
* @param offset The position to begin writing the file.
* @throws FileNotFoundException, IOException
*/
public long write(String filename, String data, long offset) throws FileNotFoundException, IOException {
RandomAccessFile file = new RandomAccessFile(filename, "rw");
file.seek(offset);
file.writeBytes(data);
file.close();
/**/
public long write(String filename, String data, int offset) throws FileNotFoundException, IOException {
boolean append = false;
if (offset > 0) {
this.truncateFile(filename, offset);
append = true;
}
byte [] rawData = data.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(rawData);
FileOutputStream out = new FileOutputStream(filename, append);
byte buff[] = new byte[rawData.length];
in.read(buff, 0, buff.length);
out.write(buff, 0, rawData.length);
out.flush();
out.close();
return data.length();
}
/**
* Truncate the file to size
*
+156 -8
View File
@@ -3,7 +3,7 @@
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
* Copyright (c) 2010-2011, IBM Corporation
*/
package com.phonegap;
@@ -16,21 +16,55 @@ import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.net.*;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class NetworkManager extends Plugin {
public static int NOT_REACHABLE = 0;
public static int NOT_REACHABLE = 0;
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
public static int REACHABLE_VIA_WIFI_NETWORK = 2;
public static final String WIFI = "wifi";
public static final String WIMAX = "wimax";
// mobile
public static final String MOBILE = "mobile";
// 2G network types
public static final String GSM = "gsm";
public static final String GPRS = "gprs";
public static final String EDGE = "edge";
// 3G network types
public static final String CDMA = "cdma";
public static final String UMTS = "umts";
// 4G network types
public static final String LTE = "lte";
public static final String UMB = "umb";
// return types
public static final String TYPE_UNKNOWN = "unknown";
public static final String TYPE_ETHERNET = "ethernet";
public static final String TYPE_WIFI = "wifi";
public static final String TYPE_2G = "2g";
public static final String TYPE_3G = "3g";
public static final String TYPE_4G = "4g";
public static final String TYPE_NONE = "none";
ConnectivityManager sockMan;
private static final String LOG_TAG = "NetworkManager";
private String connectionCallbackId;
ConnectivityManager sockMan;
BroadcastReceiver receiver;
/**
* Constructor.
*/
public NetworkManager() {
this.receiver = null;
}
/**
@@ -41,9 +75,24 @@ public class NetworkManager extends Plugin {
*/
public void setContext(PhonegapActivity ctx) {
super.setContext(ctx);
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
}
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
this.connectionCallbackId = null;
// We need to listen to connectivity events to update navigator.connection
IntentFilter intentFilter = new IntentFilter() ;
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
if (this.receiver == null) {
this.receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
}
};
ctx.registerReceiver(this.receiver, intentFilter);
}
}
/**
* Executes the request and returns PluginResult.
*
@@ -68,6 +117,13 @@ public class NetworkManager extends Plugin {
int i = this.isReachable(args.getString(0), args.getBoolean(1));
return new PluginResult(status, i);
}
else if (action.equals("getConnectionInfo")) {
this.connectionCallbackId = callbackId;
NetworkInfo info = sockMan.getActiveNetworkInfo();
PluginResult pluginResult = new PluginResult(status, this.getConnectionInfo(info));
pluginResult.setKeepCallback(true);
return pluginResult;
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
@@ -84,12 +140,104 @@ public class NetworkManager extends Plugin {
// All methods take a while, so always use async
return false;
}
/**
* Stop network receiver.
*/
public void onDestroy() {
if (this.receiver != null) {
try {
this.ctx.unregisterReceiver(this.receiver);
} catch (Exception e) {
Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
}
}
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
/**
* Updates the JavaScript side whenever the connection changes
*
* @param info the current active network info
* @return
*/
private void updateConnectionInfo(NetworkInfo info) {
// send update to javascript "navigator.network.connection"
sendUpdate(this.getConnectionInfo(info));
}
/**
* Get the latest network connection information
*
* @param info the current active network info
* @return a JSONObject that represents the network info
*/
private String getConnectionInfo(NetworkInfo info) {
String type = TYPE_NONE;
if (info != null) {
// If we are not connected to any network set type to none
if (!info.isConnected()) {
type = TYPE_NONE;
}
else {
type = getType(info);
}
}
return type;
}
/**
* Create a new plugin result and send it back to JavaScript
*
* @param connection the network info to set as navigator.connection
*/
private void sendUpdate(String type) {
PluginResult result = new PluginResult(PluginResult.Status.OK, type);
result.setKeepCallback(true);
this.success(result, this.connectionCallbackId);
}
/**
* Determine the type of connection
*
* @param info the network info so we can determine connection type.
* @return the type of mobile network we are on
*/
private String getType(NetworkInfo info) {
if (info != null) {
String type = info.getTypeName();
if (type.toLowerCase().equals(WIFI)) {
return TYPE_WIFI;
}
else if (type.toLowerCase().equals(MOBILE)) {
type = info.getSubtypeName();
if (type.toLowerCase().equals(GSM) ||
type.toLowerCase().equals(GPRS) ||
type.toLowerCase().equals(EDGE)) {
return TYPE_2G;
}
else if (type.toLowerCase().equals(CDMA) ||
type.toLowerCase().equals(UMTS)) {
return TYPE_3G;
}
else if (type.toLowerCase().equals(LTE) ||
type.toLowerCase().equals(UMB)) {
return TYPE_4G;
}
}
}
else {
return TYPE_NONE;
}
return TYPE_UNKNOWN;
}
/**
* Determine if a network connection exists.
*
* @return
@@ -127,7 +275,7 @@ public class NetworkManager extends Plugin {
public int isReachable(String uri, boolean isIpAddress) {
int reachable = NOT_REACHABLE;
if (uri.indexOf("http://") == -1) {
if (uri.indexOf("http://") == -1 && uri.indexOf("https://") == -1) {
uri = "http://" + uri;
}
+6 -2
View File
@@ -54,13 +54,17 @@ public interface IPlugin {
/**
* Called when the system is about to start resuming a previous activity.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
void onPause();
void onPause(boolean multitasking);
/**
* Called when the activity will start interacting with the user.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
void onResume();
void onResume(boolean multitasking);
/**
* The final call you receive before your activity is destroyed.
+12 -2
View File
@@ -64,14 +64,24 @@ public abstract class Plugin implements IPlugin {
/**
* Called when the system is about to start resuming a previous activity.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
public void onPause() {
public void onPause(boolean multitasking) {
}
/**
* Called when the activity will start interacting with the user.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
public void onResume() {
public void onResume(boolean multitasking) {
}
/**
* Called when the activity receives a new intent.
*/
public void onNewIntent(Intent intent) {
}
/**
@@ -13,6 +13,7 @@ import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.Intent;
import android.webkit.WebView;
/**
@@ -229,27 +230,31 @@ public final class PluginManager {
/**
* Called when the system is about to start resuming a previous activity.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
public void onPause() {
public void onPause(boolean multitasking) {
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Plugin> entry = it.next();
Plugin plugin = entry.getValue();
plugin.onPause();
plugin.onPause(multitasking);
}
}
/**
* Called when the activity will start interacting with the user.
*
* @param multitasking Flag indicating if multitasking is turned on for app
*/
public void onResume() {
public void onResume(boolean multitasking) {
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Plugin> entry = it.next();
Plugin plugin = entry.getValue();
plugin.onResume();
plugin.onResume(multitasking);
}
}
@@ -265,4 +270,17 @@ public final class PluginManager {
plugin.onDestroy();
}
}
/**
* Called when the activity receives a new intent.
*/
public void onNewIntent(Intent intent) {
java.util.Set<Entry<String,Plugin>> s = this.plugins.entrySet();
java.util.Iterator<Entry<String,Plugin>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Plugin> entry = it.next();
Plugin plugin = entry.getValue();
plugin.onNewIntent(intent);
}
}
}
+14 -14
View File
@@ -5,7 +5,7 @@ class Classic
@android_sdk_path, @name, @pkg, @www, @path = a
build
end
def build
setup
clobber
@@ -16,8 +16,8 @@ class Classic
copy_libs
add_name_to_strings
write_java
end
end
def setup
@android_dir = File.expand_path(File.dirname(__FILE__).gsub(/lib$/,''))
@framework_dir = File.join(@android_dir, "framework")
@@ -31,14 +31,14 @@ class Classic
@app_js_dir = ''
@content = 'index.html'
end
# replaces @path with new android project
def clobber
FileUtils.rm_r(@path) if File.exists? @path
FileUtils.mkdir_p @path
end
# removes local.properties and recreates based on android_sdk_path
# removes local.properties and recreates based on android_sdk_path
# then generates framework/phonegap.jar
def build_jar
%w(local.properties phonegap.js phonegap.jar).each do |f|
@@ -46,7 +46,7 @@ class Classic
end
open(File.join(@framework_dir, "local.properties"), 'w') do |f|
f.puts "sdk.dir=#{ @android_sdk_path }"
end
end
Dir.chdir(@framework_dir)
`ant jar`
Dir.chdir(@android_dir)
@@ -55,9 +55,9 @@ class Classic
# runs android create project
# TODO need to allow more flexible SDK targetting via config.xml
def create_android
IO.popen("android list targets") { |f|
IO.popen("android list targets") { |f|
targets = f.readlines(nil)[0].scan(/id\:.*$/)
if (targets.length > 0)
if (targets.length > 0)
target_id = targets.last.match(/\d+/).to_a.first
`android create project -t #{ target_id } -k #{ @pkg } -a #{ @name } -n #{ @name } -p #{ @path }`
else
@@ -66,7 +66,7 @@ class Classic
end
}
end
# copies the project/www folder into tmp/android/www
def include_www
FileUtils.mkdir_p File.join(@path, "assets", "www")
@@ -127,7 +127,7 @@ class Classic
end
File.open(File.join(@path, "assets", "www", @app_js_dir, "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) }
end
# puts app name in strings
def add_name_to_strings
x = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
@@ -138,8 +138,8 @@ class Classic
"
open(File.join(@path, "res", "values", "strings.xml"), 'w') do |f|
f.puts x.gsub(' ','')
end
end
end
end
# create java source file
def write_java
@@ -164,7 +164,7 @@ class Classic
FileUtils.mkdir_p(code_dir)
open(File.join(code_dir, "#{ @name }.java"),'w') { |f| f.puts j }
end
# friendly output for now
def msg
puts "Created #{ @path }"
+18 -18
View File
@@ -1,5 +1,5 @@
# Create
#
#
# Generates an Android project from a valid WWW directory and puts it in ../[PROJECT NAME]_android
#
class Create < Classic
@@ -8,35 +8,35 @@ class Create < Classic
read_config
build
end
def guess_paths(path)
# if no path is supplied uses current directory for project
path = FileUtils.pwd if path.nil?
# if a www is found use it for the project
path = File.join(path, 'www') if File.exists? File.join(path, 'www')
# defaults
@name = path.split("/").last.gsub('-','').gsub(' ','') # no dashses nor spaces
@path = File.join(path, '..', "#{ @name }_android")
@www = path
@pkg = "com.phonegap.#{ @name }"
@www = path
@pkg = "com.phonegap.#{ @name }"
@android_sdk_path = Dir.getwd[0,1] != "/" ? `android-sdk-path.bat android.bat`.gsub('\\tools','').gsub('\\', '\\\\\\\\') : `which android`.gsub(/\/tools\/android$/,'').chomp
@android_dir = File.expand_path(File.dirname(__FILE__).gsub('lib',''))
@framework_dir = File.join(@android_dir, "framework")
@icon = File.join(@www, 'icon.png')
@app_js_dir = ''
@content = 'index.html'
# stop executation on errors
raise "Expected index.html in the following folder #{ path }.\nThe path is expected to be the directory droidgap create is run from or specified as a command line arg like droidgap create my_path." unless File.exists? File.join(path, 'index.html')
raise "Expected index.html in the following folder #{ path }.\nThe path is expected to be the directory droidgap create is run from or specified as a command line arg like droidgap create my_path." unless File.exists? File.join(path, 'index.html')
raise 'Could not find android in your PATH!' if @android_sdk_path.empty?
end
# reads in a config.xml file
def read_config
config_file = File.join(@www, 'config.xml')
if File.exists?(config_file)
require 'rexml/document'
f = File.new config_file
@@ -47,9 +47,9 @@ class Create < Classic
@config[:icons] = {}
defaultIconSize = 0
doc.root.elements.each do |n|
@config[:name] = n.text.gsub('-','').gsub(' ','') if n.name == 'name'
@config[:description] = n.text if n.name == 'description'
@config[:content] = n.attributes["src"] if n.name == 'content'
@config[:name] = n.text.gsub('-','').gsub(' ','') if n.name == 'name'
@config[:description] = n.text if n.name == 'description'
@config[:content] = n.attributes["src"] if n.name == 'content'
if n.name == 'icon'
if n.attributes["width"] == '72' && n.attributes["height"] == '72'
@config[:icons]["drawable-hdpi".to_sym] = n.attributes["src"]
@@ -74,12 +74,12 @@ class Create < Classic
end
end
if n.name == "preference" && n.attributes["name"] == 'javascript_folder'
@config[:js_dir] = n.attributes["value"]
end
end
end
end
# extract android specific stuff
@config[:versionCode] = doc.elements["//android:versionCode"] ? doc.elements["//android:versionCode"].text : 3
@config[:minSdkVersion] = doc.elements["//android:minSdkVersion"] ? doc.elements["//android:minSdkVersion"].text : 1
@@ -92,6 +92,6 @@ class Create < Classic
@app_js_dir = @config[:js_dir] ? @config[:js_dir] : ''
# sets the start page
@content = @config[:content] ? @config[:content] : 'index.html'
end
end
end
end
end
+12 -5
View File
@@ -33,12 +33,19 @@ class Update
# TODO need to allow for www import inc icon
def copy_libs
puts "Copying over libraries and assets..."
FileUtils.mkdir_p File.join(@path, "libs")
FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs")
version = IO.read(File.join(@framework_dir, '../VERSION'))
FileUtils.mkdir_p File.join(@path, "assets", "www")
FileUtils.cp File.join(@framework_dir, "assets", "www", "phonegap.js"), File.join(@path, "assets", "www")
FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs")
# concat JS and put into www folder. this can be overridden in the config.xml via @app_js_dir
js_dir = File.join(@framework_dir, "assets", "js")
phonegapjs = IO.read(File.join(js_dir, 'phonegap.js.base'))
Dir.new(js_dir).entries.each do |script|
next if script[0].chr == "." or script == "phonegap.js.base"
phonegapjs << IO.read(File.join(js_dir, script))
phonegapjs << "\n\n"
end
File.open(File.join(@path, "assets", "www", "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) }
end
#
end