First DroidGap (1.1) version, use at your own risk

This commit is contained in:
Chris Brody 2012-04-05 01:11:25 +02:00
parent a9b94c2190
commit 641b19daa3
4 changed files with 682 additions and 2 deletions

View File

@ -0,0 +1,316 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010-2011, IBM Corporation
*/
/*
* This is purely for the Android 1.5/1.6 HTML 5 Storage
* I was hoping that Android 2.0 would deprecate this, but given the fact that
* most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
*/
/**
* SQL result set object
* PRIVATE METHOD
* @constructor
*/
var DDB_Rows = function() {
this.resultSet = []; // results array
this.length = 0; // number of rows
};
/**
* Get item from SQL result set
*
* @param row The row number to return
* @return The row object
*/
DDB_Rows.prototype.item = function(row) {
return this.resultSet[row];
};
/**
* SQL result set that is returned to user.
* PRIVATE METHOD
* @constructor
*/
var DDB_Result = function() {
this.rows = new DDB_Rows();
};
/**
* Storage object that is called by native code when performing queries.
* PRIVATE METHOD
* @constructor
*/
var DDB = function() {
this.queryQueue = {};
};
/**
* Callback from native code when query is complete.
* PRIVATE METHOD
*
* @param id Query id
*/
DDB.prototype.completeQuery = function(id, data) {
var query = this.queryQueue[id];
if (query) {
try {
delete this.queryQueue[id];
// Get transaction
var tx = query.tx;
// If transaction hasn't failed
// Note: We ignore all query results if previous query
// in the same transaction failed.
if (tx && tx.queryList[id]) {
// Save query results
var r = new DDB_Result();
r.rows.resultSet = data;
r.rows.length = data.length;
try {
if (typeof query.successCallback === 'function') {
query.successCallback(query.tx, r);
}
} catch (ex) {
console.log("executeSql error calling user success callback: "+ex);
}
tx.queryComplete(id);
}
} catch (e) {
console.log("executeSql error: "+e);
}
}
};
/**
* Callback from native code when query fails
* PRIVATE METHOD
*
* @param reason Error message
* @param id Query id
*/
DDB.prototype.fail = function(reason, id) {
var query = this.queryQueue[id];
if (query) {
try {
delete this.queryQueue[id];
// Get transaction
var tx = query.tx;
// If transaction hasn't failed
// Note: We ignore all query results if previous query
// in the same transaction failed.
if (tx && tx.queryList[id]) {
tx.queryList = {};
try {
if (typeof query.errorCallback === 'function') {
query.errorCallback(query.tx, reason);
}
} catch (ex) {
console.log("executeSql error calling user error callback: "+ex);
}
tx.queryFailed(id, reason);
}
} catch (e) {
console.log("executeSql error: "+e);
}
}
};
/**
* SQL query object
* PRIVATE METHOD
*
* @constructor
* @param tx The transaction object that this query belongs to
*/
var DDB_Query = function(tx) {
// Set the id of the query
this.id = PhoneGap.createUUID();
// Add this query to the queue
dddb.queryQueue[this.id] = this;
// Init result
this.resultSet = [];
// Set transaction that this query belongs to
this.tx = tx;
// Add this query to transaction list
this.tx.queryList[this.id] = this;
// Callbacks
this.successCallback = null;
this.errorCallback = null;
};
/**
* Transaction object
* PRIVATE METHOD
* @constructor
*/
var DDB_Tx = function() {
// Set the id of the transaction
this.id = PhoneGap.createUUID();
// Callbacks
this.successCallback = null;
this.errorCallback = null;
// Query list
this.queryList = {};
};
/**
* Mark query in transaction as complete.
* If all queries are complete, call the user's transaction success callback.
*
* @param id Query id
*/
DDB_Tx.prototype.queryComplete = function(id) {
delete this.queryList[id];
// If no more outstanding queries, then fire transaction success
if (this.successCallback) {
var count = 0;
var i;
for (i in this.queryList) {
if (this.queryList.hasOwnProperty(i)) {
count++;
}
}
if (count === 0) {
try {
this.successCallback();
} catch(e) {
console.log("Transaction error calling user success callback: " + e);
}
}
}
};
/**
* Mark query in transaction as failed.
*
* @param id Query id
* @param reason Error message
*/
DDB_Tx.prototype.queryFailed = function(id, reason) {
// The sql queries in this transaction have already been run, since
// we really don't have a real transaction implemented in native code.
// However, the user callbacks for the remaining sql queries in transaction
// will not be called.
this.queryList = {};
if (this.errorCallback) {
try {
this.errorCallback(reason);
} catch(e) {
console.log("Transaction error calling user error callback: " + e);
}
}
};
/**
* Execute SQL statement
*
* @param sql SQL statement to execute
* @param params Statement parameters
* @param successCallback Success callback
* @param errorCallback Error callback
*/
DDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) {
// Init params array
if (typeof params === 'undefined') {
params = [];
}
// Create query and add to queue
var query = new DDB_Query(this);
dddb.queryQueue[query.id] = query;
// Save callbacks
query.successCallback = successCallback;
query.errorCallback = errorCallback;
// Call native code
PhoneGap.exec(null, null, "SQLitePlugin", "executeSql", [sql, params, query.id]);
};
var DatabaseShell = function() {
};
/**
* Start a transaction.
* Does not support rollback in event of failure.
*
* @param process {Function} The transaction function
* @param successCallback {Function}
* @param errorCallback {Function}
*/
DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
var tx = new DDB_Tx();
tx.successCallback = successCallback;
tx.errorCallback = errorCallback;
try {
process(tx);
} catch (e) {
console.log("Transaction error: "+e);
if (tx.errorCallback) {
try {
tx.errorCallback(e);
} catch (ex) {
console.log("Transaction error calling user error callback: "+e);
}
}
}
};
/**
* Open database
*
* @param name Database name
* @param version Database version
* @param display_name Database display name
* @param size Database size in bytes
* @return Database object
*/
var DDB_openDatabase = function(name, version, display_name, size) {
PhoneGap.exec(null, null, "SQLitePlugin", "openDatabase", [name, version, display_name, size]);
var db = new DatabaseShell();
return db;
};
/**
* For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
* TODO: Do similar for sessionStorage.
*/
/**
* @constructor
*/
window.my_openDatabase = function(name, version, desc, size){
window.dddb = new DDB();
return DDB_openDatabase(name, version, desc, size);
}

View File

@ -0,0 +1,111 @@
<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>PhoneGap</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="phonegap-1.1.0.js"></script>
<script type="text/javascript" charset="utf-8" src="SQLitePlugin.js"></script>
<script type="text/javascript" charset="utf-8" src="main.js"></script>
<script type="text/javascript" charset="utf-8" >
function init1test() {
//alert("alert 0");
}
// Wait for PhoneGap to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
//
function onDeviceReady() {
var db = window.my_openDatabase("Database", "1.0", "PhoneGap Demo", 200000);
db.transaction(function(tx) {
tx.executeSql('DROP TABLE IF EXISTS test_table');
tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (id integer primary key, data text, data_num integer)');
return tx.executeSql("INSERT INTO test_table (data, data_num) VALUES (?,?)", ["test", 100], function(tx, res) {
//console.log("insertId: " + res.insertId + " -- probably 1");
//console.log("rowsAffected: " + res.rowsAffected + " -- should be 1");
tx.executeSql("select count(id) as cnt from test_table;", [], function(tx, res) {
console.log("rows.length: " + res.rows.length + " -- should be 1");
return console.log("rows[0].cnt: " + res.rows.item(0).cnt + " -- should be 1");
});
}, function(e) {
return console.log("ERROR: " + e.message);
});
});
}
// Populate the database
//
function populateDB(tx) {
alert("a 3");
tx.executeSql('DROP TABLE IF EXISTS DEMO');
alert("a 4");
tx.executeSql('CREATE TABLE IF NOT EXISTS DEMO (id unique, data)');
alert("a 5");
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (1, "First row")');
alert("a 6");
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (2, "Second row")');
alert("a 7");
}
// Transaction error callback
//
function errorCB(tx, err) {
alert("Error processing SQL: "+err);
}
// Transaction success callback
//
function successCB() {
alert("success!");
}
</script>
</head>
<body onload="init1test();" id="stage" class="theme">
<h1>Welcome to PhoneGap!</h1>
<h2>this file is located at assets/www/index.html</h2>
<div id="info">
<h4>Platform: <span id="platform"> &nbsp;</span>, Version: <span id="version">&nbsp;</span></h4>
<h4>UUID: <span id="uuid"> &nbsp;</span>, Name: <span id="name">&nbsp;</span></h4>
<h4>Width: <span id="width"> &nbsp;</span>, Height: <span id="height">&nbsp;
</span>, Color Depth: <span id="colorDepth"></span></h4>
</div>
<dl id="accel-data">
<dt>X:</dt><dd id="x">&nbsp;</dd>
<dt>Y:</dt><dd id="y">&nbsp;</dd>
<dt>Z:</dt><dd id="z">&nbsp;</dd>
</dl>
<a href="#" class="btn large" onclick="toggleAccel();">Toggle Accelerometer</a>
<a href="#" class="btn large" onclick="getLocation();">Get Location</a>
<a href="tel:411" class="btn large">Call 411</a>
<a href="#" class="btn large" onclick="beep();">Beep</a>
<a href="#" class="btn large" onclick="vibrate();">Vibrate</a>
<a href="#" class="btn large" onclick="show_pic();">Get a Picture</a>
<a href="#" class="btn large" onclick="get_contacts();">Get Phone's Contacts</a>
<a href="#" class="btn large" onclick="check_network();">Check Network</a>
<div id="viewport" class="viewport" style="display: none;">
<img style="width:60px;height:60px" id="test_img" src="" />
</div>
</body>
</html>

View File

@ -0,0 +1,248 @@
/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
*/
package com.phonegap.plugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import android.database.Cursor;
import android.database.sqlite.*;
import android.util.Log;
/**
* This class implements the HTML5 database support for Android 1.X devices. It
* is not used for Android 2.X, since HTML5 database is built in to the browser.
*/
public class SQLitePlugin 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 SQLitePlugin() {
}
/**
* 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 {
// TODO: Do we want to allow a user to do this, since they could get
// to other app databases?
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")) {
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
// --------------------------------------------------------------------------
/**
* Set the application package for the database. Each application saves its
* database files in a directory with the application package as part of the
* file name.
*
* For example, application "com.phonegap.demo.Demo" would save its database
* files in "/data/data/com.phonegap.demo/databases/" directory.
*
* @param appPackage
* The application package.
*/
public void setStorage(String appPackage) {
this.path = "/data/data/" + appPackage + "/databases/";
}
/**
* 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) {
Package pack = this.ctx.getClass().getPackage();
String appPackage = pack.getName();
this.setStorage(appPackage);
}
this.dbName = this.path + 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("dddb.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("SQLitePlugin.executeSql(): Error=" + ex.getMessage());
// Send error message back to JavaScript
this.sendJavascript("dddb.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("dddb.completeQuery('" + tx_id + "', " + result
+ ");");
}
}

View File

@ -9,7 +9,7 @@ Created by @Joenoon:
Adapted to 1.5 by @coomsie
API changes by @chbrody
API changes and Android version by @chbrody
DISCLAIMER:
@ -89,10 +89,15 @@ Insert this in there:
General Usage
=============
Android (DroidGap)
------------------
I put the information here for the sake of completeness. I have tested the DroidGap SQLitePlugin version on a simulator on PhoneGap 1.1 *ONLY* and do not guarantee what will happen in any other situation. Basically, I copied and adapted the code from storage.js and Storage.java to make a plugin version. I got the versions that were there on October 2011, so it should be OK to use them under the MIT or Apache licenses. Hereby you can take SQLitePlugin.java (it is in the wrong place but it still worked), SQLitePlugin.js, and look at my index.html, register in plugins.xml, and give it your best shot! Fork it and take it over!
Cordova iOS
-----------
**NOTE:** Please use sqliteNative.openDatabase() to open a database, the parameters are different from the old SQLitePlugin() constructor which is now gone. This should a closer resemblance to the HTML5/W3 SQL API.
**NOTE:** Please use sqliteNative.openDatabase() to open a database, this will be changed to sqlitePlugin.openDatabase(), the parameters are different from the old SQLitePlugin() constructor which is now gone. This should a closer resemblance to the HTML5/W3 SQL API.
## Coffee Script