mirror of
https://github.com/apache/cordova-android.git
synced 2026-05-11 00:00:05 +08:00
Merge branch 'master' of github.com:phonegap/phonegap-android
Conflicts: framework/res/xml/phonegap.xml framework/src/com/phonegap/DroidGap.java
This commit is contained in:
@@ -5,10 +5,10 @@
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true"
|
||||
android:xlargeScreens="true"
|
||||
android:resizeable="true"
|
||||
android:anyDensity="true"
|
||||
/>
|
||||
<!-- android:xlargeScreens="true" screen supported only after Android-9 -->
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
@@ -59,6 +59,14 @@ App.prototype.clearHistory = function() {
|
||||
PhoneGap.exec(null, null, "App", "clearHistory", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Go to previous page displayed.
|
||||
* This is the same as pressing the backbutton on Android device.
|
||||
*/
|
||||
App.prototype.backHistory = function() {
|
||||
PhoneGap.exec(null, null, "App", "backHistory", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
@@ -79,6 +87,16 @@ App.prototype.exitApp = function() {
|
||||
return PhoneGap.exec(null, null, "App", "exitApp", []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist) that will be loaded into PhoneGap container instead of default browser.
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
App.prototype.addWhiteListEntry = function(origin, subdomains) {
|
||||
return PhoneGap.exec(null, null, "App", "addWhiteListEntry", [origin, subdomains]);
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
navigator.app = new App();
|
||||
});
|
||||
|
||||
@@ -49,6 +49,24 @@ Camera.EncodingType = {
|
||||
};
|
||||
Camera.prototype.EncodingType = Camera.EncodingType;
|
||||
|
||||
/**
|
||||
* Type of pictures to select from. Only applicable when
|
||||
* PictureSourceType is PHOTOLIBRARY or SAVEDPHOTOALBUM
|
||||
*
|
||||
* Example: navigator.camera.getPicture(success, fail,
|
||||
* { quality: 80,
|
||||
* destinationType: Camera.DestinationType.DATA_URL,
|
||||
* sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
|
||||
* mediaType: Camera.MediaType.PICTURE})
|
||||
*/
|
||||
Camera.MediaType = {
|
||||
PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
|
||||
VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
|
||||
ALLMEDIA : 2 // allow selection from all media types
|
||||
};
|
||||
Camera.prototype.MediaType = Camera.MediaType;
|
||||
|
||||
|
||||
/**
|
||||
* Source to getPicture from.
|
||||
*
|
||||
@@ -87,52 +105,48 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
|
||||
console.log("Camera Error: errorCallback is not a function");
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
var quality = 80;
|
||||
if (options.quality) {
|
||||
quality = this.options.quality;
|
||||
}
|
||||
|
||||
var maxResolution = 0;
|
||||
if (options.maxResolution) {
|
||||
maxResolution = this.options.maxResolution;
|
||||
if (options === null || typeof options === "undefined") {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var destinationType = Camera.DestinationType.DATA_URL;
|
||||
if (this.options.destinationType) {
|
||||
destinationType = this.options.destinationType;
|
||||
if (options.quality === null || typeof options.quality === "undefined") {
|
||||
options.quality = 80;
|
||||
}
|
||||
var sourceType = Camera.PictureSourceType.CAMERA;
|
||||
if (typeof this.options.sourceType === "number") {
|
||||
sourceType = this.options.sourceType;
|
||||
if (options.maxResolution === null || typeof options.maxResolution === "undefined") {
|
||||
options.maxResolution = 0;
|
||||
}
|
||||
var encodingType = Camera.EncodingType.JPEG;
|
||||
if (typeof options.encodingType == "number") {
|
||||
encodingType = this.options.encodingType;
|
||||
if (options.destinationType === null || typeof options.destinationType === "undefined") {
|
||||
options.destinationType = Camera.DestinationType.DATA_URL;
|
||||
}
|
||||
|
||||
var targetWidth = -1;
|
||||
if (typeof options.targetWidth == "number") {
|
||||
targetWidth = options.targetWidth;
|
||||
} else if (typeof options.targetWidth == "string") {
|
||||
if (options.sourceType === null || typeof options.sourceType === "undefined") {
|
||||
options.sourceType = Camera.PictureSourceType.CAMERA;
|
||||
}
|
||||
if (options.encodingType === null || typeof options.encodingType === "undefined") {
|
||||
options.encodingType = Camera.EncodingType.JPEG;
|
||||
}
|
||||
if (options.mediaType === null || typeof options.mediaType === "undefined") {
|
||||
options.mediaType = Camera.MediaType.PICTURE;
|
||||
}
|
||||
if (options.targetWidth === null || typeof options.targetWidth === "undefined") {
|
||||
options.targetWidth = -1;
|
||||
}
|
||||
else if (typeof options.targetWidth == "string") {
|
||||
var width = new Number(options.targetWidth);
|
||||
if (isNaN(width) === false) {
|
||||
targetWidth = width.valueOf();
|
||||
options.targetWidth = width.valueOf();
|
||||
}
|
||||
}
|
||||
|
||||
var targetHeight = -1;
|
||||
if (typeof options.targetHeight == "number") {
|
||||
targetHeight = options.targetHeight;
|
||||
} else if (typeof options.targetHeight == "string") {
|
||||
if (options.targetHeight === null || typeof options.targetHeight === "undefined") {
|
||||
options.targetHeight = -1;
|
||||
}
|
||||
else if (typeof options.targetHeight == "string") {
|
||||
var height = new Number(options.targetHeight);
|
||||
if (isNaN(height) === false) {
|
||||
targetHeight = height.valueOf();
|
||||
options.targetHeight = height.valueOf();
|
||||
}
|
||||
}
|
||||
|
||||
PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType]);
|
||||
PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [options]);
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
|
||||
@@ -9,6 +9,21 @@
|
||||
if (!PhoneGap.hasResource("compass")) {
|
||||
PhoneGap.addResource("compass");
|
||||
|
||||
CompassError = function(){
|
||||
this.code = null;
|
||||
};
|
||||
|
||||
// Capture error codes
|
||||
CompassError.COMPASS_INTERNAL_ERR = 0;
|
||||
CompassError.COMPASS_NOT_SUPPORTED = 20;
|
||||
|
||||
CompassHeading = function() {
|
||||
this.magneticHeading = null;
|
||||
this.trueHeading = null;
|
||||
this.headingAccuracy = null;
|
||||
this.timestamp = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class provides access to device Compass data.
|
||||
* @constructor
|
||||
@@ -111,6 +126,14 @@ Compass.prototype.clearWatch = function(id) {
|
||||
}
|
||||
};
|
||||
|
||||
Compass.prototype._castDate = function(pluginResult) {
|
||||
if (pluginResult.message.timestamp) {
|
||||
var timestamp = new Date(pluginResult.message.timestamp);
|
||||
pluginResult.message.timestamp = timestamp;
|
||||
}
|
||||
return pluginResult;
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.compass === "undefined") {
|
||||
navigator.compass = new Compass();
|
||||
|
||||
+124
-194
@@ -11,8 +11,6 @@ PhoneGap.addResource("file");
|
||||
|
||||
/**
|
||||
* This class provides some useful information about a file.
|
||||
* This is the fields returned when navigator.fileMgr.getFileProperties()
|
||||
* is called.
|
||||
* @constructor
|
||||
*/
|
||||
var FileProperties = function(filePath) {
|
||||
@@ -32,9 +30,9 @@ var FileProperties = function(filePath) {
|
||||
* @param size {Number} size of the file in bytes
|
||||
*/
|
||||
var File = function(name, fullPath, type, lastModifiedDate, size) {
|
||||
this.name = name || null;
|
||||
this.name = name || null;
|
||||
this.fullPath = fullPath || null;
|
||||
this.type = type || null;
|
||||
this.type = type || null;
|
||||
this.lastModifiedDate = lastModifiedDate || null;
|
||||
this.size = size || 0;
|
||||
};
|
||||
@@ -61,64 +59,9 @@ FileError.QUOTA_EXCEEDED_ERR = 10;
|
||||
FileError.TYPE_MISMATCH_ERR = 11;
|
||||
FileError.PATH_EXISTS_ERR = 12;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// File manager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** @constructor */
|
||||
var FileMgr = function() {
|
||||
};
|
||||
|
||||
FileMgr.prototype.getFileProperties = function(filePath) {
|
||||
return PhoneGap.exec(null, null, "File", "getFileProperties", [filePath]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.getFileBasePaths = function() {
|
||||
};
|
||||
|
||||
FileMgr.prototype.testSaveLocationExists = function(successCallback, errorCallback) {
|
||||
return PhoneGap.exec(successCallback, errorCallback, "File", "testSaveLocationExists", []);
|
||||
};
|
||||
|
||||
FileMgr.prototype.testFileExists = function(fileName, successCallback, errorCallback) {
|
||||
return PhoneGap.exec(successCallback, errorCallback, "File", "testFileExists", [fileName]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.testDirectoryExists = function(dirName, successCallback, errorCallback) {
|
||||
return PhoneGap.exec(successCallback, errorCallback, "File", "testDirectoryExists", [dirName]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback) {
|
||||
return PhoneGap.exec(successCallback, errorCallback, "File", "getFreeDiskSpace", []);
|
||||
};
|
||||
|
||||
FileMgr.prototype.write = function(fileName, data, position, successCallback, errorCallback) {
|
||||
PhoneGap.exec(successCallback, errorCallback, "File", "write", [fileName, data, position]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.truncate = function(fileName, size, successCallback, errorCallback) {
|
||||
PhoneGap.exec(successCallback, errorCallback, "File", "truncate", [fileName, size]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.readAsText = function(fileName, encoding, successCallback, errorCallback) {
|
||||
PhoneGap.exec(successCallback, errorCallback, "File", "readAsText", [fileName, encoding]);
|
||||
};
|
||||
|
||||
FileMgr.prototype.readAsDataURL = function(fileName, successCallback, errorCallback) {
|
||||
PhoneGap.exec(successCallback, errorCallback, "File", "readAsDataURL", [fileName]);
|
||||
};
|
||||
|
||||
PhoneGap.addConstructor(function() {
|
||||
if (typeof navigator.fileMgr === "undefined") {
|
||||
navigator.fileMgr = new FileMgr();
|
||||
}
|
||||
});
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// File Reader
|
||||
//-----------------------------------------------------------------------------
|
||||
// TODO: All other FileMgr function operate on the SD card as root. However,
|
||||
// for FileReader & FileWriter the root is not SD card. Should this be changed?
|
||||
|
||||
/**
|
||||
* This class reads the mobile device file system.
|
||||
@@ -188,11 +131,11 @@ FileReader.prototype.abort = function() {
|
||||
*/
|
||||
FileReader.prototype.readAsText = function(file, encoding) {
|
||||
this.fileName = "";
|
||||
if (typeof file.fullPath === "undefined") {
|
||||
this.fileName = file;
|
||||
} else {
|
||||
this.fileName = file.fullPath;
|
||||
}
|
||||
if (typeof file.fullPath === "undefined") {
|
||||
this.fileName = file;
|
||||
} else {
|
||||
this.fileName = file.fullPath;
|
||||
}
|
||||
|
||||
// LOADING state
|
||||
this.readyState = FileReader.LOADING;
|
||||
@@ -208,8 +151,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
|
||||
var me = this;
|
||||
|
||||
// Read file
|
||||
navigator.fileMgr.readAsText(this.fileName, enc,
|
||||
|
||||
PhoneGap.exec(
|
||||
// Success callback
|
||||
function(r) {
|
||||
var evt;
|
||||
@@ -235,89 +177,6 @@ FileReader.prototype.readAsText = function(file, encoding) {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
},
|
||||
|
||||
// Error callback
|
||||
function(e) {
|
||||
var evt;
|
||||
// If DONE (cancelled), then don't do anything
|
||||
if (me.readyState === FileReader.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save error
|
||||
me.error = e;
|
||||
|
||||
// If onerror callback
|
||||
if (typeof me.onerror === "function") {
|
||||
me.onerror({"type":"error", "target":me});
|
||||
}
|
||||
|
||||
// DONE state
|
||||
me.readyState = FileReader.DONE;
|
||||
|
||||
// If onloadend callback
|
||||
if (typeof me.onloadend === "function") {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read file and return data as a base64 encoded data url.
|
||||
* A data url is of the form:
|
||||
* data:[<mediatype>][;base64],<data>
|
||||
*
|
||||
* @param file {File} File object containing file properties
|
||||
*/
|
||||
FileReader.prototype.readAsDataURL = function(file) {
|
||||
this.fileName = "";
|
||||
if (typeof file.fullPath === "undefined") {
|
||||
this.fileName = file;
|
||||
} else {
|
||||
this.fileName = file.fullPath;
|
||||
}
|
||||
|
||||
// LOADING state
|
||||
this.readyState = FileReader.LOADING;
|
||||
|
||||
// If loadstart callback
|
||||
if (typeof this.onloadstart === "function") {
|
||||
this.onloadstart({"type":"loadstart", "target":this});
|
||||
}
|
||||
|
||||
var me = this;
|
||||
|
||||
// Read file
|
||||
navigator.fileMgr.readAsDataURL(this.fileName,
|
||||
|
||||
// Success callback
|
||||
function(r) {
|
||||
var evt;
|
||||
|
||||
// If DONE (cancelled), then don't do anything
|
||||
if (me.readyState === FileReader.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save result
|
||||
me.result = r;
|
||||
|
||||
// If onload callback
|
||||
if (typeof me.onload === "function") {
|
||||
me.onload({"type":"load", "target":me});
|
||||
}
|
||||
|
||||
// DONE state
|
||||
me.readyState = FileReader.DONE;
|
||||
|
||||
// If onloadend callback
|
||||
if (typeof me.onloadend === "function") {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
},
|
||||
|
||||
// Error callback
|
||||
function(e) {
|
||||
var evt;
|
||||
@@ -341,8 +200,86 @@ FileReader.prototype.readAsDataURL = function(file) {
|
||||
if (typeof me.onloadend === "function") {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
}
|
||||
);
|
||||
}, "File", "readAsText", [this.fileName, enc]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read file and return data as a base64 encoded data url.
|
||||
* A data url is of the form:
|
||||
* data:[<mediatype>][;base64],<data>
|
||||
*
|
||||
* @param file {File} File object containing file properties
|
||||
*/
|
||||
FileReader.prototype.readAsDataURL = function(file) {
|
||||
this.fileName = "";
|
||||
if (typeof file.fullPath === "undefined") {
|
||||
this.fileName = file;
|
||||
} else {
|
||||
this.fileName = file.fullPath;
|
||||
}
|
||||
|
||||
// LOADING state
|
||||
this.readyState = FileReader.LOADING;
|
||||
|
||||
// If loadstart callback
|
||||
if (typeof this.onloadstart === "function") {
|
||||
this.onloadstart({"type":"loadstart", "target":this});
|
||||
}
|
||||
|
||||
var me = this;
|
||||
|
||||
// Read file
|
||||
PhoneGap.exec(
|
||||
// Success callback
|
||||
function(r) {
|
||||
var evt;
|
||||
|
||||
// If DONE (cancelled), then don't do anything
|
||||
if (me.readyState === FileReader.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save result
|
||||
me.result = r;
|
||||
|
||||
// If onload callback
|
||||
if (typeof me.onload === "function") {
|
||||
me.onload({"type":"load", "target":me});
|
||||
}
|
||||
|
||||
// DONE state
|
||||
me.readyState = FileReader.DONE;
|
||||
|
||||
// If onloadend callback
|
||||
if (typeof me.onloadend === "function") {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
},
|
||||
// Error callback
|
||||
function(e) {
|
||||
var evt;
|
||||
// If DONE (cancelled), then don't do anything
|
||||
if (me.readyState === FileReader.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save error
|
||||
me.error = e;
|
||||
|
||||
// If onerror callback
|
||||
if (typeof me.onerror === "function") {
|
||||
me.onerror({"type":"error", "target":me});
|
||||
}
|
||||
|
||||
// DONE state
|
||||
me.readyState = FileReader.DONE;
|
||||
|
||||
// If onloadend callback
|
||||
if (typeof me.onloadend === "function") {
|
||||
me.onloadend({"type":"loadend", "target":me});
|
||||
}
|
||||
}, "File", "readAsDataURL", [this.fileName]);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -383,10 +320,10 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
|
||||
var FileWriter = function(file) {
|
||||
this.fileName = "";
|
||||
this.length = 0;
|
||||
if (file) {
|
||||
this.fileName = file.fullPath || file;
|
||||
this.length = file.size || 0;
|
||||
}
|
||||
if (file) {
|
||||
this.fileName = file.fullPath || file;
|
||||
this.length = file.size || 0;
|
||||
}
|
||||
// default is to write at the beginning of the file
|
||||
this.position = 0;
|
||||
|
||||
@@ -398,12 +335,12 @@ var FileWriter = function(file) {
|
||||
this.error = null;
|
||||
|
||||
// Event handlers
|
||||
this.onwritestart = null; // When writing starts
|
||||
this.onprogress = null; // While writing the file, and reporting partial file data
|
||||
this.onwrite = null; // When the write has successfully completed.
|
||||
this.onwriteend = null; // When the request has completed (either in success or failure).
|
||||
this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
|
||||
this.onerror = null; // When the write has failed (see errors).
|
||||
this.onwritestart = null; // When writing starts
|
||||
this.onprogress = null; // While writing the file, and reporting partial file data
|
||||
this.onwrite = null; // When the write has successfully completed.
|
||||
this.onwriteend = null; // When the request has completed (either in success or failure).
|
||||
this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
|
||||
this.onerror = null; // When the write has failed (see errors).
|
||||
};
|
||||
|
||||
// States
|
||||
@@ -416,9 +353,9 @@ FileWriter.DONE = 2;
|
||||
*/
|
||||
FileWriter.prototype.abort = function() {
|
||||
// check for invalid state
|
||||
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// set error
|
||||
var error = new FileError(), evt;
|
||||
@@ -448,10 +385,10 @@ FileWriter.prototype.abort = function() {
|
||||
* @param text to be written
|
||||
*/
|
||||
FileWriter.prototype.write = function(text) {
|
||||
// Throw an exception if we are already writing a file
|
||||
if (this.readyState === FileWriter.WRITING) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
// Throw an exception if we are already writing a file
|
||||
if (this.readyState === FileWriter.WRITING) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// WRITING state
|
||||
this.readyState = FileWriter.WRITING;
|
||||
@@ -464,8 +401,7 @@ FileWriter.prototype.write = function(text) {
|
||||
}
|
||||
|
||||
// Write file
|
||||
navigator.fileMgr.write(this.fileName, text, this.position,
|
||||
|
||||
PhoneGap.exec(
|
||||
// Success callback
|
||||
function(r) {
|
||||
var evt;
|
||||
@@ -492,7 +428,6 @@ FileWriter.prototype.write = function(text) {
|
||||
me.onwriteend({"type":"writeend", "target":me});
|
||||
}
|
||||
},
|
||||
|
||||
// Error callback
|
||||
function(e) {
|
||||
var evt;
|
||||
@@ -517,9 +452,7 @@ FileWriter.prototype.write = function(text) {
|
||||
if (typeof me.onwriteend === "function") {
|
||||
me.onwriteend({"type":"writeend", "target":me});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}, "File", "write", [this.fileName, text, this.position]);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -543,18 +476,18 @@ FileWriter.prototype.seek = function(offset) {
|
||||
|
||||
// See back from end of file.
|
||||
if (offset < 0) {
|
||||
this.position = Math.max(offset + this.length, 0);
|
||||
}
|
||||
this.position = Math.max(offset + this.length, 0);
|
||||
}
|
||||
// Offset is bigger then file size so set position
|
||||
// to the end of the file.
|
||||
else if (offset > this.length) {
|
||||
this.position = this.length;
|
||||
}
|
||||
else if (offset > this.length) {
|
||||
this.position = this.length;
|
||||
}
|
||||
// Offset is between 0 and file size so set the position
|
||||
// to start writing.
|
||||
else {
|
||||
this.position = offset;
|
||||
}
|
||||
else {
|
||||
this.position = offset;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -563,10 +496,10 @@ FileWriter.prototype.seek = function(offset) {
|
||||
* @param size to chop the file at.
|
||||
*/
|
||||
FileWriter.prototype.truncate = function(size) {
|
||||
// Throw an exception if we are already writing a file
|
||||
if (this.readyState === FileWriter.WRITING) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
// Throw an exception if we are already writing a file
|
||||
if (this.readyState === FileWriter.WRITING) {
|
||||
throw FileError.INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// WRITING state
|
||||
this.readyState = FileWriter.WRITING;
|
||||
@@ -579,8 +512,7 @@ FileWriter.prototype.truncate = function(size) {
|
||||
}
|
||||
|
||||
// Write file
|
||||
navigator.fileMgr.truncate(this.fileName, size,
|
||||
|
||||
PhoneGap.exec(
|
||||
// Success callback
|
||||
function(r) {
|
||||
var evt;
|
||||
@@ -606,7 +538,6 @@ FileWriter.prototype.truncate = function(size) {
|
||||
me.onwriteend({"type":"writeend", "target":me});
|
||||
}
|
||||
},
|
||||
|
||||
// Error callback
|
||||
function(e) {
|
||||
var evt;
|
||||
@@ -630,8 +561,7 @@ FileWriter.prototype.truncate = function(size) {
|
||||
if (typeof me.onwriteend === "function") {
|
||||
me.onwriteend({"type":"writeend", "target":me});
|
||||
}
|
||||
}
|
||||
);
|
||||
}, "File", "truncate", [this.fileName, size]);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1050,10 +980,10 @@ LocalFileSystem.prototype._castDate = function(pluginResult) {
|
||||
* Add the FileSystem interface into the browser.
|
||||
*/
|
||||
PhoneGap.addConstructor(function() {
|
||||
var pgLocalFileSystem = new LocalFileSystem();
|
||||
// Needed for cast methods
|
||||
var pgLocalFileSystem = new LocalFileSystem();
|
||||
// Needed for cast methods
|
||||
if(typeof window.localFileSystem == "undefined") window.localFileSystem = pgLocalFileSystem;
|
||||
if(typeof window.requestFileSystem == "undefined") window.requestFileSystem = pgLocalFileSystem.requestFileSystem;
|
||||
if(typeof window.resolveLocalFileSystemURI == "undefined") window.resolveLocalFileSystemURI = pgLocalFileSystem.resolveLocalFileSystemURI;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -53,10 +53,14 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
|
||||
var fileName = null;
|
||||
var mimeType = null;
|
||||
var params = null;
|
||||
var chunkedMode = true;
|
||||
if (options) {
|
||||
fileKey = options.fileKey;
|
||||
fileName = options.fileName;
|
||||
mimeType = options.mimeType;
|
||||
if (options.chunkedMode != null || typeof options.chunkedMode != "undefined") {
|
||||
chunkedMode = options.chunkedMode;
|
||||
}
|
||||
if (options.params) {
|
||||
params = options.params;
|
||||
}
|
||||
@@ -65,7 +69,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
|
||||
}
|
||||
}
|
||||
|
||||
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug]);
|
||||
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="phonegap-1.0.0.js"></script>
|
||||
<script src="phonegap-1.1.0.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
+4
-4
@@ -109,7 +109,7 @@
|
||||
<target name="build-javascript">
|
||||
|
||||
<!-- Clean up existing files -->
|
||||
<delete file="assets/www/phonegap_${version}.js"/>
|
||||
<!--<delete file="assets/www/phonegap_${version}.js"/>-->
|
||||
|
||||
<!-- Create uncompressed JS file -->
|
||||
<concat destfile="assets/www/phonegap-${version}.js">
|
||||
@@ -119,15 +119,15 @@
|
||||
|
||||
<!-- update project files to reference phonegap-x.x.x.min.js -->
|
||||
<replaceregexp match="phonegap(.*)\.js" replace="phonegap-${version}.js" byline="true">
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../example/index.html" />
|
||||
<fileset file="assets/www/index.html" />
|
||||
<!-- <fileset file="../bin/templates/project/assets/www/index.html" /> -->
|
||||
</replaceregexp>
|
||||
<replaceregexp match="phonegapVersion = [\u0022].*[\u0022];" replace="phonegapVersion = ${dblQuote}${version}${dblQuote};" byline="true">
|
||||
<fileset file="src/com/phonegap/Device.java" />
|
||||
</replaceregexp>
|
||||
|
||||
<!-- Delete temp file -->
|
||||
<delete file="assets/www/phonegap-tmp.js"/>
|
||||
<!--<delete file="assets/www/phonegap-tmp.js"/>-->
|
||||
</target>
|
||||
|
||||
<!-- Build PhoneGap jar file that includes all native code, and PhoneGap JS file
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phonegap>
|
||||
<access origin="http://127.0.0.1*"/>
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<log level="DEBUG"/>
|
||||
>>>>>>> 7ee04ebf313c7403cf623a1f9c00b6b5e7cc9f0b
|
||||
</phonegap>
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.phonegap;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import android.app.Activity;
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
import java.util.HashMap;
|
||||
@@ -43,6 +44,9 @@ public class App extends Plugin {
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
}
|
||||
else if (action.equals("backHistory")) {
|
||||
this.backHistory();
|
||||
}
|
||||
else if (action.equals("overrideBackbutton")) {
|
||||
this.overrideBackbutton(args.getBoolean(0));
|
||||
@@ -54,6 +58,9 @@ public class App extends Plugin {
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
}
|
||||
else if (action.equals("addWhiteListEntry")) {
|
||||
this.addWhiteListEntry(args.getString(0), args.optBoolean(1));
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
@@ -140,9 +147,19 @@ public class App extends Plugin {
|
||||
|
||||
/**
|
||||
* Clear web history in this web view.
|
||||
* This does not have any effect since each page has its own activity.
|
||||
*/
|
||||
public void clearHistory() {
|
||||
((DroidGap)this.ctx).clearHistory();
|
||||
// TODO: Kill previous activities?
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page displayed.
|
||||
* This is the same as pressing the backbutton on Android device.
|
||||
*/
|
||||
public void backHistory() {
|
||||
((DroidGap)this.ctx).endActivity();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +186,17 @@ public class App extends Plugin {
|
||||
* Exit the Android application.
|
||||
*/
|
||||
public void exitApp() {
|
||||
((DroidGap)this.ctx).finish();
|
||||
((DroidGap)this.ctx).setResult(Activity.RESULT_OK);
|
||||
((DroidGap)this.ctx).endActivity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist)
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
public void addWhiteListEntry(String origin, boolean subdomains) {
|
||||
((DroidGap)this.ctx).addWhiteListEntry(origin, subdomains);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
||||
* @return T=streaming, F=local
|
||||
*/
|
||||
public boolean isStreaming(String file) {
|
||||
if (file.contains("http://")) {
|
||||
if (file.contains("http://") || file.contains("https://")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -10,12 +10,14 @@ package com.phonegap;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.Plugin;
|
||||
import com.phonegap.api.PluginResult;
|
||||
@@ -23,9 +25,11 @@ import com.phonegap.api.PluginResult;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -42,16 +46,27 @@ public class CameraLauncher extends Plugin {
|
||||
private static final int CAMERA = 1; // Take picture from camera
|
||||
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
|
||||
|
||||
private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
|
||||
private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL
|
||||
private static final int ALLMEDIA = 2; // allow selection from all media types
|
||||
|
||||
private static final int JPEG = 0; // Take a picture of type JPEG
|
||||
private static final int PNG = 1; // Take a picture of type PNG
|
||||
private static final String GET_PICTURE = "Get Picture";
|
||||
private static final String GET_VIDEO = "Get Video";
|
||||
private static final String GET_All = "Get All";
|
||||
|
||||
private static final String LOG_TAG = "CameraLauncher";
|
||||
|
||||
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
private int targetWidth; // desired width of the image
|
||||
private int targetHeight; // desired height of the image
|
||||
private Uri imageUri;
|
||||
private int encodingType;
|
||||
// Uri of captured image
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private int encodingType; // Type of encoding to use
|
||||
private int mediaType; // What type of media to retrieve
|
||||
|
||||
public String callbackId;
|
||||
private int numPics;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -74,29 +89,30 @@ public class CameraLauncher extends Plugin {
|
||||
|
||||
try {
|
||||
if (action.equals("takePicture")) {
|
||||
int destType = DATA_URL;
|
||||
if (args.length() > 1) {
|
||||
destType = args.getInt(1);
|
||||
}
|
||||
int srcType = CAMERA;
|
||||
if (args.length() > 2) {
|
||||
srcType = args.getInt(2);
|
||||
}
|
||||
if (args.length() > 3) {
|
||||
this.targetWidth = args.getInt(3);
|
||||
}
|
||||
if (args.length() > 4) {
|
||||
this.targetHeight = args.getInt(4);
|
||||
}
|
||||
int destType = DATA_URL;
|
||||
this.targetHeight = 0;
|
||||
this.targetWidth = 0;
|
||||
this.encodingType = JPEG;
|
||||
if (args.length() > 5) {
|
||||
this.encodingType = args.getInt(5);
|
||||
this.mediaType = PICTURE;
|
||||
this.mQuality = 80;
|
||||
|
||||
JSONObject options = args.optJSONObject(0);
|
||||
if (options != null) {
|
||||
srcType = options.getInt("sourceType");
|
||||
destType = options.getInt("destinationType");
|
||||
this.targetHeight = options.getInt("targetHeight");
|
||||
this.targetWidth = options.getInt("targetWidth");
|
||||
this.encodingType = options.getInt("encodingType");
|
||||
this.mediaType = options.getInt("mediaType");
|
||||
this.mQuality = options.getInt("quality");
|
||||
}
|
||||
|
||||
if (srcType == CAMERA) {
|
||||
this.takePicture(args.getInt(0), destType, encodingType);
|
||||
this.takePicture(destType, encodingType);
|
||||
}
|
||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||
this.getImage(args.getInt(0), srcType, destType);
|
||||
this.getImage(srcType, destType);
|
||||
}
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
@@ -127,9 +143,10 @@ public class CameraLauncher extends Plugin {
|
||||
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
public void takePicture(int quality, int returnType, int encodingType) {
|
||||
this.mQuality = quality;
|
||||
|
||||
public void takePicture(int returnType, int encodingType) {
|
||||
// Save the number of images currently on disk for later
|
||||
this.numPics = queryImgDB().getCount();
|
||||
|
||||
// Display camera
|
||||
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
|
||||
|
||||
@@ -166,15 +183,27 @@ public class CameraLauncher extends Plugin {
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
|
||||
public void getImage(int quality, int srcType, int returnType) {
|
||||
this.mQuality = quality;
|
||||
|
||||
public void getImage(int srcType, int returnType) {
|
||||
Intent intent = new Intent();
|
||||
intent.setType("image/*");
|
||||
String title = GET_PICTURE;
|
||||
if (this.mediaType == PICTURE) {
|
||||
intent.setType("image/*");
|
||||
}
|
||||
else if (this.mediaType == VIDEO) {
|
||||
intent.setType("video/*");
|
||||
title = GET_VIDEO;
|
||||
}
|
||||
else if (this.mediaType == ALLMEDIA) {
|
||||
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
|
||||
// of android so I had to go with the wildcard search.
|
||||
intent.setType("*/*");
|
||||
title = GET_All;
|
||||
}
|
||||
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
|
||||
new String("Get Picture")), (srcType+1)*16 + returnType + 1);
|
||||
new String(title)), (srcType+1)*16 + returnType + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,7 +263,7 @@ public class CameraLauncher extends Plugin {
|
||||
// Get src and dest types from request code
|
||||
int srcType = (requestCode/16) - 1;
|
||||
int destType = (requestCode % 16) - 1;
|
||||
|
||||
|
||||
// If CAMERA
|
||||
if (srcType == CAMERA) {
|
||||
// If image available
|
||||
@@ -262,6 +291,7 @@ public class CameraLauncher extends Plugin {
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
this.processPicture(bitmap);
|
||||
checkForDuplicateImage(DATA_URL);
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
@@ -301,6 +331,8 @@ public class CameraLauncher extends Plugin {
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
|
||||
checkForDuplicateImage(FILE_URI);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error capturing image.");
|
||||
@@ -323,24 +355,55 @@ public class CameraLauncher extends Plugin {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
this.processPicture(bitmap);
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
// If you ask for video or all media type you will automatically get back a file URI
|
||||
// and there will be no attempt to resize any returned data
|
||||
if (this.mediaType != PICTURE) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
else {
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
this.processPicture(bitmap);
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI) {
|
||||
// Do we need to scale the returned file
|
||||
if (this.targetHeight > 0 && this.targetWidth > 0) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
|
||||
String fileName = DirectoryManager.getTempDirectoryPath(ctx) + "/resize.jpg";
|
||||
OutputStream os = new FileOutputStream(fileName);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
|
||||
this.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName)), this.callbackId);
|
||||
System.gc();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
@@ -351,7 +414,46 @@ public class CameraLauncher extends Plugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cursor that can be used to determine how many images we have.
|
||||
*
|
||||
* @return a cursor
|
||||
*/
|
||||
private Cursor queryImgDB() {
|
||||
return this.ctx.getContentResolver().query(
|
||||
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
new String[] { MediaStore.Images.Media._ID },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to find out if we are in a situation where the Camera Intent adds to images
|
||||
* to the content store. If we are using a FILE_URI and the number of images in the DB
|
||||
* increases by 2 we have a duplicate, when using a DATA_URL the number is 1.
|
||||
*
|
||||
* @param type FILE_URI or DATA_URL
|
||||
*/
|
||||
private void checkForDuplicateImage(int type) {
|
||||
int diff = 1;
|
||||
Cursor cursor = queryImgDB();
|
||||
int currentNumOfImages = cursor.getCount();
|
||||
|
||||
if (type == FILE_URI) {
|
||||
diff = 2;
|
||||
}
|
||||
|
||||
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
|
||||
if ((currentNumOfImages - numPics) == diff) {
|
||||
cursor.moveToLast();
|
||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
||||
Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id);
|
||||
this.ctx.getContentResolver().delete(uri, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,10 @@ import com.phonegap.api.PluginResult;
|
||||
|
||||
public class Capture extends Plugin {
|
||||
|
||||
private static final String VIDEO_3GPP = "video/3gpp";
|
||||
private static final String AUDIO_3GPP = "audio/3gpp";
|
||||
private static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
|
||||
private static final int CAPTURE_IMAGE = 1; // Constant for capture image
|
||||
private static final int CAPTURE_VIDEO = 2; // Constant for capture video
|
||||
@@ -97,14 +101,15 @@ public class Capture extends Plugin {
|
||||
if (mimeType == null || mimeType.equals("")) {
|
||||
mimeType = FileUtils.getMimeType(filePath);
|
||||
}
|
||||
Log.d(LOG_TAG, "Mime type = " + mimeType);
|
||||
|
||||
if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) {
|
||||
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
|
||||
obj = getImageData(filePath, obj);
|
||||
}
|
||||
else if (filePath.endsWith("audio/3gpp")) {
|
||||
else if (mimeType.endsWith(AUDIO_3GPP)) {
|
||||
obj = getAudioVideoData(filePath, obj, false);
|
||||
}
|
||||
else if (mimeType.equals("video/3gpp")) {
|
||||
else if (mimeType.equals(VIDEO_3GPP)) {
|
||||
obj = getAudioVideoData(filePath, obj, true);
|
||||
}
|
||||
}
|
||||
@@ -233,7 +238,7 @@ public class Capture extends Plugin {
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
|
||||
Uri uri = null;
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
@@ -329,7 +334,20 @@ public class Capture extends Plugin {
|
||||
// File properties
|
||||
obj.put("name", fp.getName());
|
||||
obj.put("fullPath", fp.getAbsolutePath());
|
||||
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
|
||||
|
||||
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
|
||||
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
|
||||
// is stored in the audio or video content store.
|
||||
if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
|
||||
if (data.toString().contains("/audio/")) {
|
||||
obj.put("type", AUDIO_3GPP);
|
||||
} else {
|
||||
obj.put("type", VIDEO_3GPP);
|
||||
}
|
||||
} else {
|
||||
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
|
||||
}
|
||||
|
||||
obj.put("lastModifiedDate", fp.lastModified());
|
||||
obj.put("size", fp.length());
|
||||
} catch (JSONException e) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.phonegap.api.PhonegapActivity;
|
||||
import com.phonegap.api.Plugin;
|
||||
@@ -27,129 +28,130 @@ import android.content.Context;
|
||||
*/
|
||||
public class CompassListener extends Plugin implements SensorEventListener {
|
||||
|
||||
public static int STOPPED = 0;
|
||||
public static int STARTING = 1;
|
||||
public static int STOPPED = 0;
|
||||
public static int STARTING = 1;
|
||||
public static int RUNNING = 2;
|
||||
public static int ERROR_FAILED_TO_START = 3;
|
||||
|
||||
public long TIMEOUT = 30000; // Timeout in msec to shut off listener
|
||||
|
||||
int status; // status of listener
|
||||
float heading; // most recent heading value
|
||||
long timeStamp; // time of most recent value
|
||||
long lastAccessTime; // time the value was last retrieved
|
||||
|
||||
public long TIMEOUT = 30000; // Timeout in msec to shut off listener
|
||||
|
||||
int status; // status of listener
|
||||
float heading; // most recent heading value
|
||||
long timeStamp; // time of most recent value
|
||||
long lastAccessTime; // time the value was last retrieved
|
||||
int accuracy; // accuracy of the sensor
|
||||
|
||||
private SensorManager sensorManager;// Sensor manager
|
||||
Sensor mSensor; // Compass sensor returned by sensor manager
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CompassListener() {
|
||||
Sensor mSensor; // Compass sensor returned by sensor manager
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CompassListener() {
|
||||
this.timeStamp = 0;
|
||||
this.setStatus(CompassListener.STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(PhonegapActivity ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
else if (action.equals("getStatus")) {
|
||||
int i = this.getStatus();
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// If not running, then this is an async call, so don't worry about waiting
|
||||
if (this.status != RUNNING) {
|
||||
int r = this.start();
|
||||
if (r == ERROR_FAILED_TO_START) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, ERROR_FAILED_TO_START);
|
||||
}
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
float f = this.getHeading();
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("setTimeout")) {
|
||||
this.setTimeout(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
long l = this.getTimeout();
|
||||
return new PluginResult(status, l);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
else if (action.equals("getStatus")) {
|
||||
int i = this.getStatus();
|
||||
return new PluginResult(status, i);
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// If not running, then this is an async call, so don't worry about waiting
|
||||
if (this.status != RUNNING) {
|
||||
int r = this.start();
|
||||
if (r == ERROR_FAILED_TO_START) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, ERROR_FAILED_TO_START);
|
||||
}
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, AccelListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
//float f = this.getHeading();
|
||||
return new PluginResult(status, getCompassHeading(), "navigator.compass._castDate");
|
||||
}
|
||||
else if (action.equals("setTimeout")) {
|
||||
this.setTimeout(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
long l = this.getTimeout();
|
||||
return new PluginResult(status, l);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getStatus")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// Can only return value if RUNNING
|
||||
if (this.status == RUNNING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getStatus")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getHeading")) {
|
||||
// Can only return value if RUNNING
|
||||
if (this.status == RUNNING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (action.equals("getTimeout")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when listener is to be shut down and object is being destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
@@ -158,113 +160,135 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
/**
|
||||
* Start listening for compass sensor.
|
||||
*
|
||||
* @return status of listener
|
||||
* @return status of listener
|
||||
*/
|
||||
public int start() {
|
||||
|
||||
// If already starting or running, then just return
|
||||
public int start() {
|
||||
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
|
||||
return this.status;
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
||||
|
||||
// If found, then register as listener
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
this.setStatus(CompassListener.STARTING);
|
||||
}
|
||||
}
|
||||
|
||||
// If error, then set status to error
|
||||
// If error, then set status to error
|
||||
else {
|
||||
this.setStatus(CompassListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
|
||||
return this.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to compass sensor.
|
||||
*/
|
||||
public void stop() {
|
||||
public void stop() {
|
||||
if (this.status != CompassListener.STOPPED) {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
this.setStatus(CompassListener.STOPPED);
|
||||
}
|
||||
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensor listener event.
|
||||
*
|
||||
* @param SensorEvent event
|
||||
*/
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
|
||||
// We only care about the orientation as far as it refers to Magnetic North
|
||||
float heading = event.values[0];
|
||||
// We only care about the orientation as far as it refers to Magnetic North
|
||||
float heading = event.values[0];
|
||||
|
||||
// Save heading
|
||||
// Save heading
|
||||
this.timeStamp = System.currentTimeMillis();
|
||||
this.heading = heading;
|
||||
this.setStatus(CompassListener.RUNNING);
|
||||
this.heading = heading;
|
||||
this.setStatus(CompassListener.RUNNING);
|
||||
|
||||
// If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power
|
||||
if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power
|
||||
if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of compass sensor.
|
||||
*
|
||||
* @return status
|
||||
* @return status
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent compass heading.
|
||||
*
|
||||
* @return heading
|
||||
*/
|
||||
public float getHeading() {
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent compass heading.
|
||||
*
|
||||
* @return heading
|
||||
*/
|
||||
public float getHeading() {
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
return this.heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @param timeout Timeout in msec.
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @return timeout in msec
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return this.TIMEOUT;
|
||||
}
|
||||
return this.heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @param timeout Timeout in msec.
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
* @return timeout in msec
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return this.TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status and send it to JavaScript.
|
||||
* @param status
|
||||
*/
|
||||
private void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
/**
|
||||
* Set the status and send it to JavaScript.
|
||||
* @param status
|
||||
*/
|
||||
private void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the CompassHeading JSON object to be returned to JavaScript
|
||||
*
|
||||
* @return a compass heading
|
||||
*/
|
||||
private JSONObject getCompassHeading() {
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
try {
|
||||
obj.put("magneticHeading", this.getHeading());
|
||||
obj.put("trueHeading", this.getHeading());
|
||||
// Since the magnetic and true heading are always the same our and accuracy
|
||||
// is defined as the difference between true and magnetic always return zero
|
||||
obj.put("headingAccuracy", 0);
|
||||
obj.put("timestamp", this.timeStamp);
|
||||
} catch (JSONException e) {
|
||||
// Should never happen
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import android.provider.Settings;
|
||||
|
||||
public class Device extends Plugin {
|
||||
|
||||
public static String phonegapVersion = "1.0.0"; // PhoneGap version
|
||||
public static String phonegapVersion = "1.1.0"; // PhoneGap version
|
||||
public static String platform = "Android"; // Device OS
|
||||
public static String uuid; // Device UUID
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -81,9 +81,10 @@ public class FileTransfer extends Plugin {
|
||||
try {
|
||||
JSONObject params = args.optJSONObject(5);
|
||||
boolean trustEveryone = args.optBoolean(6);
|
||||
boolean chunkedMode = args.getBoolean(7);
|
||||
|
||||
if (action.equals("upload")) {
|
||||
FileUploadResult r = upload(file, server, fileKey, fileName, mimeType, params, trustEveryone);
|
||||
FileUploadResult r = upload(file, server, fileKey, fileName, mimeType, params, trustEveryone, chunkedMode);
|
||||
Log.d(LOG_TAG, "****** About to return a result from upload");
|
||||
return new PluginResult(PluginResult.Status.OK, r.toJSONObject());
|
||||
} else {
|
||||
@@ -202,7 +203,7 @@ public class FileTransfer extends Plugin {
|
||||
* @return FileUploadResult containing result of upload request
|
||||
*/
|
||||
public FileUploadResult upload(String file, String server, final String fileKey, final String fileName,
|
||||
final String mimeType, JSONObject params, boolean trustEveryone) throws IOException, SSLException {
|
||||
final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException {
|
||||
// Create return object
|
||||
FileUploadResult result = new FileUploadResult();
|
||||
|
||||
@@ -240,7 +241,7 @@ public class FileTransfer extends Plugin {
|
||||
conn = https;
|
||||
}
|
||||
}
|
||||
// Return a standard HTTP conneciton
|
||||
// Return a standard HTTP connection
|
||||
else {
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
@@ -264,7 +265,12 @@ public class FileTransfer extends Plugin {
|
||||
if (cookie != null) {
|
||||
conn.setRequestProperty("Cookie", cookie);
|
||||
}
|
||||
|
||||
|
||||
// Should set this up as an option
|
||||
if (chunkedMode) {
|
||||
conn.setChunkedStreamingMode(maxBufferSize);
|
||||
}
|
||||
|
||||
dos = new DataOutputStream( conn.getOutputStream() );
|
||||
|
||||
// Send any extra parameters
|
||||
@@ -274,7 +280,7 @@ public class FileTransfer extends Plugin {
|
||||
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"" + key.toString() + "\";");
|
||||
dos.writeBytes(LINE_END + LINE_END);
|
||||
dos.writeBytes(params.getString(key.toString()));
|
||||
dos.write(params.getString(key.toString()).getBytes());
|
||||
dos.writeBytes(LINE_END);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
@@ -357,6 +363,9 @@ public class FileTransfer extends Plugin {
|
||||
Uri uri = Uri.parse(path);
|
||||
return ctx.getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else if (path.startsWith("file://")) {
|
||||
return new FileInputStream(path.substring(7));
|
||||
}
|
||||
else {
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class FileUtils extends Plugin {
|
||||
else if (action.equals("requestFileSystem")) {
|
||||
long size = args.optLong(1);
|
||||
if (size != 0) {
|
||||
if (size > DirectoryManager.getFreeDiskSpace()) {
|
||||
if (size > (DirectoryManager.getFreeDiskSpace()*1024)) {
|
||||
JSONObject error = new JSONObject().put("code", FileUtils.QUOTA_EXCEEDED_ERR);
|
||||
return new PluginResult(PluginResult.Status.ERROR, error);
|
||||
}
|
||||
@@ -158,6 +158,7 @@ public class FileUtils extends Plugin {
|
||||
success = remove(args.getString(0));
|
||||
|
||||
if (success) {
|
||||
notifyDelete(args.getString(0));
|
||||
return new PluginResult(status);
|
||||
} else {
|
||||
JSONObject error = new JSONObject().put("code", FileUtils.NO_MODIFICATION_ALLOWED_ERR);
|
||||
@@ -221,6 +222,17 @@ public class FileUtils extends Plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Need to check to see if we need to clean up the content store
|
||||
*
|
||||
* @param filePath the path to check
|
||||
*/
|
||||
private void notifyDelete(String filePath) {
|
||||
int result = this.ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Images.Media.DATA + " = ?",
|
||||
new String[] {filePath});
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user to look up the Entry for a file or directory referred to by a local URI.
|
||||
*
|
||||
* @param url of the file/directory to look up
|
||||
|
||||
@@ -41,6 +41,8 @@ public class NetworkManager extends Plugin {
|
||||
public static final String HSPA = "hspa";
|
||||
public static final String HSUPA = "hsupa";
|
||||
public static final String HSDPA = "hsdpa";
|
||||
public static final String ONEXRTT = "1xrtt";
|
||||
public static final String EHRPD = "ehrpd";
|
||||
// 4G network types
|
||||
public static final String LTE = "lte";
|
||||
public static final String UMB = "umb";
|
||||
@@ -208,8 +210,10 @@ public class NetworkManager extends Plugin {
|
||||
type.toLowerCase().equals(EDGE)) {
|
||||
return TYPE_2G;
|
||||
}
|
||||
else if (type.toLowerCase().equals(CDMA) ||
|
||||
else if (type.toLowerCase().startsWith(CDMA) ||
|
||||
type.toLowerCase().equals(UMTS) ||
|
||||
type.toLowerCase().equals(ONEXRTT) ||
|
||||
type.toLowerCase().equals(EHRPD) ||
|
||||
type.toLowerCase().equals(HSUPA) ||
|
||||
type.toLowerCase().equals(HSDPA) ||
|
||||
type.toLowerCase().equals(HSPA)) {
|
||||
|
||||
@@ -87,4 +87,11 @@ public interface IPlugin {
|
||||
*/
|
||||
void onActivityResult(int requestCode, int resultCode, Intent intent);
|
||||
|
||||
}
|
||||
/**
|
||||
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the PhoneGap webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
boolean onOverrideUrlLoading(String url);
|
||||
}
|
||||
Executable
+223
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
|
||||
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
|
||||
*
|
||||
* Copyright (c) 2005-2010, Nitobi Software Inc.
|
||||
* Copyright (c) 2010, IBM Corporation
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Log to Android logging system.
|
||||
*
|
||||
* Log message can be a string or a printf formatted string with arguments.
|
||||
* See http://developer.android.com/reference/java/util/Formatter.html
|
||||
*/
|
||||
public class LOG {
|
||||
|
||||
public static final int VERBOSE = Log.VERBOSE;
|
||||
public static final int DEBUG = Log.DEBUG;
|
||||
public static final int INFO = Log.INFO;
|
||||
public static final int WARN = Log.WARN;
|
||||
public static final int ERROR = Log.ERROR;
|
||||
|
||||
// Current log level
|
||||
public static int LOGLEVEL = Log.ERROR;
|
||||
|
||||
/**
|
||||
* Set the current log level.
|
||||
*
|
||||
* @param logLevel
|
||||
*/
|
||||
public static void setLogLevel(int logLevel) {
|
||||
LOGLEVEL = logLevel;
|
||||
Log.i("PhoneGapLog", "Changing log level to " + logLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current log level.
|
||||
*
|
||||
* @param logLevel
|
||||
*/
|
||||
public static void setLogLevel(String logLevel) {
|
||||
if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
|
||||
else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
|
||||
else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
|
||||
else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
|
||||
else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
|
||||
Log.i("PhoneGapLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if log level will be logged
|
||||
*
|
||||
* @param logLevel
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLoggable(int logLevel) {
|
||||
return (logLevel >= LOGLEVEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void v(String tag, String s) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void d(String tag, String s) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void i(String tag, String s) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void w(String tag, String s) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
*/
|
||||
public static void e(String tag, String s) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void v(String tag, String s, Throwable e) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void d(String tag, String s, Throwable e) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void i(String tag, String s, Throwable e) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void w(String tag, String s, Throwable e) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param e
|
||||
*/
|
||||
public static void e(String tag, String s, Throwable e) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void v(String tag, String s, Object... args) {
|
||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void d(String tag, String s, Object... args) {
|
||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Info log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void i(String tag, String s, Object... args) {
|
||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void w(String tag, String s, Object... args) {
|
||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log message with printf formatting.
|
||||
*
|
||||
* @param tag
|
||||
* @param s
|
||||
* @param args
|
||||
*/
|
||||
public static void e(String tag, String s, Object... args) {
|
||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,4 +47,11 @@ public abstract class PhonegapActivity extends Activity {
|
||||
* @param plugin The plugin on which onActivityResult is to be called
|
||||
*/
|
||||
abstract public void setActivityResultCallback(IPlugin plugin);
|
||||
|
||||
/**
|
||||
* Load the specified URL in the PhoneGap webview.
|
||||
*
|
||||
* @param url The URL to load.
|
||||
*/
|
||||
abstract public void loadUrl(String url);
|
||||
}
|
||||
|
||||
@@ -104,6 +104,16 @@ public abstract class Plugin implements IPlugin {
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the PhoneGap webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send generic JavaScript statement back to JavaScript.
|
||||
* success(...) and error(...) should be used instead where possible.
|
||||
|
||||
@@ -9,6 +9,7 @@ package com.phonegap.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@@ -17,6 +18,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
@@ -25,7 +27,7 @@ import android.webkit.WebView;
|
||||
* Calling native plugin code can be done by calling PluginManager.exec(...)
|
||||
* from JavaScript.
|
||||
*/
|
||||
public final class PluginManager {
|
||||
public final class PluginManager {
|
||||
|
||||
private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
|
||||
private HashMap<String, String> services = new HashMap<String,String>();
|
||||
@@ -33,6 +35,10 @@ public final class PluginManager {
|
||||
private final PhonegapActivity ctx;
|
||||
private final WebView app;
|
||||
|
||||
// Map URL schemes like foo: to plugins that want to handle those schemes
|
||||
// This would allow how all URLs are handled to be offloaded to a plugin
|
||||
protected HashMap<String, String> urlMap = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -53,14 +59,17 @@ public final class PluginManager {
|
||||
if (id == 0) { pluginConfigurationMissing(); }
|
||||
XmlResourceParser xml = ctx.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
String pluginClass = "", pluginName = "";
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("plugin")) {
|
||||
String name = xml.getAttributeValue(null, "name");
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
pluginClass = xml.getAttributeValue(null, "value");
|
||||
pluginName = xml.getAttributeValue(null, "name");
|
||||
//System.out.println("Plugin: "+name+" => "+value);
|
||||
this.addService(name, value);
|
||||
this.addService(pluginName, pluginClass);
|
||||
} else if (strNode.equals("url-filter")) {
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -101,14 +110,9 @@ public final class PluginManager {
|
||||
boolean runAsync = async;
|
||||
try {
|
||||
final JSONArray args = new JSONArray(jsonArgs);
|
||||
String clazz = this.services.get(service);
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = getClassByName(clazz);
|
||||
}
|
||||
if (isPhoneGapPlugin(c)) {
|
||||
final IPlugin plugin = this.addPlugin(clazz, c);
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
final IPlugin plugin = this.getPlugin(service);
|
||||
final PhonegapActivity ctx = this.ctx;
|
||||
if (plugin != null) {
|
||||
runAsync = async && !plugin.isSynch(action);
|
||||
if (runAsync) {
|
||||
// Run this on a different thread so that this one can return back to JS
|
||||
@@ -150,8 +154,6 @@ public final class PluginManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
|
||||
} catch (JSONException e) {
|
||||
System.out.println("ERROR: "+e.toString());
|
||||
cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
@@ -175,7 +177,11 @@ public final class PluginManager {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
return Class.forName(clazz);
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,18 +209,18 @@ public final class PluginManager {
|
||||
* @return The plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private IPlugin addPlugin(String className, Class clazz) {
|
||||
if (this.plugins.containsKey(className)) {
|
||||
return this.getPlugin(className);
|
||||
}
|
||||
try {
|
||||
IPlugin plugin = (IPlugin)clazz.newInstance();
|
||||
this.plugins.put(className, plugin);
|
||||
plugin.setContext(this.ctx);
|
||||
plugin.setView(this.app);
|
||||
return plugin;
|
||||
}
|
||||
catch (Exception e) {
|
||||
private IPlugin addPlugin(String pluginName, String className) {
|
||||
try {
|
||||
Class c = getClassByName(className);
|
||||
if (isPhoneGapPlugin(c)) {
|
||||
IPlugin plugin = (IPlugin)c.newInstance();
|
||||
this.plugins.put(className, plugin);
|
||||
plugin.setContext(this.ctx);
|
||||
plugin.setView(this.app);
|
||||
plugin.onResume(true);
|
||||
return plugin;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error adding plugin "+className+".");
|
||||
}
|
||||
@@ -224,12 +230,18 @@ public final class PluginManager {
|
||||
/**
|
||||
* Get the loaded plugin.
|
||||
*
|
||||
* If the plugin is not already loaded then load it.
|
||||
*
|
||||
* @param className The class of the loaded plugin.
|
||||
* @return
|
||||
*/
|
||||
private IPlugin getPlugin(String className) {
|
||||
IPlugin plugin = this.plugins.get(className);
|
||||
return plugin;
|
||||
private IPlugin getPlugin(String pluginName) {
|
||||
String className = this.services.get(pluginName);
|
||||
if (this.plugins.containsKey(className)) {
|
||||
return this.plugins.get(className);
|
||||
} else {
|
||||
return this.addPlugin(pluginName, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,6 +311,23 @@ public final class PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the URL of the webview changes.
|
||||
*
|
||||
* @param url The URL that is being changed to.
|
||||
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
HashMap.Entry<String, String> pairs = it.next();
|
||||
if (url.startsWith(pairs.getKey())) {
|
||||
return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pluginConfigurationMissing() {
|
||||
System.err.println("=====================================================================================");
|
||||
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");
|
||||
|
||||
Reference in New Issue
Block a user