You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ma...@apache.org on 2012/02/03 16:43:10 UTC

[15/15] Rename to Cordova

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/Notification.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Notification.java b/framework/src/org/apache/cordova/Notification.java
new file mode 100755
index 0000000..9605ea6
--- /dev/null
+++ b/framework/src/org/apache/cordova/Notification.java
@@ -0,0 +1,366 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.apache.cordova.api.CordovaActivity;
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Vibrator;
+
+/**
+ * This class provides access to notifications on the device.
+ */
+public class Notification extends Plugin {
+	
+	public int confirmResult = -1;
+	public ProgressDialog spinnerDialog = null;
+	public ProgressDialog progressDialog = null;	
+	
+	/**
+	 * Constructor.
+	 */
+	public Notification() {
+	}
+
+	/**
+	 * Executes the request and returns PluginResult.
+	 * 
+	 * @param action 		The action to execute.
+	 * @param args 			JSONArry of arguments for the plugin.
+	 * @param callbackId	The callback id used when calling back into JavaScript.
+	 * @return 				A PluginResult object with a status and message.
+	 */
+	public PluginResult execute(String action, JSONArray args, String callbackId) {
+		PluginResult.Status status = PluginResult.Status.OK;
+		String result = "";		
+		
+		try {
+			if (action.equals("beep")) {
+				this.beep(args.getLong(0));
+			}
+			else if (action.equals("vibrate")) {
+				this.vibrate(args.getLong(0));
+			}
+			else if (action.equals("alert")) {
+				this.alert(args.getString(0),args.getString(1),args.getString(2), callbackId);
+				PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
+				r.setKeepCallback(true);
+				return r;
+			}
+			else if (action.equals("confirm")) {
+				this.confirm(args.getString(0),args.getString(1),args.getString(2), callbackId);
+				PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
+				r.setKeepCallback(true);
+				return r;
+			}
+			else if (action.equals("activityStart")) {
+				this.activityStart(args.getString(0),args.getString(1));
+			}
+			else if (action.equals("activityStop")) {
+				this.activityStop();
+			}
+			else if (action.equals("progressStart")) {
+				this.progressStart(args.getString(0),args.getString(1));
+			}
+			else if (action.equals("progressValue")) {
+				this.progressValue(args.getInt(0));
+			}
+			else if (action.equals("progressStop")) {
+				this.progressStop();
+			}
+			return new PluginResult(status, result);
+		} catch (JSONException e) {
+			return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+		}
+	}
+
+	/**
+	 * Identifies if action to be executed returns a value and should be run synchronously.
+	 * 
+	 * @param action	The action to execute
+	 * @return			T=returns value
+	 */
+	public boolean isSynch(String action) {
+		if (action.equals("alert")) {
+			return true;
+		}
+		else if (action.equals("confirm")) {
+			return true;
+		}
+		else if (action.equals("activityStart")) {
+			return true;
+		}
+		else if (action.equals("activityStop")) {
+			return true;
+		}
+		else if (action.equals("progressStart")) {
+			return true;
+		}
+		else if (action.equals("progressValue")) {
+			return true;
+		}
+		else if (action.equals("progressStop")) {
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+	/**
+	 * Beep plays the default notification ringtone.
+	 * 
+	 * @param count			Number of times to play notification
+	 */
+	public void beep(long count) {
+		Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+		Ringtone notification = RingtoneManager.getRingtone(this.ctx, ringtone);
+		
+		// If phone is not set to silent mode
+		if (notification != null) {
+			for (long i = 0; i < count; ++i) {
+				notification.play();
+				long timeout = 5000;
+				while (notification.isPlaying() && (timeout > 0)) {
+					timeout = timeout - 100;
+					try {
+						Thread.sleep(100);
+					} catch (InterruptedException e) {
+					}
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Vibrates the device for the specified amount of time.
+	 * 
+	 * @param time			Time to vibrate in ms.
+	 */
+	public void vibrate(long time){
+        // Start the vibration, 0 defaults to half a second.
+		if (time == 0) {
+			time = 500;
+		}
+        Vibrator vibrator = (Vibrator) this.ctx.getSystemService(Context.VIBRATOR_SERVICE);
+        vibrator.vibrate(time);
+	}
+	
+	/**
+	 * Builds and shows a native Android alert with given Strings
+	 * @param message 		The message the alert should display
+	 * @param title 		The title of the alert
+	 * @param buttonLabel 	The label of the button 
+	 * @param callbackId	The callback id
+	 */
+	public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
+
+		final CordovaActivity ctx = this.ctx;
+		final Notification notification = this;
+		
+		Runnable runnable = new Runnable() {
+			public void run() {
+		
+				AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
+				dlg.setMessage(message);
+				dlg.setTitle(title);
+				dlg.setCancelable(false);
+				dlg.setPositiveButton(buttonLabel,
+						new AlertDialog.OnClickListener() {
+					public void onClick(DialogInterface dialog, int which) {
+						dialog.dismiss();
+						notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
+					}
+				});
+				dlg.create();
+				dlg.show();
+			};
+		};
+		this.ctx.runOnUiThread(runnable);
+	}
+
+	/**
+	 * Builds and shows a native Android confirm dialog with given title, message, buttons.
+	 * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
+	 * The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
+	 * 
+	 * @param message 		The message the dialog should display
+	 * @param title 		The title of the dialog
+	 * @param buttonLabels 	A comma separated list of button labels (Up to 3 buttons)
+	 * @param callbackId	The callback id
+	 */
+	public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
+
+		final CordovaActivity ctx = this.ctx;
+		final Notification notification = this;
+		final String[] fButtons = buttonLabels.split(",");
+
+		Runnable runnable = new Runnable() {
+			public void run() {
+				AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
+				dlg.setMessage(message);
+				dlg.setTitle(title);
+				dlg.setCancelable(false);
+
+				// First button
+				if (fButtons.length > 0) {
+					dlg.setPositiveButton(fButtons[0],
+							new AlertDialog.OnClickListener() {
+						public void onClick(DialogInterface dialog, int which) {
+							dialog.dismiss();
+							notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
+						}
+					});
+				}
+
+				// Second button
+				if (fButtons.length > 1) {
+					dlg.setNeutralButton(fButtons[1], 
+							new AlertDialog.OnClickListener() {
+						public void onClick(DialogInterface dialog, int which) {
+							dialog.dismiss();
+							notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
+						}
+					});
+				}
+
+				// Third button
+				if (fButtons.length > 2) {
+					dlg.setNegativeButton(fButtons[2],
+							new AlertDialog.OnClickListener() {
+						public void onClick(DialogInterface dialog, int which) {
+							dialog.dismiss();
+							notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
+						}
+					}
+					);
+				}
+
+				dlg.create();
+				dlg.show();
+			};
+		};
+		this.ctx.runOnUiThread(runnable);
+	}
+
+	/**
+	 * Show the spinner.
+	 * 
+	 * @param title			Title of the dialog
+	 * @param message		The message of the dialog
+	 */
+	public synchronized void activityStart(final String title, final String message) {
+		if (this.spinnerDialog != null) {
+			this.spinnerDialog.dismiss();
+			this.spinnerDialog = null;
+		}
+		final Notification notification = this;
+		final CordovaActivity ctx = this.ctx;
+		Runnable runnable = new Runnable() {
+			public void run() {
+				notification.spinnerDialog = ProgressDialog.show(ctx, title , message, true, true, 
+					new DialogInterface.OnCancelListener() { 
+						public void onCancel(DialogInterface dialog) {
+							notification.spinnerDialog = null;
+						}
+					});
+				}
+			};
+		this.ctx.runOnUiThread(runnable);
+	}
+	
+	/**
+	 * Stop spinner.
+	 */
+	public synchronized void activityStop() {
+		if (this.spinnerDialog != null) {
+			this.spinnerDialog.dismiss();
+			this.spinnerDialog = null;
+		}
+	}
+
+	/**
+	 * Show the progress dialog.
+	 * 
+	 * @param title			Title of the dialog
+	 * @param message		The message of the dialog
+	 */
+	public synchronized void progressStart(final String title, final String message) {
+		if (this.progressDialog != null) {
+			this.progressDialog.dismiss();
+			this.progressDialog = null;
+		}
+		final Notification notification = this;
+		final CordovaActivity ctx = this.ctx;
+		Runnable runnable = new Runnable() {
+			public void run() {
+				notification.progressDialog = new ProgressDialog(ctx);
+				notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+				notification.progressDialog.setTitle(title);
+				notification.progressDialog.setMessage(message);
+				notification.progressDialog.setCancelable(true);
+				notification.progressDialog.setMax(100);
+				notification.progressDialog.setProgress(0);
+				notification.progressDialog.setOnCancelListener(
+					new DialogInterface.OnCancelListener() { 
+						public void onCancel(DialogInterface dialog) {
+							notification.progressDialog = null;
+						}
+					});
+				notification.progressDialog.show();
+			}
+		};
+		this.ctx.runOnUiThread(runnable);
+	}
+	
+	/**
+	 * Set value of progress bar.
+	 * 
+	 * @param value			0-100
+	 */
+	public synchronized void progressValue(int value) {
+		if (this.progressDialog != null) {
+			this.progressDialog.setProgress(value);
+		}		
+	}
+	
+	/**
+	 * Stop progress dialog.
+	 */
+	public synchronized void progressStop() {
+		if (this.progressDialog != null) {
+			this.progressDialog.dismiss();
+			this.progressDialog = null;
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/PreferenceNode.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PreferenceNode.java b/framework/src/org/apache/cordova/PreferenceNode.java
new file mode 100644
index 0000000..6d5edcd
--- /dev/null
+++ b/framework/src/org/apache/cordova/PreferenceNode.java
@@ -0,0 +1,16 @@
+package org.apache.cordova;
+
+// represents the <preference> element from the W3C config.xml spec
+// see http://www.w3.org/TR/widgets/#the-preference-element-and-its-attributes
+public class PreferenceNode {
+    public String name;
+    public String value;
+    public boolean readonly;
+
+    // constructor
+    public PreferenceNode(String name, String value, boolean readonly) {
+        this.name = name;
+        this.value = value;
+        this.readonly = readonly;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/PreferenceSet.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PreferenceSet.java b/framework/src/org/apache/cordova/PreferenceSet.java
new file mode 100644
index 0000000..39dab73
--- /dev/null
+++ b/framework/src/org/apache/cordova/PreferenceSet.java
@@ -0,0 +1,44 @@
+package org.apache.cordova;
+
+import java.util.HashSet;
+
+import org.apache.cordova.PreferenceNode;
+
+
+public class PreferenceSet {
+    private HashSet<PreferenceNode> innerSet;
+
+    public PreferenceSet() {
+        this.innerSet = new HashSet<PreferenceNode>();
+    }
+
+    public void add(PreferenceNode node) {
+        this.innerSet.add(node);
+    }
+
+    public int size() {
+        return this.innerSet.size();
+    }
+
+    public void clear() {
+        this.innerSet.clear();
+    }
+
+    public String pref(String prefName) {
+        for (PreferenceNode n : innerSet)
+            if (prefName.equals(n.name))
+                return n.value;
+
+        return null;
+    }
+
+    public boolean prefMatches(String prefName, String prefValue) {
+        String value = pref(prefName);
+
+        if (value == null) {
+            return false;
+        } else {
+            return value.equals(prefValue);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/StandAlone.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/StandAlone.java b/framework/src/org/apache/cordova/StandAlone.java
new file mode 100644
index 0000000..d41771d
--- /dev/null
+++ b/framework/src/org/apache/cordova/StandAlone.java
@@ -0,0 +1,35 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.lang.reflect.Field;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class StandAlone extends DroidGap {
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        super.loadUrl("file:///android_asset/www/index.html");                        
+    }		
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/Storage.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Storage.java b/framework/src/org/apache/cordova/Storage.java
new file mode 100755
index 0000000..365383d
--- /dev/null
+++ b/framework/src/org/apache/cordova/Storage.java
@@ -0,0 +1,239 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.io.File;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.*;
+
+/**
+ * This class implements the HTML5 database support to work around a bug for 
+ * Android 3.0 devices. It is not used for other versions of Android, since 
+ * HTML5 database is built in to the browser.
+ */
+public class Storage extends Plugin {
+
+	// Data Definition Language
+	private static final String ALTER = "alter";
+	private static final String CREATE = "create";
+	private static final String DROP = "drop";
+	private static final String TRUNCATE = "truncate";
+	
+	SQLiteDatabase myDb = null; // Database object
+	String path = null; // Database path
+	String dbName = null; // Database name
+
+	/**
+	 * Constructor.
+	 */
+	public Storage() {
+	}
+
+	/**
+	 * Executes the request and returns PluginResult.
+	 * 
+	 * @param action
+	 *            The action to execute.
+	 * @param args
+	 *            JSONArry of arguments for the plugin.
+	 * @param callbackId
+	 *            The callback id used when calling back into JavaScript.
+	 * @return A PluginResult object with a status and message.
+	 */
+	public PluginResult execute(String action, JSONArray args, String callbackId) {
+		PluginResult.Status status = PluginResult.Status.OK;
+		String result = "";
+
+		try {
+			if (action.equals("openDatabase")) {
+				this.openDatabase(args.getString(0), args.getString(1),
+						args.getString(2), args.getLong(3));
+			} else if (action.equals("executeSql")) {
+				String[] s = null;
+				if (args.isNull(1)) {
+					s = new String[0];
+				} else {
+					JSONArray a = args.getJSONArray(1);
+					int len = a.length();
+					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 PluginResult(status, result);
+		} catch (JSONException e) {
+			return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+		}
+	}
+
+	/**
+	 * Identifies if action to be executed returns a value and should be run
+	 * synchronously.
+	 * 
+	 * @param action
+	 *            The action to execute
+	 * @return T=returns value
+	 */
+	public boolean isSynch(String action) {
+		return true;
+	}
+
+	/**
+	 * Clean up and close database.
+	 */
+	@Override
+	public void onDestroy() {
+		if (this.myDb != null) {
+			this.myDb.close();
+			this.myDb = null;
+		}
+	}
+
+	// --------------------------------------------------------------------------
+	// LOCAL METHODS
+	// --------------------------------------------------------------------------
+
+	/**
+	 * Open database.
+	 * 
+	 * @param db
+	 *            The name of the database
+	 * @param version
+	 *            The version
+	 * @param display_name
+	 *            The display name
+	 * @param size
+	 *            The size in bytes
+	 */
+	public void openDatabase(String db, String version, String display_name,
+			long size) {
+
+		// If database is open, then close it
+		if (this.myDb != null) {
+			this.myDb.close();
+		}
+
+		// If no database path, generate from application package
+		if (this.path == null) {
+			this.path = this.ctx.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
+		}
+
+		this.dbName = this.path + File.pathSeparator + db + ".db";
+		this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
+	}
+
+	/**
+	 * Execute SQL statement.
+	 * 
+	 * @param query
+	 *            The SQL query
+	 * @param params
+	 *            Parameters for the query
+	 * @param tx_id
+	 *            Transaction id
+	 */
+	public void executeSql(String query, String[] params, String tx_id) {
+		try {
+			if (isDDL(query)) {
+				this.myDb.execSQL(query);
+				this.sendJavascript("droiddb.completeQuery('" + tx_id + "', '');");
+			} 
+			else {
+				Cursor myCursor = this.myDb.rawQuery(query, params);
+				this.processResults(myCursor, tx_id);
+				myCursor.close();
+			}
+		} 
+		catch (SQLiteException ex) {
+			ex.printStackTrace();
+			System.out.println("Storage.executeSql(): Error=" +  ex.getMessage());
+			
+			// Send error message back to JavaScript
+			this.sendJavascript("droiddb.fail('" + ex.getMessage() + "','" + tx_id + "');");
+		}
+	}
+
+	/**
+	 * Checks to see the the query is a Data Definintion command
+	 * 
+	 * @param query to be executed
+	 * @return true if it is a DDL command, false otherwise
+	 */
+	private boolean isDDL(String query) {
+		String cmd = query.toLowerCase();
+		if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Process query results.
+	 * 
+	 * @param cur
+	 *            Cursor into query results
+	 * @param tx_id
+	 *            Transaction id
+	 */
+	public void processResults(Cursor cur, String tx_id) {
+
+		String result = "[]";
+		// If query result has rows
+
+		if (cur.moveToFirst()) {
+			JSONArray fullresult = new JSONArray();
+			String key = "";
+			String value = "";
+			int colCount = cur.getColumnCount();
+
+			// Build up JSON result object for each row
+			do {
+				JSONObject row = new JSONObject();
+				try {
+					for (int i = 0; i < colCount; ++i) {
+						key = cur.getColumnName(i);
+						value = cur.getString(i);
+						row.put(key, value);
+					}
+					fullresult.put(row);
+
+				} catch (JSONException e) {
+					e.printStackTrace();
+				}
+
+			} while (cur.moveToNext());
+
+			result = fullresult.toString();
+		}
+
+		// Let JavaScript know that there are no more rows
+		this.sendJavascript("droiddb.completeQuery('" + tx_id + "', " + result + ");");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/TempListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/TempListener.java b/framework/src/org/apache/cordova/TempListener.java
new file mode 100755
index 0000000..85831da
--- /dev/null
+++ b/framework/src/org/apache/cordova/TempListener.java
@@ -0,0 +1,112 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.util.List;
+
+import org.apache.cordova.api.CordovaActivity;
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.content.Context;
+
+public class TempListener extends Plugin implements SensorEventListener {
+	
+    Sensor mSensor;	
+	private SensorManager sensorManager;
+	
+	/**
+	 * 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(CordovaActivity ctx) {
+		super.setContext(ctx);
+        this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
+	}
+
+	/**
+	 * Executes the request and returns PluginResult.
+	 * 
+	 * @param action 		The action to execute.
+	 * @param args 			JSONArry of arguments for the plugin.
+	 * @param callbackId	The callback id used when calling back into JavaScript.
+	 * @return 				A PluginResult object with a status and message.
+	 */
+	public PluginResult execute(String action, JSONArray args, String callbackId) {
+		PluginResult.Status status = PluginResult.Status.OK;
+		String result = "";		
+		
+		if (action.equals("start")) {
+			this.start();
+		}
+		else if (action.equals("stop")) {
+			this.stop();
+		}
+		return new PluginResult(status, result);
+	}
+    
+    /**
+     * Called by AccelBroker when listener is to be shut down.
+     * Stop listener.
+     */
+    public void onDestroy() {
+    	this.stop();    	
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+	public void start()	{
+		List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
+		if (list.size() > 0) {
+			this.mSensor = list.get(0);
+			this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
+		}
+	}
+	
+	public void stop() {
+		this.sensorManager.unregisterListener(this);
+	}
+	
+	public void onAccuracyChanged(Sensor sensor, int accuracy) {
+		// TODO Auto-generated method stub
+	}
+
+	public void onSensorChanged(SensorEvent event) {
+		// We want to know what temp this is.
+		float temp = event.values[0];
+		this.sendJavascript("gotTemp(" + temp + ");");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/CordovaActivity.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/CordovaActivity.java b/framework/src/org/apache/cordova/api/CordovaActivity.java
new file mode 100755
index 0000000..be2a12a
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/CordovaActivity.java
@@ -0,0 +1,80 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import android.app.Activity;
+import android.content.Intent;
+
+/**
+ * The Cordova activity abstract class that is extended by DroidGap.
+ * It is used to isolate plugin development, and remove dependency on entire Cordova library.
+ */
+public abstract class CordovaActivity extends Activity {
+
+    /**
+     * @deprecated
+     * Add services to res/xml/plugins.xml instead.
+     * 
+     * Add a class that implements a service.
+     * 
+     * @param serviceType
+     * @param className
+     */
+    @Deprecated
+    abstract public void addService(String serviceType, String className);
+    
+    /**
+     * Send JavaScript statement back to JavaScript.
+     * 
+     * @param message
+     */
+    abstract public void sendJavascript(String statement);
+
+    /**
+     * 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
+     * @param requestCode		The request code that is passed to callback to identify the activity
+     */
+    abstract public void startActivityForResult(IPlugin command, Intent intent, int requestCode);
+
+    /**
+     * Set the plugin to be called when a sub-activity exits.
+     * 
+     * @param plugin			The plugin on which onActivityResult is to be called
+     */
+    abstract public void setActivityResultCallback(IPlugin plugin);
+
+    /**
+     * Load the specified URL in the Cordova webview.
+     * 
+     * @param url				The URL to load.
+     */
+    abstract public void loadUrl(String url);
+    
+    /**
+     * Send a message to all plugins. 
+     * 
+     * @param id            The message id
+     * @param data          The message data
+     */
+    abstract public void postMessage(String id, Object data);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/IPlugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/IPlugin.java b/framework/src/org/apache/cordova/api/IPlugin.java
new file mode 100755
index 0000000..90a3b1d
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/IPlugin.java
@@ -0,0 +1,116 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import org.json.JSONArray;
+import android.content.Intent;
+import android.webkit.WebView;
+
+/**
+ * Plugin interface must be implemented by any plugin classes.
+ *
+ * The execute method is called by the PluginManager.
+ */
+public interface IPlugin {
+		
+	/**
+	 * 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.
+	 */
+	PluginResult execute(String action, JSONArray args, String callbackId);
+
+	/**
+	 * Identifies if action to be executed returns a value and should be run synchronously.
+	 * 
+	 * @param action	The action to execute
+	 * @return			T=returns value
+	 */
+	public boolean isSynch(String action);
+
+	/**
+	 * Sets the context of the Plugin. This can then be used to do things like
+	 * get file paths associated with the Activity.
+	 * 
+	 * @param ctx The context of the main Activity.
+	 */
+	void setContext(CordovaActivity ctx);
+
+	/**
+	 * Sets the main View of the application, this is the WebView within which 
+	 * a Cordova app runs.
+	 * 
+	 * @param webView The Cordova WebView
+	 */
+	void setView(WebView webView);
+
+    /**
+     * Called when the system is about to start resuming a previous activity. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    void onPause(boolean multitasking);
+
+    /**
+     * Called when the activity will start interacting with the user. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    void onResume(boolean multitasking);
+    
+    /**
+     * Called when the activity receives a new intent. 
+     */
+    void onNewIntent(Intent intent);
+
+    /**
+     * The final call you receive before your activity is destroyed. 
+     */
+    void onDestroy();
+	
+    /**
+     * Called when a message is sent to plugin. 
+     * 
+     * @param id            The message id
+     * @param data          The message data
+     */
+    public void onMessage(String id, Object data);
+
+    /**
+     * 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);
+
+    /**
+     * By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
+     * 
+     * @param url				The URL that is trying to be loaded in the Cordova webview.
+     * @return					Return true to prevent the URL from loading. Default is false.
+     */
+    boolean onOverrideUrlLoading(String url);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/LOG.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/LOG.java b/framework/src/org/apache/cordova/api/LOG.java
new file mode 100755
index 0000000..4e3956b
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/LOG.java
@@ -0,0 +1,234 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import android.util.Log;
+
+/**
+ * Log to Android logging system.
+ * 
+ * Log message can be a string or a printf formatted string with arguments.
+ * See http://developer.android.com/reference/java/util/Formatter.html
+ */
+public class LOG {
+    
+    public static final int VERBOSE = Log.VERBOSE;
+    public static final int DEBUG = Log.DEBUG;
+    public static final int INFO = Log.INFO;
+    public static final int WARN = Log.WARN;
+    public static final int ERROR = Log.ERROR;
+
+    // Current log level
+    public static int LOGLEVEL = Log.ERROR;
+    
+    /**
+     * Set the current log level.
+     * 
+     * @param logLevel
+     */
+    public static void setLogLevel(int logLevel) {
+        LOGLEVEL = logLevel;
+        Log.i("CordovaLog", "Changing log level to " + logLevel);
+    }
+    
+    /**
+     * Set the current log level.
+     * 
+     * @param logLevel
+     */
+    public static void setLogLevel(String logLevel) {
+        if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
+        else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
+        else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
+        else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
+        else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
+        Log.i("CordovaLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
+    }
+
+    /**
+     * Determine if log level will be logged
+     * 
+     * @param logLevel
+     * @return
+     */
+    public static boolean isLoggable(int logLevel) {
+        return (logLevel >= LOGLEVEL);
+    }
+
+    /**
+     * Verbose log message.
+     * 
+     * @param tag
+     * @param s
+     */
+    public static void v(String tag, String s) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
+    }
+
+    /**
+     * Debug log message.
+     * 
+     * @param tag
+     * @param s
+     */
+    public static void d(String tag, String s) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
+    }
+    
+    /**
+     * Info log message.
+     * 
+     * @param tag
+     * @param s
+     */
+    public static void i(String tag, String s) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
+    }
+
+    /**
+     * Warning log message.
+     * 
+     * @param tag
+     * @param s
+     */
+    public static void w(String tag, String s) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
+    }
+
+    /**
+     * Error log message.
+     * 
+     * @param tag
+     * @param s
+     */
+    public static void e(String tag, String s) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
+    }
+
+    /**
+     * Verbose log message.
+     * 
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void v(String tag, String s, Throwable e) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
+    }
+
+    /**
+     * Debug log message.
+     * 
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void d(String tag, String s, Throwable e) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
+    }
+    
+    /**
+     * Info log message.
+     * 
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void i(String tag, String s, Throwable e) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
+    }
+
+    /**
+     * Warning log message.
+     * 
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void w(String tag, String s, Throwable e) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
+    }
+
+    /**
+     * Error log message.
+     * 
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void e(String tag, String s, Throwable e) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
+    }
+
+    /**
+     * Verbose log message with printf formatting.
+     * 
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void v(String tag, String s, Object... args) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
+    }
+
+    /**
+     * Debug log message with printf formatting.
+     * 
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void d(String tag, String s, Object... args) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
+    }
+
+    /**
+     * Info log message with printf formatting.
+     * 
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void i(String tag, String s, Object... args) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
+    }
+    
+    /**
+     * Warning log message with printf formatting.
+     * 
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void w(String tag, String s, Object... args) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
+    }
+    
+    /**
+     * Error log message with printf formatting.
+     * 
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void e(String tag, String s, Object... args) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/Plugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/Plugin.java b/framework/src/org/apache/cordova/api/Plugin.java
new file mode 100755
index 0000000..66bb168
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/Plugin.java
@@ -0,0 +1,210 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import android.content.Intent;
+import android.webkit.WebView;
+
+/**
+ * Plugin interface must be implemented by any plugin classes.
+ *
+ * The execute method is called by the PluginManager.
+ */
+public abstract class Plugin implements IPlugin {
+
+	public String id;
+    public WebView webView;					// WebView object
+    public CordovaActivity ctx;			// CordovaActivity object
+
+	/**
+	 * 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 abstract PluginResult execute(String action, JSONArray args, String callbackId);
+
+	/**
+	 * Identifies if action to be executed returns a value and should be run synchronously.
+	 * 
+	 * @param action	The action to execute
+	 * @return			T=returns value
+	 */
+	public boolean isSynch(String action) {
+		return false;
+	}
+
+	/**
+	 * Sets the context of the Plugin. 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(CordovaActivity ctx) {
+		this.ctx = ctx;
+	}
+
+	/**
+	 * Sets the main View of the application, this is the WebView within which 
+	 * a Cordova app runs.
+	 * 
+	 * @param webView The Cordova WebView
+	 */
+	public void setView(WebView webView) {
+		this.webView = webView;
+	}
+	
+    /**
+     * Called when the system is about to start resuming a previous activity. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onPause(boolean multitasking) {
+    }
+
+    /**
+     * Called when the activity will start interacting with the user. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onResume(boolean multitasking) {
+    }
+    
+    /**
+     * Called when the activity receives a new intent. 
+     */
+    public void onNewIntent(Intent intent) {
+    }
+    
+    /**
+     * The final call you receive before your activity is destroyed. 
+     */
+    public void onDestroy() {
+    }
+	
+    /**
+     * Called when a message is sent to plugin. 
+     * 
+     * @param id            The message id
+     * @param data          The message data
+     */
+    public void onMessage(String id, Object data) {
+    }
+
+    /**
+     * 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) {
+    }
+
+    /**
+     * By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
+     * 
+     * @param url				The URL that is trying to be loaded in the Cordova webview.
+     * @return					Return true to prevent the URL from loading. Default is false.
+     */
+    public boolean onOverrideUrlLoading(String url) {
+    	return false;
+    }
+
+    /**
+     * Send generic JavaScript statement back to JavaScript.
+     * success(...) and error(...) should be used instead where possible.
+     * 
+     * @param statement
+     */
+    public void sendJavascript(String statement) {
+    	this.ctx.sendJavascript(statement);
+    }
+
+    /**
+     * Call the JavaScript success callback for this plugin.
+     * 
+     * This can be used if the execute code for the plugin is asynchronous meaning
+     * that execute should return null and the callback from the async operation can
+     * call success(...) or error(...)
+     * 
+     * @param pluginResult		The result to return.
+	 * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void success(PluginResult pluginResult, String callbackId) {
+    	this.ctx.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     * 
+     * @param message			The message to add to the success result.
+     * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void success(JSONObject message, String callbackId) {
+    	this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     * 
+     * @param message			The message to add to the success result.
+     * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void success(String message, String callbackId) {
+    	this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK, message).toSuccessCallbackString(callbackId));
+    }
+    
+    /**
+     * Call the JavaScript error callback for this plugin.
+     * 
+     * @param pluginResult		The result to return.
+	 * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void error(PluginResult pluginResult, String callbackId) {
+    	this.ctx.sendJavascript(pluginResult.toErrorCallbackString(callbackId));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     * 
+     * @param message			The message to add to the error result.
+     * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void error(JSONObject message, String callbackId) {
+    	this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     * 
+     * @param message			The message to add to the error result.
+     * @param callbackId		The callback id used when calling back into JavaScript.
+     */
+    public void error(String message, String callbackId) {
+    	this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR, message).toErrorCallbackString(callbackId));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java
new file mode 100755
index 0000000..9f47fea
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/PluginManager.java
@@ -0,0 +1,358 @@
+/*
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Intent;
+import android.content.res.XmlResourceParser;
+import android.util.Log;
+import android.webkit.WebView;
+
+/**
+ * PluginManager is exposed to JavaScript in the Cordova WebView.
+ * 
+ * Calling native plugin code can be done by calling PluginManager.exec(...)
+ * from JavaScript.
+ */
+public final class PluginManager {
+
+	private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
+	private HashMap<String, String> services = new HashMap<String,String>();
+	
+	private final CordovaActivity ctx;
+	private final WebView app;
+	
+    // Map URL schemes like foo: to plugins that want to handle those schemes
+    // This would allow how all URLs are handled to be offloaded to a plugin
+    protected HashMap<String, String> urlMap = new HashMap<String,String>();
+	
+	/**
+	 * Constructor.
+	 * 
+	 * @param app
+	 * @param ctx
+	 */
+	public PluginManager(WebView app, CordovaActivity ctx) {
+		this.ctx = ctx;
+		this.app = app;
+		this.loadPlugins();
+	}
+	
+	/**
+	 * Re-init when loading a new HTML page into webview.
+	 */
+	public void reinit() {
+	    
+	    // Stop plugins on current HTML page and discard
+	    this.onPause(false);
+	    this.onDestroy();
+	    this.plugins = new HashMap<String, IPlugin>();
+	}
+	
+	/**
+	 * Load plugins from res/xml/plugins.xml
+	 */
+	public void loadPlugins() {
+		int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
+		if (id == 0) { pluginConfigurationMissing(); }
+		XmlResourceParser xml = ctx.getResources().getXml(id);
+		int eventType = -1;
+		String pluginClass = "", pluginName = "";
+		while (eventType != XmlResourceParser.END_DOCUMENT) {
+			if (eventType == XmlResourceParser.START_TAG) {
+				String strNode = xml.getName();
+				if (strNode.equals("plugin")) {
+					pluginClass = xml.getAttributeValue(null, "value");
+					pluginName = xml.getAttributeValue(null, "name");
+					//System.out.println("Plugin: "+name+" => "+value);
+					this.addService(pluginName, pluginClass);
+					
+					// Create plugin at load time if attribute "onload"
+					if ("true".equals(xml.getAttributeValue(null, "onload"))) {
+					    this.getPlugin(pluginName);
+					}
+				} else if (strNode.equals("url-filter")) {
+					this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
+				}
+			}
+			try {
+				eventType = xml.next();
+			} catch (XmlPullParserException e) {
+				e.printStackTrace();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/**
+	 * Receives a request for execution and fulfills it by finding the appropriate
+	 * Java class and calling it's execute method.
+	 * 
+	 * PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded 
+	 * string is returned that will indicate if any errors have occurred when trying to find
+	 * or execute the class denoted by the clazz argument.
+	 * 
+	 * @param service 		String containing the service to run
+	 * @param action 		String containt the action that the class is supposed to perform. This is
+	 * 						passed to the plugin execute method and it is up to the plugin developer 
+	 * 						how to deal with it.
+	 * @param callbackId 	String containing the id of the callback that is execute in JavaScript if
+	 * 						this is an async plugin call.
+	 * @param args 			An Array literal string containing any arguments needed in the
+	 * 						plugin execute method.
+	 * @param async 		Boolean indicating whether the calling JavaScript code is expecting an
+	 * 						immediate return value. If true, either Cordova.callbackSuccess(...) or 
+	 * 						Cordova.callbackError(...) is called once the plugin code has executed.
+	 * 
+	 * @return 				JSON encoded string with a response message and status.
+	 */
+	@SuppressWarnings("unchecked")
+	public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async) {
+		PluginResult cr = null;
+		boolean runAsync = async;
+		try {
+			final JSONArray args = new JSONArray(jsonArgs);
+			final IPlugin plugin = this.getPlugin(service); 
+			final CordovaActivity ctx = this.ctx;
+			if (plugin != null) {
+				runAsync = async && !plugin.isSynch(action);
+				if (runAsync) {
+					// Run this on a different thread so that this one can return back to JS
+					Thread thread = new Thread(new Runnable() {
+						public void run() {
+							try {
+								// Call execute on the plugin so that it can do it's thing
+								PluginResult cr = plugin.execute(action, args, callbackId);
+								int status = cr.getStatus();
+
+								// If no result to be sent and keeping callback, then no need to sent back to JavaScript
+								if ((status == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
+								}
+
+								// Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
+								else if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
+									ctx.sendJavascript(cr.toSuccessCallbackString(callbackId));
+								} 
+								
+								// If error
+								else {
+									ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
+								}
+							} catch (Exception e) {
+								PluginResult cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
+								ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
+							}
+						}
+					});
+					thread.start();
+					return "";
+				} else {
+					// Call execute on the plugin so that it can do it's thing
+					cr = plugin.execute(action, args, callbackId);
+
+					// If no result to be sent and keeping callback, then no need to sent back to JavaScript
+					if ((cr.getStatus() == PluginResult.Status.NO_RESULT.ordinal()) && cr.getKeepCallback()) {
+						return "";
+					}
+				}
+			}
+		} catch (JSONException e) {
+			System.out.println("ERROR: "+e.toString());
+			cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+		}
+		// if async we have already returned at this point unless there was an error...
+		if (runAsync) {
+			if (cr == null) {
+				cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);				
+			}
+			ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
+		}
+		return ( cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }" );
+	}
+	
+	/**
+	 * Get the class.
+	 * 
+	 * @param clazz
+	 * @return
+	 * @throws ClassNotFoundException
+	 */
+	@SuppressWarnings("unchecked")
+	private Class getClassByName(final String clazz) throws ClassNotFoundException {
+		Class c = null;
+		if (clazz != null) {
+			c = Class.forName(clazz);
+		}
+		return c;
+	}
+
+	/**
+	 * Get the interfaces that a class implements and see if it implements the
+	 * org.apache.cordova.api.Plugin interface.
+	 * 
+	 * @param c The class to check the interfaces of.
+	 * @return Boolean indicating if the class implements org.apache.cordova.api.Plugin
+	 */
+	@SuppressWarnings("unchecked")
+	private boolean isCordovaPlugin(Class c) {
+		if (c != null) {
+			return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);
+		}
+		return false;
+	}
+
+    /**
+     * Add plugin to be loaded and cached.  This creates an instance of the plugin.
+     * If plugin is already created, then just return it.
+     * 
+     * @param className				The class to load
+     * @param clazz					The class object (must be a class object of the className)
+     * @param callbackId			The callback id to use when calling back into JavaScript
+     * @return						The plugin
+     */
+	@SuppressWarnings("unchecked")
+	private IPlugin addPlugin(String pluginName, String className) {
+		try {
+			Class c = getClassByName(className);
+			if (isCordovaPlugin(c)) {
+				IPlugin plugin = (IPlugin)c.newInstance();
+				this.plugins.put(className, plugin);
+				plugin.setContext(this.ctx);
+				plugin.setView(this.app);
+				return plugin;
+			}
+    	} catch (Exception e) {
+    		  e.printStackTrace();
+    		  System.out.println("Error adding plugin "+className+".");
+    	}
+    	return null;
+    }
+    
+    /**
+     * Get the loaded plugin.
+     * 
+     * If the plugin is not already loaded then load it.
+     * 
+     * @param className				The class of the loaded plugin.
+     * @return
+     */
+    private IPlugin getPlugin(String pluginName) {
+		String className = this.services.get(pluginName);
+    	if (this.plugins.containsKey(className)) {
+    		return this.plugins.get(className);
+    	} else {
+	    	return this.addPlugin(pluginName, className);
+	    }
+    }
+    
+    /**
+     * Add a class that implements a service.
+     * This does not create the class instance.  It just maps service name to class name.
+     * 
+     * @param serviceType
+     * @param className
+     */
+    public void addService(String serviceType, String className) {
+    	this.services.put(serviceType, className);
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onPause(boolean multitasking) {
+        for (IPlugin plugin : this.plugins.values()) {
+            plugin.onPause(multitasking);
+        }
+    }
+    
+    /**
+     * Called when the activity will start interacting with the user. 
+     * 
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onResume(boolean multitasking) {
+        for (IPlugin plugin : this.plugins.values()) {
+            plugin.onResume(multitasking);
+        }
+    }
+
+    /**
+     * The final call you receive before your activity is destroyed. 
+     */
+    public void onDestroy() {
+        for (IPlugin plugin : this.plugins.values()) {
+            plugin.onDestroy();
+        }
+    }
+
+    /**
+     * Send a message to all plugins. 
+     * 
+     * @param id            The message id
+     * @param data          The message data
+     */
+    public void postMessage(String id, Object data) {
+        for (IPlugin plugin : this.plugins.values()) {
+            plugin.onMessage(id, data);
+        }
+    }
+
+    /**
+     * Called when the activity receives a new intent. 
+     */    
+    public void onNewIntent(Intent intent) {
+        for (IPlugin plugin : this.plugins.values()) {
+            plugin.onNewIntent(intent);
+        }
+    }
+
+    /**
+     * Called when the URL of the webview changes.
+     * 
+     * @param url The URL that is being changed to.
+     * @return Return false to allow the URL to load, return true to prevent the URL from loading.
+     */
+    public boolean onOverrideUrlLoading(String url) {
+    	Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
+        while (it.hasNext()) {
+            HashMap.Entry<String, String> pairs = it.next();
+            if (url.startsWith(pairs.getKey())) {
+            	return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
+            }
+        }
+    	return false;
+    }
+
+	private void pluginConfigurationMissing() {
+		System.err.println("=====================================================================================");
+		System.err.println("ERROR: plugin.xml is missing.  Add res/xml/plugins.xml to your project.");      
+		System.err.println("https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=blob;f=framework/res/xml/plugins.xml");        
+		System.err.println("=====================================================================================");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/api/PluginResult.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginResult.java b/framework/src/org/apache/cordova/api/PluginResult.java
new file mode 100755
index 0000000..4841995
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/PluginResult.java
@@ -0,0 +1,140 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import android.util.Log;
+
+public class PluginResult {
+	private final int status;
+	private final String message;
+	private boolean keepCallback = false;
+	private String cast = null;
+	
+	public PluginResult(Status status) {
+		this.status = status.ordinal();
+		this.message = "'" + PluginResult.StatusMessages[this.status] + "'";
+	}
+	
+	public PluginResult(Status status, String message) {
+		this.status = status.ordinal();
+		this.message = JSONObject.quote(message);
+	}
+
+	public PluginResult(Status status, JSONArray message, String cast) {
+		this.status = status.ordinal();
+		this.message = message.toString();
+		this.cast = cast;
+	}
+
+	public PluginResult(Status status, JSONObject message, String cast) {
+		this.status = status.ordinal();
+		this.message = message.toString();
+		this.cast = cast;
+	}
+
+	public PluginResult(Status status, JSONArray message) {
+		this.status = status.ordinal();
+		this.message = message.toString();
+	}
+
+	public PluginResult(Status status, JSONObject message) {
+		this.status = status.ordinal();
+		this.message = message.toString();
+	}
+
+	public PluginResult(Status status, int i) {
+		this.status = status.ordinal();
+		this.message = ""+i;
+	}
+
+	public PluginResult(Status status, float f) {
+		this.status = status.ordinal();
+		this.message = ""+f;
+	}
+
+	public PluginResult(Status status, boolean b) {
+		this.status = status.ordinal();
+		this.message = ""+b;
+	}
+	
+	public void setKeepCallback(boolean b) {
+		this.keepCallback = b;
+	}
+	
+	public int getStatus() {
+		return status;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+	
+	public boolean getKeepCallback() {
+		return this.keepCallback;
+	}
+	
+	public String getJSONString() {
+		return "{status:" + this.status + ",message:" + this.message + ",keepCallback:" + this.keepCallback + "}";
+	}
+	
+	public String toSuccessCallbackString(String callbackId) {
+		StringBuffer buf = new StringBuffer("");
+		if (cast != null) {
+			buf.append("var temp = "+cast+"("+this.getJSONString() + ");\n");
+			buf.append("Cordova.callbackSuccess('"+callbackId+"',temp);");
+		}
+		else {
+			buf.append("Cordova.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");");			
+		}
+		return buf.toString();
+	}
+	
+	public String toErrorCallbackString(String callbackId) {
+		return "Cordova.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
+	}
+	
+	public static String[] StatusMessages = new String[] {
+		"No result",
+		"OK",
+		"Class not found",
+		"Illegal access",
+		"Instantiation error",
+		"Malformed url",
+		"IO error",
+		"Invalid action",
+		"JSON error",
+		"Error"
+	};
+	
+	public enum Status {
+		NO_RESULT,
+		OK,
+		CLASS_NOT_FOUND_EXCEPTION,
+		ILLEGAL_ACCESS_EXCEPTION,
+		INSTANTIATION_EXCEPTION,
+		MALFORMED_URL_EXCEPTION,
+		IO_EXCEPTION,
+		INVALID_ACTION,
+		JSON_EXCEPTION,
+		ERROR
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/file/EncodingException.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/file/EncodingException.java b/framework/src/org/apache/cordova/file/EncodingException.java
new file mode 100644
index 0000000..4dbbd5e
--- /dev/null
+++ b/framework/src/org/apache/cordova/file/EncodingException.java
@@ -0,0 +1,28 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+public class EncodingException extends Exception {
+
+	public EncodingException(String message) {
+		super(message);
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/file/FileExistsException.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/file/FileExistsException.java b/framework/src/org/apache/cordova/file/FileExistsException.java
new file mode 100644
index 0000000..af246e5
--- /dev/null
+++ b/framework/src/org/apache/cordova/file/FileExistsException.java
@@ -0,0 +1,28 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+public class FileExistsException extends Exception {
+
+	public FileExistsException(String msg) {
+		super(msg);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/file/InvalidModificationException.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/file/InvalidModificationException.java b/framework/src/org/apache/cordova/file/InvalidModificationException.java
new file mode 100644
index 0000000..1067265
--- /dev/null
+++ b/framework/src/org/apache/cordova/file/InvalidModificationException.java
@@ -0,0 +1,29 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+
+package org.apache.cordova.file;
+
+public class InvalidModificationException extends Exception {
+
+	public InvalidModificationException(String message) {
+		super(message);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/file/NoModificationAllowedException.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/file/NoModificationAllowedException.java b/framework/src/org/apache/cordova/file/NoModificationAllowedException.java
new file mode 100644
index 0000000..e441a53
--- /dev/null
+++ b/framework/src/org/apache/cordova/file/NoModificationAllowedException.java
@@ -0,0 +1,28 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova.file;
+
+public class NoModificationAllowedException extends Exception {
+
+	public NoModificationAllowedException(String message) {
+		super(message);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/src/org/apache/cordova/file/TypeMismatchException.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/file/TypeMismatchException.java b/framework/src/org/apache/cordova/file/TypeMismatchException.java
new file mode 100644
index 0000000..ea55e30
--- /dev/null
+++ b/framework/src/org/apache/cordova/file/TypeMismatchException.java
@@ -0,0 +1,29 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+
+package org.apache.cordova.file;
+
+public class TypeMismatchException extends Exception {
+
+	public TypeMismatchException(String message) {
+		super(message);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/test/com/phonegap/PreferenceNodeTest.java
----------------------------------------------------------------------
diff --git a/framework/test/com/phonegap/PreferenceNodeTest.java b/framework/test/com/phonegap/PreferenceNodeTest.java
deleted file mode 100644
index 91cf4bf..0000000
--- a/framework/test/com/phonegap/PreferenceNodeTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-import org.junit.*;
-import static org.junit.Assert.*;
-
-import com.phonegap.PreferenceNode;
-
-public class PreferenceNodeTest {
-    @Test
-        public void testConstructor() {
-            PreferenceNode foo = new com.phonegap.PreferenceNode("fullscreen", "false", false);
-            assertEquals("fullscreen", foo.name);
-            assertEquals("false", foo.value);
-            assertEquals(false, foo.readonly);
-        }
-
-    @Test
-        public void testNameAssignment() {
-            PreferenceNode foo = new com.phonegap.PreferenceNode("fullscreen", "false", false);
-            foo.name = "widescreen";
-            assertEquals("widescreen", foo.name);
-        }
-
-    @Test
-        public void testValueAssignment() {
-            PreferenceNode foo = new com.phonegap.PreferenceNode("fullscreen", "false", false);
-            foo.value = "maybe";
-            assertEquals("maybe", foo.value);
-        }
-
-    @Test
-        public void testReadonlyAssignment() {
-            PreferenceNode foo = new com.phonegap.PreferenceNode("fullscreen", "false", false);
-            foo.readonly = true;
-            assertEquals(true, foo.readonly);
-        }
-}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/test/com/phonegap/PreferenceSetTest.java
----------------------------------------------------------------------
diff --git a/framework/test/com/phonegap/PreferenceSetTest.java b/framework/test/com/phonegap/PreferenceSetTest.java
deleted file mode 100644
index 2eba245..0000000
--- a/framework/test/com/phonegap/PreferenceSetTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-import org.junit.*;
-import static org.junit.Assert.*;
-
-import com.phonegap.PreferenceNode;
-import com.phonegap.PreferenceSet;
-
-public class PreferenceSetTest {
-    private PreferenceSet preferences;
-    private PreferenceNode screen;
-
-    @Before
-        public void setUp() {
-            preferences = new PreferenceSet();
-            screen = new PreferenceNode("fullscreen", "true", false);
-        }
-
-    @Test
-        public void testAddition() {
-            preferences.add(screen);
-            assertEquals(1, preferences.size());
-        }
-
-    @Test
-        public void testClear() {
-            preferences.add(screen);
-            preferences.clear();
-            assertEquals(0, preferences.size());
-        }
-
-    @Test
-        public void testPreferenceRetrieval() {
-            preferences.add(screen);
-            assertEquals("true", preferences.pref("fullscreen"));
-        }
-
-    @Test
-        public void testNoPreferenceRetrieval() {
-            // return null if the preference is not defined
-            assertEquals(null, preferences.pref("antigravity"));
-        }
-
-    @Test
-        public void testUnsetPreferenceChecking() {
-            PreferenceSet emptySet = new PreferenceSet();
-            boolean value = emptySet.prefMatches("fullscreen", "true");
-            assertEquals(false, value);
-        }
-
-    @Test
-        public void testSetPreferenceChecking() {
-            preferences.add(screen);
-            boolean value = preferences.prefMatches("fullscreen", "true");
-            assertEquals(true, value);
-        }
-}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/test/org/apache/cordova/PreferenceNodeTest.java
----------------------------------------------------------------------
diff --git a/framework/test/org/apache/cordova/PreferenceNodeTest.java b/framework/test/org/apache/cordova/PreferenceNodeTest.java
new file mode 100644
index 0000000..4a1696c
--- /dev/null
+++ b/framework/test/org/apache/cordova/PreferenceNodeTest.java
@@ -0,0 +1,35 @@
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import org.apache.cordova.PreferenceNode;
+
+public class PreferenceNodeTest {
+    @Test
+        public void testConstructor() {
+            PreferenceNode foo = new org.apache.cordova.PreferenceNode("fullscreen", "false", false);
+            assertEquals("fullscreen", foo.name);
+            assertEquals("false", foo.value);
+            assertEquals(false, foo.readonly);
+        }
+
+    @Test
+        public void testNameAssignment() {
+            PreferenceNode foo = new org.apache.cordova.PreferenceNode("fullscreen", "false", false);
+            foo.name = "widescreen";
+            assertEquals("widescreen", foo.name);
+        }
+
+    @Test
+        public void testValueAssignment() {
+            PreferenceNode foo = new org.apache.cordova.PreferenceNode("fullscreen", "false", false);
+            foo.value = "maybe";
+            assertEquals("maybe", foo.value);
+        }
+
+    @Test
+        public void testReadonlyAssignment() {
+            PreferenceNode foo = new org.apache.cordova.PreferenceNode("fullscreen", "false", false);
+            foo.readonly = true;
+            assertEquals(true, foo.readonly);
+        }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/664a061d/framework/test/org/apache/cordova/PreferenceSetTest.java
----------------------------------------------------------------------
diff --git a/framework/test/org/apache/cordova/PreferenceSetTest.java b/framework/test/org/apache/cordova/PreferenceSetTest.java
new file mode 100644
index 0000000..5c612fa
--- /dev/null
+++ b/framework/test/org/apache/cordova/PreferenceSetTest.java
@@ -0,0 +1,55 @@
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import org.apache.cordova.PreferenceNode;
+import org.apache.cordova.PreferenceSet;
+
+public class PreferenceSetTest {
+    private PreferenceSet preferences;
+    private PreferenceNode screen;
+
+    @Before
+        public void setUp() {
+            preferences = new PreferenceSet();
+            screen = new PreferenceNode("fullscreen", "true", false);
+        }
+
+    @Test
+        public void testAddition() {
+            preferences.add(screen);
+            assertEquals(1, preferences.size());
+        }
+
+    @Test
+        public void testClear() {
+            preferences.add(screen);
+            preferences.clear();
+            assertEquals(0, preferences.size());
+        }
+
+    @Test
+        public void testPreferenceRetrieval() {
+            preferences.add(screen);
+            assertEquals("true", preferences.pref("fullscreen"));
+        }
+
+    @Test
+        public void testNoPreferenceRetrieval() {
+            // return null if the preference is not defined
+            assertEquals(null, preferences.pref("antigravity"));
+        }
+
+    @Test
+        public void testUnsetPreferenceChecking() {
+            PreferenceSet emptySet = new PreferenceSet();
+            boolean value = emptySet.prefMatches("fullscreen", "true");
+            assertEquals(false, value);
+        }
+
+    @Test
+        public void testSetPreferenceChecking() {
+            preferences.add(screen);
+            boolean value = preferences.prefMatches("fullscreen", "true");
+            assertEquals(true, value);
+        }
+}