Merge branch 'master' of github.com:phonegap/phonegap-android

This commit is contained in:
Anis Kadri 2011-08-29 15:46:27 -07:00
commit e2acd1af33
16 changed files with 2280 additions and 4471 deletions

View File

@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.autofocus" />

124
framework/assets/js/battery.js Executable file
View File

@ -0,0 +1,124 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010-2011, IBM Corporation
*/
if (!PhoneGap.hasResource("battery")) {
PhoneGap.addResource("battery");
/**
* This class contains information about the current battery status.
* @constructor
*/
var Battery = function() {
this._level = null;
this._isPlugged = null;
this._batteryListener = [];
this._lowListener = [];
this._criticalListener = [];
};
/**
* Registers as an event producer for battery events.
*
* @param {Object} eventType
* @param {Object} handler
* @param {Object} add
*/
Battery.prototype.eventHandler = function(eventType, handler, add) {
var me = navigator.battery;
if (add) {
// If there are no current registered event listeners start the battery listener on native side.
if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
PhoneGap.exec(me._status, me._error, "Battery", "start", []);
}
// Register the event listener in the proper array
if (eventType === "batterystatus") {
var pos = me._batteryListener.indexOf(handler);
if (pos === -1) {
me._batteryListener.push(handler);
}
} else if (eventType === "batterylow") {
var pos = me._lowListener.indexOf(handler);
if (pos === -1) {
me._lowListener.push(handler);
}
} else if (eventType === "batterycritical") {
var pos = me._criticalListener.indexOf(handler);
if (pos === -1) {
me._criticalListener.push(handler);
}
}
} else {
// Remove the event listener from the proper array
if (eventType === "batterystatus") {
var pos = me._batteryListener.indexOf(handler);
if (pos > -1) {
me._batteryListener.splice(pos, 1);
}
} else if (eventType === "batterylow") {
var pos = me._lowListener.indexOf(handler);
if (pos > -1) {
me._lowListener.splice(pos, 1);
}
} else if (eventType === "batterycritical") {
var pos = me._criticalListener.indexOf(handler);
if (pos > -1) {
me._criticalListener.splice(pos, 1);
}
}
// If there are no more registered event listeners stop the battery listener on native side.
if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
PhoneGap.exec(null, null, "Battery", "stop", []);
}
}
};
/**
* Callback for battery status
*
* @param {Object} info keys: level, isPlugged
*/
Battery.prototype._status = function(info) {
if (info) {
var me = this;
if (me._level != info.level || me._isPlugged != info.isPlugged) {
// Fire batterystatus event
PhoneGap.fireWindowEvent("batterystatus", info);
// Fire low battery event
if (info.level == 20 || info.level == 5) {
if (info.level == 20) {
PhoneGap.fireWindowEvent("batterylow", info);
}
else {
PhoneGap.fireWindowEvent("batterycritical", info);
}
}
}
me._level = info.level;
me._isPlugged = info.isPlugged;
}
};
/**
* Error callback for battery start
*/
Battery.prototype._error = function(e) {
console.log("Error initializing Battery: " + e);
};
PhoneGap.addConstructor(function() {
if (typeof navigator.battery === "undefined") {
navigator.battery = new Battery();
PhoneGap.addWindowEventHandler("batterystatus", navigator.battery.eventHandler);
PhoneGap.addWindowEventHandler("batterylow", navigator.battery.eventHandler);
PhoneGap.addWindowEventHandler("batterycritical", navigator.battery.eventHandler);
}
});
}

View File

@ -155,6 +155,13 @@ Media.prototype.release = function() {
PhoneGap.exec(null, null, "Media", "release", [this.id]); PhoneGap.exec(null, null, "Media", "release", [this.id]);
}; };
/**
* Adjust the volume.
*/
Media.prototype.setVolume = function(volume) {
PhoneGap.exec(null, null, "Media", "setVolume", [this.id, volume]);
};
/** /**
* List of media objects. * List of media objects.
* PRIVATE * PRIVATE

View File

@ -27,7 +27,7 @@ var Connection = function() {
// set a timer if still offline at the end of timer send the offline event // set a timer if still offline at the end of timer send the offline event
me._timer = setTimeout(function(){ me._timer = setTimeout(function(){
me.type = type; me.type = type;
PhoneGap.fireEvent('offline'); PhoneGap.fireDocumentEvent('offline');
me._timer = null; me._timer = null;
}, me.timeout); }, me.timeout);
} else { } else {
@ -37,7 +37,7 @@ var Connection = function() {
me._timer = null; me._timer = null;
} }
me.type = type; me.type = type;
PhoneGap.fireEvent('online'); PhoneGap.fireDocumentEvent('online');
} }
// should only fire this once // should only fire this once
@ -47,6 +47,12 @@ var Connection = function() {
} }
}, },
function(e) { function(e) {
// If we can't get the network info we should still tell PhoneGap
// to fire the deviceready event.
if (me._firstRun) {
me._firstRun = false;
PhoneGap.onPhoneGapConnectionReady.fire();
}
console.log("Error initializing Network Connection: " + e); console.log("Error initializing Network Connection: " + e);
}); });
}; };

View File

@ -46,7 +46,9 @@ var PhoneGap = {
ready: true, ready: true,
commands: [], commands: [],
timer: null timer: null
} },
documentEventHandler: {}, // Collection of custom document event handlers
windowEventHandler: {} // Collection of custom window event handlers
}; };
/** /**
@ -365,6 +367,9 @@ PhoneGap.Channel.join(function() {
// Fire onDeviceReady event once all constructors have run and PhoneGap info has been // Fire onDeviceReady event once all constructors have run and PhoneGap info has been
// received from native side, and any user defined initialization channels. // received from native side, and any user defined initialization channels.
PhoneGap.Channel.join(function() { PhoneGap.Channel.join(function() {
// Let native code know we are inited on JS side
prompt("", "gap_init:");
PhoneGap.onDeviceReady.fire(); PhoneGap.onDeviceReady.fire();
// Fire the onresume event, since first one happens before JavaScript is loaded // Fire the onresume event, since first one happens before JavaScript is loaded
@ -381,6 +386,36 @@ document.addEventListener('DOMContentLoaded', function() {
// Intercept calls to document.addEventListener and watch for deviceready // Intercept calls to document.addEventListener and watch for deviceready
PhoneGap.m_document_addEventListener = document.addEventListener; PhoneGap.m_document_addEventListener = document.addEventListener;
// Intercept calls to window.addEventListener
PhoneGap.m_window_addEventListener = window.addEventListener;
/**
* Add a custom window event handler.
*
* @param {String} event The event name that callback handles
* @param {Function} callback The event handler
*/
PhoneGap.addWindowEventHandler = function(event, callback) {
PhoneGap.windowEventHandler[event] = callback;
}
/**
* Add a custom document event handler.
*
* @param {String} event The event name that callback handles
* @param {Function} callback The event handler
*/
PhoneGap.addDocumentEventHandler = function(event, callback) {
PhoneGap.documentEventHandler[event] = callback;
}
/**
* Intercept adding document event listeners and handle our own
*
* @param {Object} evt
* @param {Function} handler
* @param capture
*/
document.addEventListener = function(evt, handler, capture) { document.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase(); var e = evt.toLowerCase();
if (e === 'deviceready') { if (e === 'deviceready') {
@ -398,15 +433,52 @@ document.addEventListener = function(evt, handler, capture) {
if (e === 'backbutton') { if (e === 'backbutton') {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [true]); PhoneGap.exec(null, null, "App", "overrideBackbutton", [true]);
} }
// If subscribing to an event that is handled by a plugin
else if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
if (PhoneGap.documentEventHandler[e](e, handler, true)) {
return; // Stop default behavior
}
}
PhoneGap.m_document_addEventListener.call(document, evt, handler, capture); PhoneGap.m_document_addEventListener.call(document, evt, handler, capture);
} }
}; };
/**
* Intercept adding window event listeners and handle our own
*
* @param {Object} evt
* @param {Function} handler
* @param capture
*/
window.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
// If subscribing to an event that is handled by a plugin
if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
if (PhoneGap.windowEventHandler[e](e, handler, true)) {
return; // Stop default behavior
}
}
PhoneGap.m_window_addEventListener.call(window, 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 // are generated by PhoneGap native code
PhoneGap.m_document_removeEventListener = document.removeEventListener; PhoneGap.m_document_removeEventListener = document.removeEventListener;
// Intercept calls to window.removeEventListener
PhoneGap.m_window_removeEventListener = window.removeEventListener;
/**
* Intercept removing document event listeners and handle our own
*
* @param {Object} evt
* @param {Function} handler
* @param capture
*/
document.removeEventListener = function(evt, handler, capture) { document.removeEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase(); var e = evt.toLowerCase();
@ -415,18 +487,70 @@ document.removeEventListener = function(evt, handler, capture) {
PhoneGap.exec(null, null, "App", "overrideBackbutton", [false]); PhoneGap.exec(null, null, "App", "overrideBackbutton", [false]);
} }
// If unsubcribing from an event that is handled by a plugin
if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
if (PhoneGap.documentEventHandler[e](e, handler, false)) {
return; // Stop default behavior
}
}
PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture); PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
}; };
/** /**
* Method to fire event from native code * Intercept removing window event listeners and handle our own
*
* @param {Object} evt
* @param {Function} handler
* @param capture
*/ */
PhoneGap.fireEvent = function(type) { window.removeEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
// If unsubcribing from an event that is handled by a plugin
if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
if (PhoneGap.windowEventHandler[e](e, handler, false)) {
return; // Stop default behavior
}
}
PhoneGap.m_window_removeEventListener.call(window, evt, handler, capture);
};
/**
* Method to fire document event
*
* @param {String} type The event type to fire
* @param {Object} data Data to send with event
*/
PhoneGap.fireDocumentEvent = function(type, data) {
var e = document.createEvent('Events'); var e = document.createEvent('Events');
e.initEvent(type); e.initEvent(type);
if (data) {
for (var i in data) {
e[i] = data[i];
}
}
document.dispatchEvent(e); document.dispatchEvent(e);
}; };
/**
* Method to fire window event
*
* @param {String} type The event type to fire
* @param {Object} data Data to send with event
*/
PhoneGap.fireWindowEvent = function(type, data) {
var e = document.createEvent('Events');
e.initEvent(type);
if (data) {
for (var i in data) {
e[i] = data[i];
}
}
window.dispatchEvent(e);
};
/** /**
* If JSON not included, use our own stringify. (Android 1.6) * If JSON not included, use our own stringify. (Android 1.6)
* The restriction on ours is that it must be an array of simple types. * The restriction on ours is that it must be an array of simple types.

File diff suppressed because it is too large Load Diff

View File

@ -16,4 +16,5 @@
<plugin name="Temperature" value="com.phonegap.TempListener"/> <plugin name="Temperature" value="com.phonegap.TempListener"/>
<plugin name="FileTransfer" value="com.phonegap.FileTransfer"/> <plugin name="FileTransfer" value="com.phonegap.FileTransfer"/>
<plugin name="Capture" value="com.phonegap.Capture"/> <plugin name="Capture" value="com.phonegap.Capture"/>
<plugin name="Battery" value="com.phonegap.BatteryListener"/>
</plugins> </plugins>

View File

@ -7,17 +7,15 @@
*/ */
package com.phonegap; package com.phonegap;
import java.util.HashMap; import android.content.Context;
import java.util.Map.Entry; import android.media.AudioManager;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import com.phonegap.api.Plugin; import java.util.HashMap;
import com.phonegap.api.PluginResult; import java.util.Map.Entry;
import android.content.Context;
import android.media.AudioManager;
/** /**
* This class called by PhonegapActivity to play and record audio. * This class called by PhonegapActivity to play and record audio.
@ -71,8 +69,13 @@ public class AudioHandler extends Plugin {
} }
else if (action.equals("stopPlayingAudio")) { else if (action.equals("stopPlayingAudio")) {
this.stopPlayingAudio(args.getString(0)); this.stopPlayingAudio(args.getString(0));
} } else if (action.equals("setVolume")) {
else if (action.equals("getCurrentPositionAudio")) { try {
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
} catch (NumberFormatException nfe) {
//no-op
}
} else if (action.equals("getCurrentPositionAudio")) {
float f = this.getCurrentPositionAudio(args.getString(0)); float f = this.getCurrentPositionAudio(args.getString(0));
return new PluginResult(status, f); return new PluginResult(status, f);
} }
@ -295,5 +298,20 @@ public class AudioHandler extends Plugin {
else { else {
return -1; return -1;
} }
} }
/**
* Set the volume for an audio device
*
* @param id The id of the audio player
* @param volume Volume to adjust to 0.0f - 1.0f
*/
public void setVolume(String id, float volume) {
AudioPlayer audio = this.players.get(id);
if (audio != null) {
audio.setVolume(volume);
} else {
System.out.println("AudioHandler.setVolume() Error: Unknown Audio Player " + id);
}
}
} }

View File

@ -7,8 +7,6 @@
*/ */
package com.phonegap; package com.phonegap;
import java.io.File;
import java.io.IOException;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnCompletionListener;
@ -18,6 +16,9 @@ import android.media.MediaRecorder;
import android.os.Environment; import android.os.Environment;
import android.util.Log; import android.util.Log;
import java.io.File;
import java.io.IOException;
/** /**
* This class implements the audio playback and recording capabilities used by PhoneGap. * This class implements the audio playback and recording capabilities used by PhoneGap.
* It is called by the AudioHandler PhoneGap class. * It is called by the AudioHandler PhoneGap class.
@ -85,7 +86,10 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
// Stop any play or record // Stop any play or record
if (this.mPlayer != null) { if (this.mPlayer != null) {
this.stopPlaying(); if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
this.mPlayer.stop();
this.setState(MEDIA_STOPPED);
}
this.mPlayer.release(); this.mPlayer.release();
this.mPlayer = null; this.mPlayer = null;
} }
@ -417,4 +421,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = state; this.state = state;
} }
/**
* Set the volume for audio player
*
* @param volume
*/
public void setVolume(float volume) {
this.mPlayer.setVolume(volume, volume);
}
} }

View File

@ -0,0 +1,145 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010-2011, IBM Corporation
*/
package com.phonegap;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
public class BatteryListener extends Plugin {
private static final String LOG_TAG = "BatteryManager";
BroadcastReceiver receiver;
private String batteryCallbackId = null;
/**
* Constructor.
*/
public BatteryListener() {
this.receiver = null;
}
/**
* 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.INVALID_ACTION;
String result = "Unsupported Operation: " + action;
if (action.equals("start")) {
if (this.batteryCallbackId != null) {
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
}
this.batteryCallbackId = callbackId;
// We need to listen to power events to update battery status
IntentFilter intentFilter = new IntentFilter() ;
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
if (this.receiver == null) {
this.receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateBatteryInfo(intent);
}
};
ctx.registerReceiver(this.receiver, intentFilter);
}
// Don't return any result now, since status results will be sent when events come in from broadcast receiver
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginResult.setKeepCallback(true);
return pluginResult;
}
else if (action.equals("stop")) {
removeBatteryListener();
this.sendUpdate(new JSONObject(), false); // release status callback in JS side
this.batteryCallbackId = null;
return new PluginResult(PluginResult.Status.OK);
}
return new PluginResult(status, result);
}
/**
* Stop battery receiver.
*/
public void onDestroy() {
removeBatteryListener();
}
/**
* Stop the battery receiver and set it to null.
*/
private void removeBatteryListener() {
if (this.receiver != null) {
try {
this.ctx.unregisterReceiver(this.receiver);
this.receiver = null;
} catch (Exception e) {
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
}
}
}
/**
* Creates a JSONObject with the current battery information
*
* @param batteryIntent the current battery information
* @return a JSONObject containing the battery status information
*/
private JSONObject getBatteryInfo(Intent batteryIntent) {
JSONObject obj = new JSONObject();
try {
obj.put("level", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, 0));
obj.put("isPlugged", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) > 0 ? true : false);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
return obj;
}
/**
* Updates the JavaScript side whenever the battery changes
*
* @param batteryIntent the current battery information
* @return
*/
private void updateBatteryInfo(Intent batteryIntent) {
sendUpdate(this.getBatteryInfo(batteryIntent), true);
}
/**
* Create a new plugin result and send it back to JavaScript
*
* @param connection the network info to set as navigator.connection
*/
private void sendUpdate(JSONObject info, boolean keepCallback) {
if (this.batteryCallbackId != null) {
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
result.setKeepCallback(keepCallback);
this.success(result, this.batteryCallbackId);
}
}
}

View File

@ -35,100 +35,102 @@ import android.util.Log;
*/ */
public class CameraLauncher extends Plugin { public class CameraLauncher extends Plugin {
private static final int DATA_URL = 0; // Return base64 encoded string private static final int DATA_URL = 0; // Return base64 encoded string
private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android) private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
private static final int CAMERA = 1; // Take picture from camera private static final int CAMERA = 1; // Take picture from camera
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android) private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
private static final int JPEG = 0; // Take a picture of type JPEG private static final int JPEG = 0; // Take a picture of type JPEG
private static final int PNG = 1; // Take a picture of type PNG private static final int PNG = 1; // Take a picture of type PNG
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private int targetWidth; // desired width of the image private int targetWidth; // desired width of the image
private int targetHeight; // desired height of the image private int targetHeight; // desired height of the image
private Uri imageUri; // Uri of captured image private Uri imageUri;
public String callbackId; private int encodingType;
// Uri of captured image
public String callbackId;
/** /**
* Constructor. * Constructor.
*/ */
public CameraLauncher() { public CameraLauncher() {
} }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
* @param action The action to execute. * @param action The action to execute.
* @param args JSONArry of arguments for the plugin. * @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK; PluginResult.Status status = PluginResult.Status.OK;
String result = ""; String result = "";
this.callbackId = callbackId; this.callbackId = callbackId;
try { try {
if (action.equals("takePicture")) { if (action.equals("takePicture")) {
int destType = DATA_URL; int destType = DATA_URL;
if (args.length() > 1) { if (args.length() > 1) {
destType = args.getInt(1); destType = args.getInt(1);
} }
int srcType = CAMERA; int srcType = CAMERA;
if (args.length() > 2) { if (args.length() > 2) {
srcType = args.getInt(2); srcType = args.getInt(2);
} }
if (args.length() > 3) { if (args.length() > 3) {
this.targetWidth = args.getInt(3); this.targetWidth = args.getInt(3);
} }
if (args.length() > 4) { if (args.length() > 4) {
this.targetHeight = args.getInt(4); this.targetHeight = args.getInt(4);
} }
int encodingType = JPEG; this.encodingType = JPEG;
if (args.length() > 5) { if (args.length() > 5) {
encodingType = args.getInt(5); this.encodingType = args.getInt(5);
} }
if (srcType == CAMERA) { if (srcType == CAMERA) {
this.takePicture(args.getInt(0), destType, encodingType); this.takePicture(args.getInt(0), destType, encodingType);
} }
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
this.getImage(args.getInt(0), srcType, destType); this.getImage(args.getInt(0), srcType, destType);
} }
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true); r.setKeepCallback(true);
return r; return r;
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
} }
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Take a picture with the camera. * Take a picture with the camera.
* When an image is captured or the camera view is cancelled, the result is returned * When an image is captured or the camera view is cancelled, the result is returned
* in PhonegapActivity.onActivityResult, which forwards the result to this.onActivityResult. * in PhonegapActivity.onActivityResult, which forwards the result to this.onActivityResult.
* *
* The image can either be returned as a base64 string or a URI that points to the file. * The image can either be returned as a base64 string or a URI that points to the file.
* To display base64 string in an img tag, set the source to: * To display base64 string in an img tag, set the source to:
* img.src="data:image/jpeg;base64,"+result; * img.src="data:image/jpeg;base64,"+result;
* or to display URI in an img tag * or to display URI in an img tag
* img.src=result; * img.src=result;
* *
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param returnType Set the type of image to return. * @param returnType Set the type of image to return.
*/ */
public void takePicture(int quality, int returnType, int encodingType) { public void takePicture(int quality, int returnType, int encodingType) {
this.mQuality = quality; this.mQuality = quality;
// Display camera // Display camera
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
@ -138,14 +140,14 @@ public class CameraLauncher extends Plugin {
this.imageUri = Uri.fromFile(photo); this.imageUri = Uri.fromFile(photo);
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1); this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
} }
/** /**
* Create a file in the applications temporary directory based upon the supplied encoding. * Create a file in the applications temporary directory based upon the supplied encoding.
* *
* @param encodingType of the image to be taken * @param encodingType of the image to be taken
* @return a File object pointing to the temporary picture * @return a File object pointing to the temporary picture
*/ */
private File createCaptureFile(int encodingType) { private File createCaptureFile(int encodingType) {
File photo = null; File photo = null;
if (encodingType == JPEG) { if (encodingType == JPEG) {
@ -157,46 +159,46 @@ public class CameraLauncher extends Plugin {
} }
/** /**
* Get image from photo library. * Get image from photo library.
* *
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param srcType The album to get image from. * @param srcType The album to get image from.
* @param returnType Set the type of image to return. * @param returnType Set the type of image to return.
*/ */
// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do! // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
public void getImage(int quality, int srcType, int returnType) { public void getImage(int quality, int srcType, int returnType) {
this.mQuality = quality; this.mQuality = quality;
Intent intent = new Intent(); Intent intent = new Intent();
intent.setType("image/*"); intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT); intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE); intent.addCategory(Intent.CATEGORY_OPENABLE);
this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent, this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
new String("Get Picture")), (srcType+1)*16 + returnType + 1); new String("Get Picture")), (srcType+1)*16 + returnType + 1);
} }
/** /**
* Scales the bitmap according to the requested size. * Scales the bitmap according to the requested size.
* *
* @param bitmap The bitmap to scale. * @param bitmap The bitmap to scale.
* @return Bitmap A new Bitmap object of the same bitmap after scaling. * @return Bitmap A new Bitmap object of the same bitmap after scaling.
*/ */
public Bitmap scaleBitmap(Bitmap bitmap) { public Bitmap scaleBitmap(Bitmap bitmap) {
int newWidth = this.targetWidth; int newWidth = this.targetWidth;
int newHeight = this.targetHeight; int newHeight = this.targetHeight;
int origWidth = bitmap.getWidth(); int origWidth = bitmap.getWidth();
int origHeight = bitmap.getHeight(); int origHeight = bitmap.getHeight();
// If no new width or height were specified return the original bitmap // If no new width or height were specified return the original bitmap
if (newWidth <= 0 && newHeight <= 0) { if (newWidth <= 0 && newHeight <= 0) {
return bitmap; return bitmap;
} }
// Only the width was specified // Only the width was specified
else if (newWidth > 0 && newHeight <= 0) { else if (newWidth > 0 && newHeight <= 0) {
newHeight = (newWidth * origHeight) / origWidth; newHeight = (newWidth * origHeight) / origWidth;
} }
// only the height was specified // only the height was specified
else if (newWidth <= 0 && newHeight > 0) { else if (newWidth <= 0 && newHeight > 0) {
newWidth = (newHeight * origWidth) / origHeight; newWidth = (newHeight * origWidth) / origHeight;
} }
// If the user specified both a positive width and height // If the user specified both a positive width and height
@ -205,7 +207,7 @@ public class CameraLauncher extends Plugin {
// Alternatively, the specified width and height could have been // Alternatively, the specified width and height could have been
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
// would result in whitespace in the new image. // would result in whitespace in the new image.
else { else {
double newRatio = newWidth / (double)newHeight; double newRatio = newWidth / (double)newHeight;
double origRatio = origWidth / (double)origHeight; double origRatio = origWidth / (double)origHeight;
@ -217,156 +219,169 @@ public class CameraLauncher extends Plugin {
} }
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
} }
/** /**
* Called when the camera view exits. * Called when the camera view exits.
* *
* @param requestCode The request code originally supplied to startActivityForResult(), * @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from. * allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult(). * @param resultCode The integer result code returned by the child activity through its setResult().
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/ */
public void onActivityResult(int requestCode, int resultCode, Intent intent) { public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Get src and dest types from request code // Get src and dest types from request code
int srcType = (requestCode/16) - 1; int srcType = (requestCode/16) - 1;
int destType = (requestCode % 16) - 1; int destType = (requestCode % 16) - 1;
// If CAMERA // If CAMERA
if (srcType == CAMERA) { if (srcType == CAMERA) {
// If image available // If image available
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
try { try {
// Read in bitmap of captured image // Create an ExifHelper to save the exif data that is lost during compression
Bitmap bitmap; ExifHelper exif = new ExifHelper();
try { if (this.encodingType == JPEG) {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri); exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Pic.jpg");
} catch (FileNotFoundException e) { exif.readExifData();
Uri uri = intent.getData(); }
android.content.ContentResolver resolver = this.ctx.getContentResolver();
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
}
bitmap = scaleBitmap(bitmap); // Read in bitmap of captured image
Bitmap bitmap;
// If sending base64 image back try {
if (destType == DATA_URL) { bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
this.processPicture(bitmap); } catch (FileNotFoundException e) {
} Uri uri = intent.getData();
android.content.ContentResolver resolver = this.ctx.getContentResolver();
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
}
// If sending filename back bitmap = scaleBitmap(bitmap);
else if (destType == FILE_URI){
// Create entry in media store for image // If sending base64 image back
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it) if (destType == DATA_URL) {
ContentValues values = new ContentValues(); this.processPicture(bitmap);
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); }
Uri uri = null;
try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException e) {
System.out.println("Can't write to external media storage.");
try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException ex) {
System.out.println("Can't write to internal media storage.");
this.failPicture("Error capturing image - no media storage found.");
return;
}
}
// Add compressed version of captured image to returned media store Uri // If sending filename back
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri); else if (destType == FILE_URI){
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); // Create entry in media store for image
os.close(); // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
ContentValues values = new ContentValues();
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = null;
try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException e) {
System.out.println("Can't write to external media storage.");
try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException ex) {
System.out.println("Can't write to internal media storage.");
this.failPicture("Error capturing image - no media storage found.");
return;
}
}
// Send Uri back to JavaScript for viewing image // Add compressed version of captured image to returned media store Uri
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
} bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
bitmap.recycle(); os.close();
bitmap = null;
System.gc(); // Restore exif data to file
} catch (IOException e) { if (this.encodingType == JPEG) {
e.printStackTrace(); exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
this.failPicture("Error capturing image."); exif.writeExifData();
} }
}
// If cancelled // Send Uri back to JavaScript for viewing image
else if (resultCode == Activity.RESULT_CANCELED) { this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
this.failPicture("Camera cancelled."); }
} bitmap.recycle();
bitmap = null;
System.gc();
} catch (IOException e) {
e.printStackTrace();
this.failPicture("Error capturing image.");
}
}
// If something else // If cancelled
else { else if (resultCode == Activity.RESULT_CANCELED) {
this.failPicture("Did not complete!"); this.failPicture("Camera cancelled.");
} }
}
// If something else
// If retrieving photo from library else {
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { this.failPicture("Did not complete!");
if (resultCode == Activity.RESULT_OK) { }
Uri uri = intent.getData(); }
android.content.ContentResolver resolver = this.ctx.getContentResolver();
// If sending base64 image back // If retrieving photo from library
if (destType == DATA_URL) { else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
try { if (resultCode == Activity.RESULT_OK) {
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); Uri uri = intent.getData();
bitmap = scaleBitmap(bitmap); android.content.ContentResolver resolver = this.ctx.getContentResolver();
this.processPicture(bitmap); // If sending base64 image back
bitmap.recycle(); if (destType == DATA_URL) {
bitmap = null; try {
System.gc(); Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
} catch (FileNotFoundException e) { bitmap = scaleBitmap(bitmap);
e.printStackTrace(); this.processPicture(bitmap);
this.failPicture("Error retrieving image."); bitmap.recycle();
} bitmap = null;
} System.gc();
} catch (FileNotFoundException e) {
// If sending filename back e.printStackTrace();
else if (destType == FILE_URI) { this.failPicture("Error retrieving image.");
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); }
} }
}
else if (resultCode == Activity.RESULT_CANCELED) { // If sending filename back
this.failPicture("Selection cancelled."); else if (destType == FILE_URI) {
} this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
else { }
this.failPicture("Selection did not complete!"); }
} else if (resultCode == Activity.RESULT_CANCELED) {
} this.failPicture("Selection cancelled.");
} }
else {
/** this.failPicture("Selection did not complete!");
* Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript. }
* }
* @param bitmap }
*/
public void processPicture(Bitmap bitmap) { /**
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream(); * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
try { *
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) { * @param bitmap
byte[] code = jpeg_data.toByteArray(); */
byte[] output = Base64.encodeBase64(code); public void processPicture(Bitmap bitmap) {
String js_out = new String(output); ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId); try {
js_out = null; if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
output = null; byte[] code = jpeg_data.toByteArray();
code = null; byte[] output = Base64.encodeBase64(code);
} String js_out = new String(output);
} this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
catch(Exception e) { js_out = null;
this.failPicture("Error compressing image."); output = null;
} code = null;
jpeg_data = null; }
} }
catch(Exception e) {
/** this.failPicture("Error compressing image.");
* Send error message to JavaScript. }
* jpeg_data = null;
* @param err }
*/
public void failPicture(String err) { /**
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId); * Send error message to JavaScript.
} *
} * @param err
*/
public void failPicture(String err) {
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
}
}

View File

@ -18,12 +18,10 @@ import org.json.JSONObject;
import android.app.Activity; import android.app.Activity;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.net.Uri; import android.net.Uri;
import android.os.Environment;
import android.util.Log; import android.util.Log;
import com.phonegap.api.Plugin; import com.phonegap.api.Plugin;
@ -31,146 +29,145 @@ import com.phonegap.api.PluginResult;
public class Capture extends Plugin { public class Capture extends Plugin {
private static final String _DATA = "_data"; // The column name where the file path is stored private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
private static final int CAPTURE_AUDIO = 0; // Constant for capture audio private static final int CAPTURE_IMAGE = 1; // Constant for capture image
private static final int CAPTURE_IMAGE = 1; // Constant for capture image private static final int CAPTURE_VIDEO = 2; // Constant for capture video
private static final int CAPTURE_VIDEO = 2; // Constant for capture video private static final String LOG_TAG = "Capture";
private static final String LOG_TAG = "Capture"; private String callbackId; // The ID of the callback to be invoked with our result
private String callbackId; // The ID of the callback to be invoked with our result private long limit; // the number of pics/vids/clips to take
private long limit; // the number of pics/vids/clips to take private double duration; // optional duration parameter for video recording
private double duration; // optional duration parameter for video recording private JSONArray results; // The array of results to be returned to the user
private JSONArray results; // The array of results to be returned to the user private Uri imageUri; // Uri of captured image
private Uri imageUri; // Uri of captured image
@Override @Override
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
this.callbackId = callbackId; this.callbackId = callbackId;
this.limit = 1; this.limit = 1;
this.duration = 0.0f; this.duration = 0.0f;
this.results = new JSONArray(); this.results = new JSONArray();
JSONObject options = args.optJSONObject(0); JSONObject options = args.optJSONObject(0);
if (options != null) { if (options != null) {
limit = options.optLong("limit", 1); limit = options.optLong("limit", 1);
duration = options.optDouble("duration", 0.0f); duration = options.optDouble("duration", 0.0f);
} }
if (action.equals("getFormatData")) { if (action.equals("getFormatData")) {
try { try {
JSONObject obj = getFormatData(args.getString(0), args.getString(1)); JSONObject obj = getFormatData(args.getString(0), args.getString(1));
return new PluginResult(PluginResult.Status.OK, obj); return new PluginResult(PluginResult.Status.OK, obj);
} catch (JSONException e) { } catch (JSONException e) {
return new PluginResult(PluginResult.Status.ERROR); return new PluginResult(PluginResult.Status.ERROR);
} }
} }
else if (action.equals("captureAudio")) { else if (action.equals("captureAudio")) {
this.captureAudio(); this.captureAudio();
} }
else if (action.equals("captureImage")) { else if (action.equals("captureImage")) {
this.captureImage(); this.captureImage();
} }
else if (action.equals("captureVideo")) { else if (action.equals("captureVideo")) {
this.captureVideo(duration); this.captureVideo(duration);
} }
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true); r.setKeepCallback(true);
return r; return r;
} }
/** /**
* Provides the media data file data depending on it's mime type * Provides the media data file data depending on it's mime type
* *
* @param filePath path to the file * @param filePath path to the file
* @param mimeType of the file * @param mimeType of the file
* @return a MediaFileData object * @return a MediaFileData object
*/ */
private JSONObject getFormatData(String filePath, String mimeType) { private JSONObject getFormatData(String filePath, String mimeType) {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
try { try {
// setup defaults // setup defaults
obj.put("height", 0); obj.put("height", 0);
obj.put("width", 0); obj.put("width", 0);
obj.put("bitrate", 0); obj.put("bitrate", 0);
obj.put("duration", 0); obj.put("duration", 0);
obj.put("codecs", ""); obj.put("codecs", "");
// If the mimeType isn't set the rest will fail // If the mimeType isn't set the rest will fail
// so let's see if we can determine it. // so let's see if we can determine it.
if (mimeType == null || mimeType.equals("")) { if (mimeType == null || mimeType.equals("")) {
mimeType = FileUtils.getMimeType(filePath); mimeType = FileUtils.getMimeType(filePath);
} }
if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) { if (mimeType.equals("image/jpeg") || filePath.endsWith(".jpg")) {
obj = getImageData(filePath, obj); obj = getImageData(filePath, obj);
} }
else if (filePath.endsWith("audio/3gpp")) { else if (filePath.endsWith("audio/3gpp")) {
obj = getAudioVideoData(filePath, obj, false); obj = getAudioVideoData(filePath, obj, false);
} }
else if (mimeType.equals("video/3gpp")) { else if (mimeType.equals("video/3gpp")) {
obj = getAudioVideoData(filePath, obj, true); obj = getAudioVideoData(filePath, obj, true);
} }
} }
catch (JSONException e) { catch (JSONException e) {
Log.d(LOG_TAG, "Error: setting media file data object"); Log.d(LOG_TAG, "Error: setting media file data object");
} }
return obj; return obj;
} }
/** /**
* Get the Image specific attributes * Get the Image specific attributes
* *
* @param filePath path to the file * @param filePath path to the file
* @param obj represents the Media File Data * @param obj represents the Media File Data
* @return a JSONObject that represents the Media File Data * @return a JSONObject that represents the Media File Data
* @throws JSONException * @throws JSONException
*/ */
private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException { private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
Bitmap bitmap = BitmapFactory.decodeFile(filePath); Bitmap bitmap = BitmapFactory.decodeFile(filePath);
obj.put("height", bitmap.getHeight()); obj.put("height", bitmap.getHeight());
obj.put("width", bitmap.getWidth()); obj.put("width", bitmap.getWidth());
return obj; return obj;
} }
/** /**
* Get the Image specific attributes * Get the Image specific attributes
* *
* @param filePath path to the file * @param filePath path to the file
* @param obj represents the Media File Data * @param obj represents the Media File Data
* @param video if true get video attributes as well * @param video if true get video attributes as well
* @return a JSONObject that represents the Media File Data * @return a JSONObject that represents the Media File Data
* @throws JSONException * @throws JSONException
*/ */
private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException { private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException {
MediaPlayer player = new MediaPlayer(); MediaPlayer player = new MediaPlayer();
try { try {
player.setDataSource(filePath); player.setDataSource(filePath);
player.prepare(); player.prepare();
obj.put("duration", player.getDuration()); obj.put("duration", player.getDuration());
if (video) { if (video) {
obj.put("height", player.getVideoHeight()); obj.put("height", player.getVideoHeight());
obj.put("width", player.getVideoWidth()); obj.put("width", player.getVideoWidth());
} }
} }
catch (IOException e) { catch (IOException e) {
Log.d(LOG_TAG, "Error: loading video file"); Log.d(LOG_TAG, "Error: loading video file");
} }
return obj; return obj;
} }
/** /**
* Sets up an intent to capture audio. Result handled by onActivityResult() * Sets up an intent to capture audio. Result handled by onActivityResult()
*/ */
private void captureAudio() { private void captureAudio() {
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION); Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
} }
/** /**
* Sets up an intent to capture images. Result handled by onActivityResult() * Sets up an intent to capture images. Result handled by onActivityResult()
*/ */
private void captureImage() { private void captureImage() {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
@ -181,179 +178,174 @@ public class Capture extends Plugin {
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
} }
/** /**
* Sets up an intent to capture video. Result handled by onActivityResult() * Sets up an intent to capture video. Result handled by onActivityResult()
*/ */
private void captureVideo(double duration) { private void captureVideo(double duration) {
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE); Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
// Introduced in API 8 // Introduced in API 8
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration); //intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO); this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
} }
/** /**
* Called when the video view exits. * Called when the video view exits.
* *
* @param requestCode The request code originally supplied to startActivityForResult(), * @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from. * allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult(). * @param resultCode The integer result code returned by the child activity through its setResult().
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
* @throws JSONException * @throws JSONException
*/ */
public void onActivityResult(int requestCode, int resultCode, Intent intent) { public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Result received okay // Result received okay
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
// An audio clip was requested // An audio clip was requested
if (requestCode == CAPTURE_AUDIO) { if (requestCode == CAPTURE_AUDIO) {
// Get the uri of the audio clip // Get the uri of the audio clip
Uri data = intent.getData(); Uri data = intent.getData();
// create a file object from the uri // create a file object from the uri
results.put(createMediaFile(data)); results.put(createMediaFile(data));
if (results.length() >= limit) { if (results.length() >= limit) {
// Send Uri back to JavaScript for listening to audio // Send Uri back to JavaScript for listening to audio
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
} else { } else {
// still need to capture more audio clips // still need to capture more audio clips
captureAudio(); captureAudio();
} }
} else if (requestCode == CAPTURE_IMAGE) { } else if (requestCode == CAPTURE_IMAGE) {
// For some reason if I try to do: // For some reason if I try to do:
// Uri data = intent.getData(); // Uri data = intent.getData();
// It crashes in the emulator and on my phone with a null pointer exception // It crashes in the emulator and on my phone with a null pointer exception
// To work around it I had to grab the code from CameraLauncher.java // To work around it I had to grab the code from CameraLauncher.java
try { try {
// Read in bitmap of captured image // Create an ExifHelper to save the exif data that is lost during compression
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri); ExifHelper exif = new ExifHelper();
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx) + "/Capture.jpg");
exif.readExifData();
// Read in bitmap of captured image
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
// Create entry in media store for image // Create entry in media store for image
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it) // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
ContentValues values = new ContentValues(); 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; Uri uri = null;
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
System.out.println("Can't write to external media storage."); System.out.println("Can't write to external media storage.");
try { try {
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values); uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
} catch (UnsupportedOperationException ex) { } catch (UnsupportedOperationException ex) {
System.out.println("Can't write to internal media storage."); System.out.println("Can't write to internal media storage.");
this.fail("Error capturing image - no media storage found."); this.fail("Error capturing image - no media storage found.");
return; return;
} }
} }
// Add compressed version of captured image to returned media store Uri // Add compressed version of captured image to returned media store Uri
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri); OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.close(); os.close();
bitmap.recycle(); bitmap.recycle();
bitmap = null; bitmap = null;
System.gc(); System.gc();
// Add image to results // Restore exif data to file
results.put(createMediaFile(uri)); exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
exif.writeExifData();
if (results.length() >= limit) {
// Send Uri back to JavaScript for viewing image // Add image to results
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId); results.put(createMediaFile(uri));
} else {
// still need to capture more images if (results.length() >= limit) {
captureImage(); // Send Uri back to JavaScript for viewing image
} this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
} catch (IOException e) { } else {
e.printStackTrace(); // still need to capture more images
this.fail("Error capturing image."); captureImage();
} }
} else if (requestCode == CAPTURE_VIDEO) { } catch (IOException e) {
// Get the uri of the video clip e.printStackTrace();
Uri data = intent.getData(); this.fail("Error capturing image.");
// create a file object from the uri }
results.put(createMediaFile(data)); } else if (requestCode == CAPTURE_VIDEO) {
// Get the uri of the video clip
Uri data = intent.getData();
// create a file object from the uri
results.put(createMediaFile(data));
if (results.length() >= limit) { if (results.length() >= limit) {
// Send Uri back to JavaScript for viewing video // Send Uri back to JavaScript for viewing video
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
} else { } else {
// still need to capture more video clips // still need to capture more video clips
captureVideo(duration); captureVideo(duration);
} }
} }
} }
// If canceled // If canceled
else if (resultCode == Activity.RESULT_CANCELED) { else if (resultCode == Activity.RESULT_CANCELED) {
// If we have partial results send them back to the user // If we have partial results send them back to the user
if (results.length() > 0) { if (results.length() > 0) {
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
} }
// user canceled the action // user canceled the action
else { else {
this.fail("Canceled."); this.fail("Canceled.");
} }
} }
// If something else // If something else
else { else {
// If we have partial results send them back to the user // If we have partial results send them back to the user
if (results.length() > 0) { if (results.length() > 0) {
this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId); this.success(new PluginResult(PluginResult.Status.OK, results, "navigator.device.capture._castMediaFile"), this.callbackId);
} }
// something bad happened // something bad happened
else { else {
this.fail("Did not complete!"); this.fail("Did not complete!");
} }
} }
}
/**
* Creates a JSONObject that represents a File from the Uri
*
* @param data the Uri of the audio/image/video
* @return a JSONObject that represents a File
*/
private JSONObject createMediaFile(Uri data) {
File fp = new File(getRealPathFromURI(data));
JSONObject obj = new JSONObject();
try {
// File properties
obj.put("name", fp.getName());
obj.put("fullPath", fp.getAbsolutePath());
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
obj.put("lastModifiedDate", fp.lastModified());
obj.put("size", fp.length());
} catch (JSONException e) {
// this will never happen
e.printStackTrace();
}
return obj;
}
/**
* Queries the media store to find out what the file path is for the Uri we supply
*
* @param contentUri the Uri of the audio/image/video
* @return the full path to the file
*/
private String getRealPathFromURI(Uri contentUri) {
String[] proj = { _DATA };
Cursor cursor = this.ctx.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(_DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} }
/** /**
* Send error message to JavaScript. * Creates a JSONObject that represents a File from the Uri
* *
* @param err * @param data the Uri of the audio/image/video
*/ * @return a JSONObject that represents a File
public void fail(String err) { * @throws IOException
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId); */
} private JSONObject createMediaFile(Uri data){
File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
JSONObject obj = new JSONObject();
try {
// File properties
obj.put("name", fp.getName());
obj.put("fullPath", fp.getAbsolutePath());
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
obj.put("lastModifiedDate", fp.lastModified());
obj.put("size", fp.length());
} catch (JSONException e) {
// this will never happen
e.printStackTrace();
}
return obj;
}
/**
* Send error message to JavaScript.
*
* @param err
*/
public void fail(String err) {
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
}
} }

1785
framework/src/com/phonegap/DroidGap.java Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,153 @@
/*
* 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) 2011, IBM Corporation
*/
package com.phonegap;
import java.io.IOException;
import android.media.ExifInterface;
public class ExifHelper {
private String aperature = null;
private String datetime = null;
private String exposureTime = null;
private String flash = null;
private String focalLength = null;
private String gpsAltitude = null;
private String gpsAltitudeRef = null;
private String gpsDateStamp = null;
private String gpsLatitude = null;
private String gpsLatitudeRef = null;
private String gpsLongitude = null;
private String gpsLongitudeRef = null;
private String gpsProcessingMethod = null;
private String gpsTimestamp = null;
private String iso = null;
private String make = null;
private String model = null;
private String orientation = null;
private String whiteBalance = null;
private ExifInterface inFile = null;
private ExifInterface outFile = null;
/**
* The file before it is compressed
*
* @param filePath
* @throws IOException
*/
public void createInFile(String filePath) throws IOException {
this.inFile = new ExifInterface(filePath);
}
/**
* The file after it has been compressed
*
* @param filePath
* @throws IOException
*/
public void createOutFile(String filePath) throws IOException {
this.outFile = new ExifInterface(filePath);
}
/**
* Reads all the EXIF data from the input file.
*/
public void readExifData() {
this.aperature = inFile.getAttribute(ExifInterface.TAG_APERTURE);
this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
}
/**
* Writes the previously stored EXIF data to the output file.
*
* @throws IOException
*/
public void writeExifData() throws IOException {
// Don't try to write to a null file
if (this.outFile == null) {
return;
}
if (this.aperature != null) {
this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperature);
}
if (this.datetime != null) {
this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
}
if (this.exposureTime != null) {
this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
}
if (this.flash != null) {
this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
}
if (this.focalLength != null) {
this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
}
if (this.gpsAltitude != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
}
if (this.gpsAltitudeRef != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
}
if (this.gpsDateStamp != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
}
if (this.gpsLatitude != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
}
if (this.gpsLatitudeRef != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
}
if (this.gpsLongitude != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
}
if (this.gpsLongitudeRef != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
}
if (this.gpsProcessingMethod != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
}
if (this.gpsTimestamp != null) {
this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
}
if (this.iso != null) {
this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
}
if (this.make != null) {
this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
}
if (this.model != null) {
this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
}
if (this.orientation != null) {
this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
}
if (this.whiteBalance != null) {
this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
}
this.outFile.saveAttributes();
}
}

View File

@ -25,6 +25,7 @@ import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import com.phonegap.api.PhonegapActivity;
import com.phonegap.api.Plugin; import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult; import com.phonegap.api.PluginResult;
import com.phonegap.file.EncodingException; import com.phonegap.file.EncodingException;
@ -39,7 +40,8 @@ import com.phonegap.file.TypeMismatchException;
*/ */
public class FileUtils extends Plugin { public class FileUtils extends Plugin {
private static final String LOG_TAG = "FileUtils"; private static final String LOG_TAG = "FileUtils";
private static final String _DATA = "_data"; // The column name where the file path is stored
public static int NOT_FOUND_ERR = 1; public static int NOT_FOUND_ERR = 1;
public static int SECURITY_ERR = 2; public static int SECURITY_ERR = 2;
public static int ABORT_ERR = 3; public static int ABORT_ERR = 3;
@ -988,5 +990,19 @@ public class FileUtils extends Plugin {
return new FileInputStream(path); return new FileInputStream(path);
} }
} }
/**
* Queries the media store to find out what the file path is for the Uri we supply
*
* @param contentUri the Uri of the audio/image/video
* @param ctx the current applicaiton context
* @return the full path to the file
*/
protected static String getRealPathFromURI(Uri contentUri, PhonegapActivity ctx) {
String[] proj = { _DATA };
Cursor cursor = ctx.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(_DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
} }

View File

@ -22,201 +22,209 @@ import android.net.NetworkInfo;
import android.util.Log; import android.util.Log;
public class NetworkManager extends Plugin { 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_CARRIER_DATA_NETWORK = 1;
public static int REACHABLE_VIA_WIFI_NETWORK = 2; public static int REACHABLE_VIA_WIFI_NETWORK = 2;
public static final String WIFI = "wifi"; public static final String WIFI = "wifi";
public static final String WIMAX = "wimax"; public static final String WIMAX = "wimax";
// mobile // mobile
public static final String MOBILE = "mobile"; public static final String MOBILE = "mobile";
// 2G network types // 2G network types
public static final String GSM = "gsm"; public static final String GSM = "gsm";
public static final String GPRS = "gprs"; public static final String GPRS = "gprs";
public static final String EDGE = "edge"; public static final String EDGE = "edge";
// 3G network types // 3G network types
public static final String CDMA = "cdma"; public static final String CDMA = "cdma";
public static final String UMTS = "umts"; public static final String UMTS = "umts";
// 4G network types public static final String HSPA = "hspa";
public static final String LTE = "lte"; public static final String HSUPA = "hsupa";
public static final String UMB = "umb"; public static final String HSDPA = "hsdpa";
// return types // 4G network types
public static final String TYPE_UNKNOWN = "unknown"; public static final String LTE = "lte";
public static final String TYPE_ETHERNET = "ethernet"; public static final String UMB = "umb";
public static final String TYPE_WIFI = "wifi"; public static final String HSPA_PLUS = "hspa+";
public static final String TYPE_2G = "2g"; // return types
public static final String TYPE_3G = "3g"; public static final String TYPE_UNKNOWN = "unknown";
public static final String TYPE_4G = "4g"; public static final String TYPE_ETHERNET = "ethernet";
public static final String TYPE_NONE = "none"; public static final String TYPE_WIFI = "wifi";
public static final String TYPE_2G = "2g";
private static final String LOG_TAG = "NetworkManager"; public static final String TYPE_3G = "3g";
public static final String TYPE_4G = "4g";
public static final String TYPE_NONE = "none";
private static final String LOG_TAG = "NetworkManager";
private String connectionCallbackId; private String connectionCallbackId;
ConnectivityManager sockMan; ConnectivityManager sockMan;
BroadcastReceiver receiver; BroadcastReceiver receiver;
/** /**
* Constructor. * Constructor.
*/ */
public NetworkManager() { public NetworkManager() {
this.receiver = null; this.receiver = null;
} }
/** /**
* Sets the context of the Command. This can then be used to do things like * Sets the context of the Command. This can then be used to do things like
* get file paths associated with the Activity. * get file paths associated with the Activity.
* *
* @param ctx The context of the main Activity. * @param ctx The context of the main Activity.
*/ */
public void setContext(PhonegapActivity ctx) { public void setContext(PhonegapActivity ctx) {
super.setContext(ctx); super.setContext(ctx);
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
this.connectionCallbackId = null; this.connectionCallbackId = null;
// We need to listen to connectivity events to update navigator.connection // We need to listen to connectivity events to update navigator.connection
IntentFilter intentFilter = new IntentFilter() ; IntentFilter intentFilter = new IntentFilter() ;
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
if (this.receiver == null) { if (this.receiver == null) {
this.receiver = new BroadcastReceiver() { this.receiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)); updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
} }
}; };
ctx.registerReceiver(this.receiver, intentFilter); ctx.registerReceiver(this.receiver, intentFilter);
} }
} }
/** /**
* Executes the request and returns PluginResult. * Executes the request and returns PluginResult.
* *
* @param action The action to execute. * @param action The action to execute.
* @param args JSONArry of arguments for the plugin. * @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript. * @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message. * @return A PluginResult object with a status and message.
*/ */
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.INVALID_ACTION; PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
String result = "Unsupported Operation: " + action; String result = "Unsupported Operation: " + action;
if (action.equals("getConnectionInfo")) { if (action.equals("getConnectionInfo")) {
this.connectionCallbackId = callbackId; this.connectionCallbackId = callbackId;
NetworkInfo info = sockMan.getActiveNetworkInfo(); NetworkInfo info = sockMan.getActiveNetworkInfo();
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info)); PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
pluginResult.setKeepCallback(true); pluginResult.setKeepCallback(true);
return pluginResult; return pluginResult;
} }
return new PluginResult(status, result); return new PluginResult(status, result);
} }
/** /**
* Identifies if action to be executed returns a value and should be run synchronously. * Identifies if action to be executed returns a value and should be run synchronously.
* *
* @param action The action to execute * @param action The action to execute
* @return T=returns value * @return T=returns value
*/ */
public boolean isSynch(String action) { public boolean isSynch(String action) {
// All methods take a while, so always use async // All methods take a while, so always use async
return false; return false;
} }
/** /**
* Stop network receiver. * Stop network receiver.
*/ */
public void onDestroy() { public void onDestroy() {
if (this.receiver != null) { if (this.receiver != null) {
try { try {
this.ctx.unregisterReceiver(this.receiver); this.ctx.unregisterReceiver(this.receiver);
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e); Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
} }
} }
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// LOCAL METHODS // LOCAL METHODS
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/** /**
* Updates the JavaScript side whenever the connection changes * Updates the JavaScript side whenever the connection changes
* *
* @param info the current active network info * @param info the current active network info
* @return * @return
*/ */
private void updateConnectionInfo(NetworkInfo info) { private void updateConnectionInfo(NetworkInfo info) {
// send update to javascript "navigator.network.connection" // send update to javascript "navigator.network.connection"
sendUpdate(this.getConnectionInfo(info)); sendUpdate(this.getConnectionInfo(info));
} }
/** /**
* Get the latest network connection information * Get the latest network connection information
* *
* @param info the current active network info * @param info the current active network info
* @return a JSONObject that represents the network info * @return a JSONObject that represents the network info
*/ */
private String getConnectionInfo(NetworkInfo info) { private String getConnectionInfo(NetworkInfo info) {
String type = TYPE_NONE; String type = TYPE_NONE;
if (info != null) { if (info != null) {
// If we are not connected to any network set type to none // If we are not connected to any network set type to none
if (!info.isConnected()) { if (!info.isConnected()) {
type = TYPE_NONE; type = TYPE_NONE;
} }
else { else {
type = getType(info); type = getType(info);
} }
} }
return type; return type;
} }
/** /**
* Create a new plugin result and send it back to JavaScript * Create a new plugin result and send it back to JavaScript
* *
* @param connection the network info to set as navigator.connection * @param connection the network info to set as navigator.connection
*/ */
private void sendUpdate(String type) { private void sendUpdate(String type) {
PluginResult result = new PluginResult(PluginResult.Status.OK, type); PluginResult result = new PluginResult(PluginResult.Status.OK, type);
result.setKeepCallback(true); result.setKeepCallback(true);
this.success(result, this.connectionCallbackId); this.success(result, this.connectionCallbackId);
} }
/** /**
* Determine the type of connection * Determine the type of connection
* *
* @param info the network info so we can determine connection type. * @param info the network info so we can determine connection type.
* @return the type of mobile network we are on * @return the type of mobile network we are on
*/ */
private String getType(NetworkInfo info) { private String getType(NetworkInfo info) {
if (info != null) { if (info != null) {
String type = info.getTypeName(); String type = info.getTypeName();
if (type.toLowerCase().equals(WIFI)) { if (type.toLowerCase().equals(WIFI)) {
return TYPE_WIFI; return TYPE_WIFI;
} }
else if (type.toLowerCase().equals(MOBILE)) { else if (type.toLowerCase().equals(MOBILE)) {
type = info.getSubtypeName(); type = info.getSubtypeName();
if (type.toLowerCase().equals(GSM) || if (type.toLowerCase().equals(GSM) ||
type.toLowerCase().equals(GPRS) || type.toLowerCase().equals(GPRS) ||
type.toLowerCase().equals(EDGE)) { type.toLowerCase().equals(EDGE)) {
return TYPE_2G; return TYPE_2G;
} }
else if (type.toLowerCase().equals(CDMA) || else if (type.toLowerCase().equals(CDMA) ||
type.toLowerCase().equals(UMTS)) { type.toLowerCase().equals(UMTS) ||
return TYPE_3G; type.toLowerCase().equals(HSUPA) ||
} type.toLowerCase().equals(HSDPA) ||
else if (type.toLowerCase().equals(LTE) || type.toLowerCase().equals(HSPA)) {
type.toLowerCase().equals(UMB)) { return TYPE_3G;
return TYPE_4G; }
} else if (type.toLowerCase().equals(LTE) ||
} type.toLowerCase().equals(UMB) ||
} type.toLowerCase().equals(HSPA_PLUS)) {
else { return TYPE_4G;
return TYPE_NONE; }
} }
return TYPE_UNKNOWN; }
} else {
return TYPE_NONE;
}
return TYPE_UNKNOWN;
}
} }