Change to use Commands and CommandManager.

This commit is contained in:
Bryce Curtis
2010-09-06 13:13:09 -05:00
parent 5c24abcafd
commit 9e931cc3f6
25 changed files with 1671 additions and 557 deletions

157
framework/src/com/phonegap/AccelListener.java Normal file → Executable file
View File

@@ -2,18 +2,27 @@ package com.phonegap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.phonegap.api.Command;
import com.phonegap.api.CommandManager;
import com.phonegap.api.CommandResult;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.content.Context;
import android.content.Intent;
import android.webkit.WebView;
/**
* This class listens to the accelerometer sensor and stores the latest
* acceleration values x,y,z.
*/
public class AccelListener extends Module implements SensorEventListener{
public class AccelListener implements SensorEventListener, Command{
public static int STOPPED = 0;
public static int STARTING = 1;
@@ -22,8 +31,8 @@ public class AccelListener extends Module implements SensorEventListener{
public float TIMEOUT = 30000; // Timeout in msec to shut off listener
WebView mAppView; // WebView object
DroidGap mCtx; // DroidGap object
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
float x,y,z; // most recent acceleration values
long timeStamp; // time of most recent value
@@ -35,22 +44,138 @@ public class AccelListener extends Module implements SensorEventListener{
/**
* Create an accelerometer listener.
*
* @param ctx The Activity (DroidGap) object
* @param appView
*/
public AccelListener(WebView appView, DroidGap ctx) {
super(appView, ctx);
this.mCtx = ctx;
this.mAppView = appView;
this.sensorManager = (SensorManager) mCtx.getSystemService(Context.SENSOR_SERVICE);
public AccelListener() {
this.x = 0;
this.y = 0;
this.z = 0;
this.timeStamp = 0;
this.status = AccelListener.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(DroidGap ctx) {
this.ctx = ctx;
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("getStatus")) {
int i = this.getStatus();
return new CommandResult(status, i);
}
else if (action.equals("start")) {
int i = this.start();
return new CommandResult(status, i);
}
else if (action.equals("stop")) {
this.stop();
return new CommandResult(status, 0);
}
else if (action.equals("getAcceleration")) {
JSONObject r = new JSONObject();
r.put("x", this.x);
r.put("y", this.y);
r.put("z", this.z);
return new CommandResult(status, r);
}
else if (action.equals("getX")) {
float f = this.getX();
return new CommandResult(status, f);
}
else if (action.equals("getY")) {
float f = this.getY();
return new CommandResult(status, f);
}
else if (action.equals("getZ")) {
float f = this.getZ();
return new CommandResult(status, f);
}
else if (action.equals("setTimeout")) {
try {
float timeout = Float.parseFloat(args.getString(0));
this.setTimeout(timeout);
return new CommandResult(status, 0);
} catch (NumberFormatException e) {
status = CommandResult.Status.INVALID_ACTION;
e.printStackTrace();
} catch (JSONException e) {
status = CommandResult.Status.JSON_EXCEPTION;
e.printStackTrace();
}
}
else if (action.equals("getTimeout")) {
float f = this.getTimeout();
return new CommandResult(status, f);
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
this.stop();
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Start listening for acceleration sensor.
*
@@ -91,16 +216,6 @@ public class AccelListener extends Module implements SensorEventListener{
}
this.status = AccelListener.STOPPED;
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
@Override
public void onDestroy() {
super.onDestroy();
this.stop();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub

View File

@@ -3,7 +3,15 @@ package com.phonegap;
import java.util.HashMap;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandManager;
import com.phonegap.api.CommandResult;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.webkit.WebView;
@@ -18,31 +26,98 @@ import android.webkit.WebView;
* android_asset: file name must start with /android_asset/sound.mp3
* sdcard: file name is just sound.mp3
*/
public class AudioHandler extends Module {
public class AudioHandler implements Command {
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
HashMap<String,AudioPlayer> players; // Audio player object
WebView mAppView; // Webview object
DroidGap mCtx; // DroidGap object
/**
* Constructor.
*
* @param view
* @param ctx
*/
public AudioHandler(WebView view, DroidGap ctx) {
super(view, ctx);
this.mAppView = view;
this.mCtx = ctx;
public AudioHandler() {
this.players = new HashMap<String,AudioPlayer>();
}
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("startRecordingAudio")) {
this.startRecordingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("stopRecordingAudio")) {
this.stopRecordingAudio(args.getString(0));
}
else if (action.equals("startPlayingAudio")) {
this.startPlayingAudio(args.getString(0), args.getString(1));
}
else if (action.equals("pausePlayingAudio")) {
this.pausePlayingAudio(args.getString(0));
}
else if (action.equals("stopPlayingAudio")) {
this.stopPlayingAudio(args.getString(0));
}
else if (action.equals("getCurrentPositionAudio")) {
long l = this.getCurrentPositionAudio(args.getString(0));
return new CommandResult(status, l);
}
else if (action.equals("getDurationAudio")) {
long l = this.getDurationAudio(args.getString(0), args.getString(1));
return new CommandResult(status, l);
}
return new CommandResult(status, result);
} catch (JSONException e) {
e.printStackTrace();
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Stop all audio players and recorders.
*/
@Override
public void onDestroy() {
super.onDestroy();
java.util.Set<Entry<String,AudioPlayer>> s = this.players.entrySet();
java.util.Iterator<Entry<String,AudioPlayer>> it = s.iterator();
while(it.hasNext()) {
@@ -52,7 +127,23 @@ public class AudioHandler extends Module {
}
this.players.clear();
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Start recording and save the specified file.
*
@@ -166,7 +257,7 @@ public class AudioHandler extends Module {
* @param output 1=earpiece, 2=speaker
*/
public void setAudioOutputDevice(int output) {
AudioManager audiMgr = (AudioManager) mCtx.getSystemService(Context.AUDIO_SERVICE);
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
if (output == 2) {
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
}
@@ -184,7 +275,7 @@ public class AudioHandler extends Module {
* @return 1=earpiece, 2=speaker
*/
public int getAudioOutputDevice() {
AudioManager audiMgr = (AudioManager) mCtx.getSystemService(Context.AUDIO_SERVICE);
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
return 1;
}

View File

@@ -95,7 +95,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void startRecording(String file) {
if (this.mPlayer != null) {
System.out.println("AudioPlayer Error: Can't record in play mode.");
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PLAY_MODE_SET+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PLAY_MODE_SET+");");
}
// Make sure we're not already recording
@@ -110,18 +110,18 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.recorder.prepare();
this.recorder.start();
this.state = MEDIA_RUNNING;
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
return;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_RECORDING+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_RECORDING+");");
}
else {
System.out.println("AudioPlayer Error: Already recording.");
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_ALREADY_RECORDING+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_ALREADY_RECORDING+");");
}
}
@@ -148,7 +148,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.recorder.stop();
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
this.moveFile(this.audioFile);
}
@@ -166,7 +166,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void startPlaying(String file) {
if (this.recorder != null) {
System.out.println("AudioPlayer Error: Can't play in record mode.");
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RECORD_MODE_SET+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RECORD_MODE_SET+");");
}
// If this is a new request to play audio
@@ -193,7 +193,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
else {
if (file.startsWith("/android_asset/")) {
String f = file.substring(15);
android.content.res.AssetFileDescriptor fd = this.handler.mCtx.getBaseContext().getAssets().openFd(f);
android.content.res.AssetFileDescriptor fd = this.handler.ctx.getBaseContext().getAssets().openFd(f);
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
}
else {
@@ -208,11 +208,11 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = MEDIA_STARTING;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
catch (Exception e) {
e.printStackTrace();
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_PLAYBACK+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_PLAYBACK+");");
}
}
@@ -225,11 +225,11 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = MEDIA_RUNNING;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
else {
System.out.println("AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RESUME_STATE+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RESUME_STATE+");");
}
}
}
@@ -245,11 +245,11 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = MEDIA_PAUSED;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
else {
System.out.println("AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PAUSE_STATE+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PAUSE_STATE+");");
}
}
@@ -262,11 +262,11 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.mPlayer.stop();
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
else {
System.out.println("AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STOP_STATE+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STOP_STATE+");");
}
}
@@ -279,7 +279,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = MEDIA_STOPPED;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
/**
@@ -362,7 +362,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = MEDIA_RUNNING;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_STATE+", "+this.state+");");
}
// Save off duration
@@ -370,7 +370,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.prepareOnly = false;
// Send status notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");");
}
@@ -390,7 +390,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.mPlayer.release();
// Send error notification to JavaScript
this.handler.mCtx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+arg1+");");
this.handler.ctx.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+arg1+");");
return false;
}
}

View File

@@ -6,9 +6,16 @@ import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandManager;
import com.phonegap.api.CommandResult;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
@@ -21,22 +28,89 @@ import android.webkit.WebView;
* and returns the captured image. When the camera view is closed, the screen displayed before
* the camera view was shown is redisplayed.
*/
public class CameraLauncher extends ActivityResultModule {
public class CameraLauncher implements Command {
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private Uri imageUri; // Uri of captured image
private boolean base64 = true;
/**
* Constructor.
*
* @param view
* @param gap
*/
public CameraLauncher(WebView view, DroidGap gap) {
super(view, gap);
public CameraLauncher() {
}
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("setBase64")) {
this.setBase64(args.getBoolean(0));
}
else if (action.equals("takePicture")) {
this.takePicture(args.getInt(0));
}
return new CommandResult(status, result);
} catch (JSONException e) {
e.printStackTrace();
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Set the type of data to return. The data can either be returned
* as a base64 string or a URI that points to the file.
@@ -70,7 +144,7 @@ public class CameraLauncher extends ActivityResultModule {
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo);
this.startActivityForResult(intent);
this.ctx.startActivityForResult((Command) this, intent);
}
/**
@@ -81,15 +155,13 @@ public class CameraLauncher extends ActivityResultModule {
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
// If image available
if (resultCode == Activity.RESULT_OK) {
try {
// Read in bitmap of captured image
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.gap.getContentResolver(), imageUri);
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
// If sending base64 image back
if (this.base64) {
@@ -104,11 +176,11 @@ public class CameraLauncher extends ActivityResultModule {
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = null;
try {
uri = this.gap.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) {
System.out.println("Can't write to external media storage.");
try {
uri = this.gap.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) {
System.out.println("Can't write to internal media storage.");
this.failPicture("Error capturing image - no media storage found.");
@@ -117,12 +189,12 @@ public class CameraLauncher extends ActivityResultModule {
}
// Add compressed version of captured image to returned media store Uri
OutputStream os = this.gap.getContentResolver().openOutputStream(uri);
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
os.close();
// Send Uri back to JavaScript for viewing image
this.sendJavascript("navigator.camera.success('" + uri.toString() + "');");
this.ctx.sendJavascript("navigator.camera.success('" + uri.toString() + "');");
}
} catch (IOException e) {
e.printStackTrace();
@@ -153,7 +225,7 @@ public class CameraLauncher extends ActivityResultModule {
byte[] code = jpeg_data.toByteArray();
byte[] output = Base64.encodeBase64(code);
String js_out = new String(output);
this.sendJavascript("navigator.camera.success('" + js_out + "');");
this.ctx.sendJavascript("navigator.camera.success('" + js_out + "');");
}
}
catch(Exception e) {
@@ -167,6 +239,6 @@ public class CameraLauncher extends ActivityResultModule {
* @param err
*/
public void failPicture(String err) {
this.sendJavascript("navigator.camera.error('" + err + "');");
this.ctx.sendJavascript("navigator.camera.error('" + err + "');");
}
}

133
framework/src/com/phonegap/CompassListener.java Normal file → Executable file
View File

@@ -2,27 +2,34 @@ package com.phonegap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.content.Context;
import android.content.Intent;
import android.webkit.WebView;
/**
* This class listens to the compass sensor and stores the latest heading value.
*/
public class CompassListener extends Module implements SensorEventListener{
public class CompassListener implements SensorEventListener, Command{
public static int STOPPED = 0;
public static int STARTING = 1;
public static int RUNNING = 2;
public static int ERROR_FAILED_TO_START = 3;
public float TIMEOUT = 30000; // Timeout in msec to shut off listener
public long TIMEOUT = 30000; // Timeout in msec to shut off listener
WebView mAppView; // WebView object
DroidGap mCtx; // Activity (DroidGap) object
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
int status; // status of listener
float heading; // most recent heading value
@@ -34,19 +41,108 @@ public class CompassListener extends Module implements SensorEventListener{
/**
* Constructor.
*
* @param appView
* @param ctx The Activity (DroidGap) object
*/
public CompassListener(WebView appView, DroidGap ctx) {
super(appView, ctx);
this.mCtx = ctx;
this.mAppView = appView;
this.sensorManager = (SensorManager) mCtx.getSystemService(Context.SENSOR_SERVICE);
public CompassListener() {
this.timeStamp = 0;
this.status = 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(DroidGap ctx) {
this.ctx = ctx;
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.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 CommandResult(status, i);
}
else if (action.equals("getHeading")) {
float f = this.getHeading();
return new CommandResult(status, f);
}
else if (action.equals("setTimeout")) {
this.setTimeout(args.getLong(0));
}
else if (action.equals("getTimeout")) {
long l = this.getTimeout();
return new CommandResult(status, l);
}
return new CommandResult(status, result);
} catch (JSONException e) {
e.printStackTrace();
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called when listener is to be shut down and object is being destroyed.
*/
public void onDestroy() {
this.stop();
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Start listening for compass sensor.
*
@@ -88,13 +184,6 @@ public class CompassListener extends Module implements SensorEventListener{
this.status = CompassListener.STOPPED;
}
/**
* Called when listener is to be shut down and object is being destroyed.
*/
@Override
public void onDestroy() {
this.stop();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
@@ -145,7 +234,7 @@ public class CompassListener extends Module implements SensorEventListener{
*
* @param timeout Timeout in msec.
*/
public void setTimeout(float timeout) {
public void setTimeout(long timeout) {
this.TIMEOUT = timeout;
}
@@ -154,7 +243,7 @@ public class CompassListener extends Module implements SensorEventListener{
*
* @return timeout in msec
*/
public float getTimeout() {
public long getTimeout() {
return this.TIMEOUT;
}
}

134
framework/src/com/phonegap/ContactManager.java Normal file → Executable file
View File

@@ -1,17 +1,22 @@
package com.phonegap;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.provider.Contacts.ContactMethods;
import android.provider.Contacts.People;
import android.util.Log;
import android.webkit.WebView;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@SuppressWarnings("deprecation")
public class ContactManager extends Module {
public class ContactManager implements Command {
public class ContactTriplet
{
@@ -19,21 +24,100 @@ public class ContactManager extends Module {
public String email = "";
public String phone = "";
}
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
private static final String LOG_TAG = "Contact Query";
DroidGap mApp;
WebView mView;
Uri mPeople = android.provider.Contacts.People.CONTENT_URI;
Uri mPhone = android.provider.Contacts.Phones.CONTENT_URI;
Uri mEmail = android.provider.Contacts.ContactMethods.CONTENT_URI;
public ContactManager(WebView view, DroidGap app)
{
super(view, app);
mApp = app;
mView = view;
/**
* Constructor.
*/
public ContactManager() {
}
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("getContactsAndSendBack")) {
this.getContactsAndSendBack();
}
else if (action.equals("search")) {
this.search(args.getString(0), args.getString(1), args.getString(2));
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
// This is to add backwards compatibility to the OLD Contacts API\
public void getContactsAndSendBack()
{
@@ -45,7 +129,7 @@ public class ContactManager extends Module {
};
try{
Cursor myCursor = mApp.managedQuery(mPeople, projection,
Cursor myCursor = this.ctx.managedQuery(mPeople, projection,
null, null , People.NAME + " ASC");
processResults(myCursor, true);
}
@@ -77,7 +161,7 @@ public class ContactManager extends Module {
};
try{
Cursor myCursor = mApp.managedQuery(mEmail, projection,
Cursor myCursor = this.ctx.managedQuery(mEmail, projection,
"contact_methods." + ContactMethods.DATA + " = ?" + "AND contact_methods.kind = 1", variables , ContactMethods.DATA + " ASC");
getMethodData(myCursor);
@@ -126,7 +210,7 @@ public class ContactManager extends Module {
};
try{
Cursor myCursor = mApp.managedQuery(mPeople, projection,
Cursor myCursor = this.ctx.managedQuery(mPeople, projection,
conditions, variables , People.NAME + " ASC");
processResults(myCursor, false);
}
@@ -162,26 +246,26 @@ public class ContactManager extends Module {
// Code for backwards compatibility with the OLD Contacts API
if (all) {
mApp.sendJavascript("navigator.ContactManager.droidAddContact('" + name + "','" + phoneNumber + "','" + email +"');");
this.ctx.sendJavascript("navigator.ContactManager.droidAddContact('" + name + "','" + phoneNumber + "','" + email +"');");
}
else {
mApp.sendJavascript("navigator.contacts.droidFoundContact('" + name + "','" + phoneNumber + "','" + email +"');");
this.ctx.sendJavascript("navigator.contacts.droidFoundContact('" + name + "','" + phoneNumber + "','" + email +"');");
}
} while (cur.moveToNext());
if (all) {
mApp.sendJavascript("navigator.ContactManager.droidDone();");
this.ctx.sendJavascript("navigator.ContactManager.droidDone();");
}
else {
mApp.sendJavascript("navigator.contacts.droidDone();");
this.ctx.sendJavascript("navigator.contacts.droidDone();");
}
}
else
{
if (all) {
mApp.sendJavascript("navigator.ContactManager.fail();");
this.ctx.sendJavascript("navigator.ContactManager.fail();");
}
else {
mApp.sendJavascript("navigator.contacts.fail('None found!');");
this.ctx.sendJavascript("navigator.contacts.fail('None found!');");
}
}
}
@@ -205,10 +289,10 @@ public class ContactManager extends Module {
if(data != null)
{
data.email = email;
mApp.sendJavascript("navigator.Contacts.droidFoundContact('" + data.name + "','" + data.phone + "','" + data.email +"');");
this.ctx.sendJavascript("navigator.Contacts.droidFoundContact('" + data.name + "','" + data.phone + "','" + data.email +"');");
}
} while (cur.moveToNext());
mApp.sendJavascript("navigator.contacts.droidDoneContacts();");
this.ctx.sendJavascript("navigator.contacts.droidDoneContacts();");
}
}
@@ -226,7 +310,7 @@ public class ContactManager extends Module {
};
try{
Cursor myCursor = mApp.managedQuery(mPeople, projection,
Cursor myCursor = this.ctx.managedQuery(mPeople, projection,
People.PRIMARY_EMAIL_ID + " = ?", variables , People.NAME + " ASC");
data = getTriplet(myCursor);
}
@@ -281,7 +365,7 @@ public class ContactManager extends Module {
try
{
Cursor myCursor = mApp.managedQuery(mEmail, projection,
Cursor myCursor = this.ctx.managedQuery(mEmail, projection,
"contact_methods." + ContactMethods._ID + " = ?" + " AND contact_methods.kind = 1", variables , ContactMethods.DATA + " ASC");
email = getEmailColumnData(myCursor);
}

116
framework/src/com/phonegap/CryptoHandler.java Normal file → Executable file
View File

@@ -1,38 +1,120 @@
package com.phonegap;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.content.Intent;
import android.webkit.WebView;
public class CryptoHandler extends Module {
public class CryptoHandler implements Command {
WebView mView;
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
public CryptoHandler(WebView view, DroidGap gap)
{
super(view, gap);
mView = view;
/**
* Constructor.
*/
public CryptoHandler() {
}
public void encrypt(String pass, String text)
{
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("encrypt")) {
this.encrypt(args.getString(0), args.getString(1));
}
else if (action.equals("decrypt")) {
this.decrypt(args.getString(0), args.getString(1));
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
public void encrypt(String pass, String text) {
try {
String encrypted = SimpleCrypto.encrypt(pass,text);
mView.loadUrl("javascript:Crypto.gotCryptedString('" + text + "')");
// TODO: Why not just return text now?
this.ctx.sendJavascript("Crypto.gotCryptedString('" + text + "')");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void decrypt(String pass, String text)
{
public void decrypt(String pass, String text) {
try {
String decrypted = SimpleCrypto.decrypt(pass,text);
mView.loadUrl("javascript:Crypto.gotPlainString('" + text + "')");
this.ctx.sendJavascript("Crypto.gotPlainString('" + text + "')");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@@ -71,34 +71,31 @@ import android.widget.LinearLayout;
* @Override
* public void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* super.addModule("com.phonegap.examples.MyModule", "MyModule");
* super.loadUrl("file:///android_asset/www/index.html");
* }
* }
*/
public class DroidGap extends Activity {
private static final String LOG_TAG = "DroidGap";
private static final String LOG_TAG = "DroidGap";
protected WebView appView; // The webview for our app
protected ImageView splashScreen;
protected Boolean loadInWebView = false;
private LinearLayout root;
private Device gap;
private BrowserKey mKey;
private LinearLayout root;
private Device gap;
private FileUtils fs;
private BrowserKey mKey;
public CallbackServer callbackServer;
private CommandManager commandManager;
private String url; // The initial URL for our app
private String baseUrl; // The base of the initial URL for our app
// Variables to manage ActivityResultCallbacks
private int activityResultCallbackCounter = 1000;
private HashMap<Integer,ActivityResultModule> activityResultCallbacks = new HashMap<Integer,ActivityResultModule>();
// List of modules started and managed
private HashMap<String,Module>modules = new HashMap<String,Module>();
private HashMap<Integer,Command> activityResultCallbacks = new HashMap<Integer,Command>();
/**
* Called when the activity is first created.
@@ -177,9 +174,9 @@ public class DroidGap extends Activity {
WebViewReflect.setGeolocationEnabled(settings, true);
// Bind the appView object to the gap class methods
bindBrowser(appView);
if (this.getModule("com.phonegap.Storage") != null) {
Storage cupcakeStorage = (Storage)this.getModule("com.phonegap.Storage");
cupcakeStorage.setStorage(appPackage);
if (this.commandManager.getCommand("com.phonegap.Storage") != null) {
Storage cupcakeStorage = (Storage)this.commandManager.getCommand("com.phonegap.Storage");
cupcakeStorage.setStorage(appPackage);
}
}
@@ -201,14 +198,8 @@ public class DroidGap extends Activity {
protected void onPause(){
super.onPause();
// Forward to modules
java.util.Set<Entry<String,Module>> s = this.modules.entrySet();
java.util.Iterator<Entry<String,Module>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Module> entry = it.next();
Module module = entry.getValue();
module.onPause();
}
// Forward to commands
this.commandManager.onPause();
// Send pause event to JavaScript
appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};");
@@ -224,14 +215,8 @@ public class DroidGap extends Activity {
protected void onResume(){
super.onResume();
// Forward to modules
java.util.Set<Entry<String,Module>> s = this.modules.entrySet();
java.util.Iterator<Entry<String,Module>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Module> entry = it.next();
Module module = entry.getValue();
module.onResume();
}
// Forward to commands
this.commandManager.onResume();
// Send resume event to JavaScript
appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};");
@@ -255,18 +240,11 @@ public class DroidGap extends Activity {
// Clean up objects
if (mKey != null) {
}
// Clean up modules
java.util.Set<Entry<String,Module>> s = this.modules.entrySet();
java.util.Iterator<Entry<String,Module>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Module> entry = it.next();
Module module = entry.getValue();
module.onDestroy();
}
// Forward to commands
this.commandManager.onDestroy();
if (callbackServer != null) {
callbackServer.destroy();
}
@@ -276,72 +254,26 @@ public class DroidGap extends Activity {
callbackServer = new CallbackServer();
commandManager = new CommandManager(appView, this);
gap = new Device(appView, this);
fs = new FileUtils(appView, this);
mKey = new BrowserKey(appView, this);
// This creates the new javascript interfaces for PhoneGap
appView.addJavascriptInterface(commandManager, "CommandManager");
appView.addJavascriptInterface(gap, "DroidGap");
this.addModule("com.phonegap.AccelListener", "Accel");
this.addModule("com.phonegap.CameraLauncher", "GapCam");
this.addModule("com.phonegap.ContactManager", "ContactHook");
this.addModule("com.phonegap.FileUtils", "FileUtil");
this.addModule("com.phonegap.NetworkManager", "NetworkManager");
this.addModule("com.phonegap.CompassListener", "CompassHook");
this.addModule("com.phonegap.CryptoHandler", "GapCrypto");
appView.addJavascriptInterface(mKey, "BackButton");
this.addModule("com.phonegap.AudioHandler", "GapAudio");
appView.addJavascriptInterface(fs, "FileUtil");
appView.addJavascriptInterface(mKey, "BackButton");
appView.addJavascriptInterface(callbackServer, "CallbackServer");
appView.addJavascriptInterface(new SplashScreen(this), "SplashScreen");
if (android.os.Build.VERSION.RELEASE.startsWith("1."))
{
this.addModule("com.phonegap.Storage", "droidStorage");
this.addModule("com.phonegap.GeoBroker", "Geo");
}
}
@SuppressWarnings("unchecked")
/**
* Add module to be loaded and made available from JavaScript.
*
* @param className The class to load
* @param javascriptInterface Bind the object to Javascript so that the methods can be
* accessed from Javascript using this variable name.
*/
public Object addModule(String className, String javascriptInterface) {
System.out.println("DroidGap.addModule("+className+", "+javascriptInterface+")");
try {
Class cl = Class.forName(className);
Class partypes[] = new Class[2];
partypes[0] = android.webkit.WebView.class;
partypes[1] = com.phonegap.DroidGap.class;
java.lang.reflect.Constructor<Module> ct = cl.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = this.appView;
arglist[1] = this;
Module module = ct.newInstance(arglist);
this.modules.put(className, module);
if (javascriptInterface != null) {
this.appView.addJavascriptInterface(module, javascriptInterface);
if (android.os.Build.VERSION.RELEASE.startsWith("1."))
{
Log.d(LOG_TAG, "bindBrowser: Adding droidStorage"); //@ibm
this.commandManager.addCommand("com.phonegap.Storage");
this.commandManager.addCommand("com.phonegap.GeoBroker");
}
return module;
}
catch (Exception e) {
e.printStackTrace();
System.out.println("Error adding module "+className+".");
}
return null;
}
/**
* Get the loaded module.
*
* @param className The class of the loaded module.
* @return
*/
public Object getModule(String className) {
Object module = this.modules.get(className);
return module;
}
/**
@@ -664,7 +596,7 @@ public class DroidGap extends Activity {
}
/**
* Any calls to Activity.startActivityForResult must go through ActivityResultCallback, so
* Any calls to Activity.startActivityForResult must use method below, so
* the result can be routed to them correctly.
*
* This is done to eliminate the need to modify DroidGap.java to receive activity results.
@@ -676,27 +608,31 @@ public class DroidGap extends Activity {
*/
@Override
public void startActivityForResult(Intent intent, int requestCode) throws RuntimeException {
if ((requestCode < 0) || this.activityResultCallbacks.containsKey(requestCode)) {
super.startActivityForResult(intent, requestCode);
System.out.println("startActivityForResult(intent,"+requestCode+")");
if (requestCode == -1) {
super.startActivityForResult(intent, requestCode);
}
else {
throw new RuntimeException("PhoneGap Exception: Do not call startActivityForResult() directly. Implement ActivityResultCallback instead.");
throw new RuntimeException("PhoneGap Exception: Call startActivityForResult(Command, Intent) instead.");
}
}
/**
* Add activity result callback to receive onActivityResult() callbacks.
*
* @param callback The callback class
* @return The request code to use for the callback
* Launch an activity for which you would like a result when it finished. When this activity exits,
* your onActivityResult() method will be called.
*
* @param command The command object
* @param intent The intent to start
* @return The request code to use for the callback
*/
public int addActivityResult(ActivityResultModule callback) {
public int startActivityForResult(Command command, Intent intent) {
int requestCode = this.activityResultCallbackCounter++;
this.activityResultCallbacks.put(requestCode, callback);
this.activityResultCallbacks.put(requestCode, command);
super.startActivityForResult(intent, requestCode);
return requestCode;
}
@Override
@Override
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
@@ -709,9 +645,9 @@ public class DroidGap extends Activity {
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
ActivityResultModule callback = this.activityResultCallbacks.get(requestCode);
Command callback = this.activityResultCallbacks.remove(requestCode);
if (callback != null) {
callback.onActivityResult(requestCode, resultCode, intent);
callback.onActivityResult(requestCode, resultCode, intent);
}
}
}

View File

@@ -4,7 +4,7 @@ import java.io.*;
import android.webkit.WebView;
public class FileUtils extends Module {
public class FileUtils {
WebView mView;
@@ -13,7 +13,6 @@ public class FileUtils extends Module {
public FileUtils(WebView view, DroidGap gap)
{
super(view, gap);
mView = view;
}

View File

@@ -2,8 +2,13 @@ package com.phonegap;
import java.util.HashMap;
import android.content.Context;
import android.location.Location;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.content.Intent;
import android.webkit.WebView;
/*
@@ -12,38 +17,121 @@ import android.webkit.WebView;
* This class only starts and stops various GeoListeners, which consist of a GPS and a Network Listener
*/
public class GeoBroker extends Module {
private WebView mAppView;
private DroidGap mCtx;
private HashMap<String, GeoListener> geoListeners;
public class GeoBroker implements Command {
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
private HashMap<String, GeoListener> geoListeners;
private GeoListener global;
public GeoBroker(WebView view, DroidGap ctx)
{
super(view, ctx);
mCtx = ctx;
mAppView = view;
geoListeners = new HashMap<String, GeoListener>();
/**
* Constructor.
*/
public GeoBroker() {
this.geoListeners = new HashMap<String, GeoListener>();
}
public void getCurrentLocation()
{
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("getCurrentLocation")) {
this.getCurrentLocation();
}
else if (action.equals("start")) {
String s = this.start(args.getInt(0), args.getString(1));
return new CommandResult(status, s);
}
else if (action.equals("stop")) {
this.stop(args.getString(0));
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
public void getCurrentLocation() {
//It's supposed to run async!
if(global == null)
global = new GeoListener("global", mCtx, 10000, mAppView);
else
if (global == null) {
global = new GeoListener("global", this.ctx, 10000, this.webView);
}
else {
global.start(10000);
}
}
public String start(int freq, String key)
{
GeoListener listener = new GeoListener(key, mCtx, freq, mAppView);
public String start(int freq, String key) {
GeoListener listener = new GeoListener(key, this.ctx, freq, this.webView);
geoListeners.put(key, listener);
return key;
}
public void stop(String key)
{
public void stop(String key) {
GeoListener geo = geoListeners.get(key);
}
}

View File

@@ -2,49 +2,137 @@ package com.phonegap;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.content.Context;
import android.content.Intent;
import android.net.*;
import android.webkit.WebView;
public class NetworkManager extends Module {
public class NetworkManager implements Command {
DroidGap mCtx;
WebView mView;
ConnectivityManager sockMan;
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
public NetworkManager(WebView view, DroidGap ctx)
{
super(view, ctx);
mCtx = ctx;
mView = view;
sockMan = (ConnectivityManager) mCtx.getSystemService(Context.CONNECTIVITY_SERVICE);
ConnectivityManager sockMan;
/**
* Constructor.
*/
public NetworkManager() {
}
public boolean isAvailable()
{
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("isAvailable")) {
boolean b = this.isAvailable();
return new CommandResult(status, b);
}
else if (action.equals("isWifiActive")) {
boolean b = this.isWifiActive();
return new CommandResult(status, b);
}
else if (action.equals("isReachable")) {
boolean b = this.isReachable(args.getString(0));
return new CommandResult(status, b);
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
public boolean isAvailable() {
NetworkInfo info = sockMan.getActiveNetworkInfo();
boolean conn = false;
if(info != null)
if (info != null) {
conn = info.isConnected();
}
return conn;
}
public boolean isWifiActive()
{
public boolean isWifiActive() {
NetworkInfo info = sockMan.getActiveNetworkInfo();
if(info != null)
{
if (info != null) {
String type = info.getTypeName();
return type.equals("WIFI");
}
return false;
}
public boolean isReachable(String uri)
{
if (uri.indexOf("http://") == -1)
public boolean isReachable(String uri) {
if (uri.indexOf("http://") == -1) {
uri = "http://" + uri;
}
boolean reached = isAvailable();
try {
DefaultHttpClient httpclient = new DefaultHttpClient();

View File

@@ -1,25 +1,122 @@
package com.phonegap;
import org.json.JSONArray;
import org.json.JSONException;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.*;
import android.util.Log;
import android.webkit.WebView;
public class Storage extends Module {
public class Storage implements Command {
private static final String LOG_TAG = "SQLite Storage:";
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
SQLiteDatabase myDb;
String path;
String txid = "";
WebView appView;
DroidGap mCtx;
public Storage(WebView view, DroidGap ctx) {
super(view, ctx);
appView = view;
mCtx = ctx;
/**
* Constructor.
*/
public Storage() {
}
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
try {
if (action.equals("setStorage")) {
this.setStorage(args.getString(0));
}
else if (action.equals("openDatabase")) {
this.openDatabase(args.getString(0), args.getString(1), args.getString(2), args.getLong(3));
}
else if (action.equals("executeSql")) {
JSONArray a = args.getJSONArray(1);
int len = a.length();
String[] s = new String[len];
for (int i=0; i<len; i++) {
s[i] = a.getString(i);
}
this.executeSql(args.getString(0), s, args.getString(2));
}
return new CommandResult(status, result);
} catch (JSONException e) {
return new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
public void setStorage(String appPackage) {
path = "/data/data/" + appPackage + "/databases/";
}
@@ -39,7 +136,7 @@ public class Storage extends Module {
} catch (SQLiteException ex) {
Log.d(LOG_TAG, ex.getMessage());
txid = "";
mCtx.sendJavascript("droiddb.fail(" + ex.getMessage() + "," + txid + ");");
this.ctx.sendJavascript("droiddb.fail(" + ex.getMessage() + "," + txid + ");");
}
}
@@ -60,9 +157,9 @@ public class Storage extends Module {
}
}
resultString += "}";
mCtx.sendJavascript("droiddb.addResult('" + resultString + "', " + txid + ");");
this.ctx.sendJavascript("droiddb.addResult('" + resultString + "', " + txid + ");");
} while (cur.moveToNext());
mCtx.sendJavascript("droiddb.completeQuery(" + txid + ");");
this.ctx.sendJavascript("droiddb.completeQuery(" + txid + ");");
txid = "";
myDb.close();
}

View File

@@ -2,27 +2,110 @@ package com.phonegap;
import java.util.List;
import org.json.JSONArray;
import com.phonegap.api.Command;
import com.phonegap.api.CommandResult;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.content.Context;
import android.content.Intent;
import android.webkit.WebView;
public class TempListener extends Module implements SensorEventListener {
WebView mAppView;
DroidGap mCtx;
Sensor mSensor;
public class TempListener implements SensorEventListener, Command {
WebView webView; // WebView object
DroidGap ctx; // DroidGap object
Sensor mSensor;
private SensorManager sensorManager;
public TempListener(WebView appView, DroidGap ctx) {
super(appView, ctx);
mCtx = ctx;
mAppView = appView;
sensorManager = (SensorManager) mCtx.getSystemService(Context.SENSOR_SERVICE);
/**
* Constructor.
*/
public TempListener() {
}
/**
* 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(DroidGap ctx) {
this.ctx = ctx;
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
}
/**
* Sets the main View of the application, this is the WebView within which
* a PhoneGap app runs.
*
* @param webView The PhoneGap WebView
*/
public void setView(WebView webView) {
this.webView = webView;
}
/**
* Executes the request and returns CommandResult.
*
* @param action The command to execute.
* @param args JSONArry of arguments for the command.
* @return A CommandResult object with a status and message.
*/
public CommandResult execute(String action, JSONArray args) {
CommandResult.Status status = CommandResult.Status.OK;
String result = "";
if (action.equals("start")) {
this.start();
}
else if (action.equals("stop")) {
this.stop();
}
return new CommandResult(status, result);
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
this.stop();
}
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data 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) {
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
public void start() {
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
if (list.size() > 0) {
@@ -42,7 +125,7 @@ public class TempListener extends Module implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
// We want to know what temp this is.
float temp = event.values[0];
mCtx.sendJavascript("gotTemp(" + temp + ");");
this.ctx.sendJavascript("gotTemp(" + temp + ");");
}
}

View File

@@ -2,7 +2,10 @@ package com.phonegap.api;
import org.json.JSONArray;
import com.phonegap.DroidGap;
import android.content.Context;
import android.content.Intent;
import android.webkit.WebView;
/**
@@ -29,7 +32,7 @@ public interface Command {
*
* @param ctx The context of the main Activity.
*/
void setContext(Context ctx);
void setContext(DroidGap ctx);
/**
* Sets the main View of the application, this is the WebView within which
@@ -38,4 +41,31 @@ public interface Command {
* @param webView The PhoneGap WebView
*/
void setView(WebView webView);
/**
* Called when the system is about to start resuming a previous activity.
*/
void onPause();
/**
* Called when the activity will start interacting with the user.
*/
void onResume();
/**
* The final call you receive before your activity is destroyed.
*/
void onDestroy();
/**
* Called when an activity you launched exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
*
* @param requestCode The request code originally supplied to startActivityForResult(),
* allowing you to identify who this result came from.
* @param resultCode The integer result code returned by the child activity through its setResult().
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
*/
void onActivityResult(int requestCode, int resultCode, Intent intent);
}

107
framework/src/com/phonegap/api/CommandManager.java Normal file → Executable file
View File

@@ -1,9 +1,13 @@
package com.phonegap.api;
import java.util.HashMap;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.Context;
import android.content.Intent;
import android.webkit.WebView;
import com.phonegap.DroidGap;
@@ -18,12 +22,13 @@ import com.phonegap.DroidGap;
*
*/
public final class CommandManager {
private Command[] commands;
private final Context ctx;
private HashMap<String, Command> commands = new HashMap<String,Command>();
private final DroidGap ctx;
private final WebView app;
public CommandManager(WebView app, Context ctx) {
public CommandManager(WebView app, DroidGap ctx) {
this.ctx = ctx;
this.app = app;
}
@@ -49,18 +54,15 @@ public final class CommandManager {
* is called once the plugin code has executed.
* @return JSON encoded string with a response message and status.
*/
public String exec(final String clazz, final String action, final String callbackId,
final String jsonArgs, final boolean async) {
public String exec(final String clazz, final String action, final String callbackId, final String jsonArgs, final boolean async) {
CommandResult cr = null;
try {
final JSONArray args = new JSONArray(jsonArgs);
Class c = getClassByName(clazz);
if (isPhoneGapCommand(c)) {
// Create a new instance of the plugin and set the context and webview
final Command plugin = (Command)c.newInstance();
plugin.setContext(this.ctx);
plugin.setView(this.app);
final Command plugin = this.addCommand(clazz);
final DroidGap ctx = this.ctx;
if (async) {
// Run this on a different thread so that this one can return back to JS
Thread thread = new Thread(new Runnable() {
@@ -69,9 +71,9 @@ public final class CommandManager {
CommandResult cr = plugin.execute(action, args);
// Check the status for 0 (success) or otherwise
if (cr.getStatus() == 0) {
app.loadUrl(cr.toSuccessCallbackString(callbackId));
ctx.sendJavascript(cr.toSuccessCallbackString(callbackId));
} else {
app.loadUrl(cr.toErrorCallbackString(callbackId));
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
}
}
});
@@ -84,16 +86,13 @@ public final class CommandManager {
}
} catch (ClassNotFoundException e) {
cr = new CommandResult(CommandResult.Status.CLASS_NOT_FOUND_EXCEPTION);
} catch (IllegalAccessException e) {
cr = new CommandResult(CommandResult.Status.ILLEGAL_ACCESS_EXCEPTION);
} catch (InstantiationException e) {
cr = new CommandResult(CommandResult.Status.INSTANTIATION_EXCEPTION);
} catch (JSONException e) {
System.out.println("ERROR: "+e.toString());
cr = new CommandResult(CommandResult.Status.JSON_EXCEPTION);
}
// if async we have already returned at this point unless there was an error...
if (async) {
app.loadUrl(cr.toErrorCallbackString(callbackId));
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
}
return ( cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }" );
}
@@ -127,4 +126,80 @@ public final class CommandManager {
}
return isCommand;
}
/**
* Add command to be loaded and cached.
* If command is already created, then just return it.
*
* @param className The class to load
* @return The command
*/
public Command addCommand(String className) {
if (this.commands.containsKey(className)) {
return this.getCommand(className);
}
try {
Command command = (Command)Class.forName(className).newInstance();
this.commands.put(className, command);
command.setContext((DroidGap)this.ctx);
command.setView(this.app);
return command;
}
catch (Exception e) {
e.printStackTrace();
System.out.println("Error adding command "+className+".");
}
return null;
}
/**
* Get the loaded command.
*
* @param className The class of the loaded command.
* @return
*/
public Command getCommand(String className) {
Command command = this.commands.get(className);
return command;
}
/**
* Called when the system is about to start resuming a previous activity.
*/
public void onPause() {
java.util.Set<Entry<String,Command>> s = this.commands.entrySet();
java.util.Iterator<Entry<String,Command>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Command> entry = it.next();
Command command = entry.getValue();
command.onPause();
}
}
/**
* Called when the activity will start interacting with the user.
*/
public void onResume() {
java.util.Set<Entry<String,Command>> s = this.commands.entrySet();
java.util.Iterator<Entry<String,Command>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Command> entry = it.next();
Command command = entry.getValue();
command.onResume();
}
}
/**
* The final call you receive before your activity is destroyed.
*/
public void onDestroy() {
java.util.Set<Entry<String,Command>> s = this.commands.entrySet();
java.util.Iterator<Entry<String,Command>> it = s.iterator();
while(it.hasNext()) {
Entry<String,Command> entry = it.next();
Command command = entry.getValue();
command.onDestroy();
}
}
}

13
framework/src/com/phonegap/api/CommandResult.java Normal file → Executable file
View File

@@ -21,6 +21,19 @@ public class CommandResult {
this.message = message.toString();
}
public CommandResult(Status status, int i) {
this.status = status.ordinal();
this.message = ""+i;
}
public CommandResult(Status status, float f) {
this.status = status.ordinal();
this.message = ""+f;
}
public CommandResult(Status status, boolean b) {
this.status = status.ordinal();
this.message = ""+b;
}
public int getStatus() {
return status;
}