mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-26 12:03:28 +08:00
Fix database for Android 1.x devices. It now behaves like HTML5 database API.
This commit is contained in:
parent
5164464d28
commit
032db387f8
@ -316,7 +316,9 @@ PhoneGap.stringify = function(args) {
|
|||||||
s = s + '}';
|
s = s + '}';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s = s + '"' + args[i] + '"';
|
var a = args[i].replace(/\\/g, '\\\\');
|
||||||
|
a = a.replace(/"/g, '\\"');
|
||||||
|
s = s + '"' + a + '"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = s + "]";
|
s = s + "]";
|
||||||
|
154
framework/assets/js/storage.js
Normal file → Executable file
154
framework/assets/js/storage.js
Normal file → Executable file
@ -5,71 +5,175 @@
|
|||||||
* most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
|
* most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Storage object that is called by native code when performing queries.
|
||||||
|
* PRIVATE METHOD
|
||||||
|
*/
|
||||||
var DroidDB = function() {
|
var DroidDB = function() {
|
||||||
this.txQueue = [];
|
this.txQueue = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback from native code when result from a query is available.
|
||||||
|
* PRIVATE METHOD
|
||||||
|
*
|
||||||
|
* @param rawdata JSON string of the row data
|
||||||
|
* @param tx_id Transaction id
|
||||||
|
*/
|
||||||
DroidDB.prototype.addResult = function(rawdata, tx_id) {
|
DroidDB.prototype.addResult = function(rawdata, tx_id) {
|
||||||
eval("var data = " + rawdata);
|
try {
|
||||||
|
eval("var data = " + rawdata + ";");
|
||||||
var tx = this.txQueue[tx_id];
|
var tx = this.txQueue[tx_id];
|
||||||
tx.resultSet.push(data);
|
tx.resultSet.push(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("DroidDB.addResult(): Error="+e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback from native code when query is complete.
|
||||||
|
* PRIVATE METHOD
|
||||||
|
*
|
||||||
|
* @param tx_id
|
||||||
|
*/
|
||||||
DroidDB.prototype.completeQuery = function(tx_id) {
|
DroidDB.prototype.completeQuery = function(tx_id) {
|
||||||
var tx = this.txQueue[tx_id];
|
var tx = null;
|
||||||
var r = new result();
|
try {
|
||||||
|
tx = this.txQueue[tx_id];
|
||||||
|
var r = new DroidDB_Result();
|
||||||
r.rows.resultSet = tx.resultSet;
|
r.rows.resultSet = tx.resultSet;
|
||||||
r.rows.length = tx.resultSet.length;
|
r.rows.length = tx.resultSet.length;
|
||||||
tx.win(r);
|
delete this.txQueue[tx_id];
|
||||||
|
} catch (e) {
|
||||||
|
console.log("DroidDB.completeQuery(): Error="+e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
tx.successCallback(tx, r);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("DroidDB.completeQuery(): Error calling user success callback="+e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback from native code when query fails
|
||||||
|
* PRIVATE METHOD
|
||||||
|
*
|
||||||
|
* @param reason
|
||||||
|
* @param tx_id
|
||||||
|
*/
|
||||||
DroidDB.prototype.fail = function(reason, tx_id) {
|
DroidDB.prototype.fail = function(reason, tx_id) {
|
||||||
var tx = this.txQueue[tx_id];
|
var tx = null;
|
||||||
tx.fail(reason);
|
try {
|
||||||
|
tx = this.txQueue[tx_id];
|
||||||
|
delete this.txQueue[tx_id];
|
||||||
|
} catch (e) {
|
||||||
|
console.log("DroidDB.fail(): Error="+e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
tx.errorCallback(reason);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("DroidDB.fail(): Error calling user error callback="+e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var DatabaseShell = function() {
|
var DatabaseShell = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a transaction.
|
||||||
|
*
|
||||||
|
* @param process {Function} The transaction function
|
||||||
|
*/
|
||||||
DatabaseShell.prototype.transaction = function(process) {
|
DatabaseShell.prototype.transaction = function(process) {
|
||||||
tx = new Tx();
|
var tx = new DroidDB_Tx();
|
||||||
process(tx);
|
process(tx);
|
||||||
};
|
};
|
||||||
|
|
||||||
var Tx = function() {
|
/**
|
||||||
droiddb.txQueue.push(this);
|
* Transaction object
|
||||||
this.id = droiddb.txQueue.length - 1;
|
* PRIVATE METHOD
|
||||||
|
*/
|
||||||
|
var DroidDB_Tx = function() {
|
||||||
|
|
||||||
|
// Set the id of the transaction
|
||||||
|
this.id = PhoneGap.createUUID();
|
||||||
|
|
||||||
|
// Add this transaction to the queue
|
||||||
|
droiddb.txQueue[this.id] = this;
|
||||||
|
|
||||||
|
// Init result
|
||||||
this.resultSet = [];
|
this.resultSet = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
Tx.prototype.executeSql = function(query, params, win, fail) {
|
/**
|
||||||
|
* Execute SQL statement
|
||||||
|
*
|
||||||
|
* @param query
|
||||||
|
* @param params
|
||||||
|
* @param successCallback
|
||||||
|
* @param errorCallback
|
||||||
|
*/
|
||||||
|
DroidDB_Tx.prototype.executeSql = function(query, params, successCallback, errorCallback) {
|
||||||
|
|
||||||
|
// Init params array
|
||||||
|
if (typeof params == 'undefined') {
|
||||||
|
params = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save callbacks
|
||||||
|
var tx = droiddb.txQueue[this.id];
|
||||||
|
tx.successCallback = successCallback;
|
||||||
|
tx.errorCallback = errorCallback;
|
||||||
|
|
||||||
|
// Call native code
|
||||||
PhoneGap.execAsync(null, null, "Storage", "executeSql", [query, params, this.id]);
|
PhoneGap.execAsync(null, null, "Storage", "executeSql", [query, params, this.id]);
|
||||||
tx.win = win;
|
|
||||||
tx.fail = fail;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = function() {
|
/**
|
||||||
this.rows = new Rows();
|
* SQL result set that is returned to user.
|
||||||
|
* PRIVATE METHOD
|
||||||
|
*/
|
||||||
|
DroidDB_Result = function() {
|
||||||
|
this.rows = new DroidDB_Rows();
|
||||||
};
|
};
|
||||||
|
|
||||||
var Rows = function() {
|
/**
|
||||||
this.resultSet = [];
|
* SQL result set object
|
||||||
this.length = 0;
|
* PRIVATE METHOD
|
||||||
|
*/
|
||||||
|
DroidDB_Rows = function() {
|
||||||
|
this.resultSet = []; // results array
|
||||||
|
this.length = 0; // number of rows
|
||||||
};
|
};
|
||||||
|
|
||||||
Rows.prototype.item = function(row_id) {
|
/**
|
||||||
return this.resultSet[id];
|
* Get item from SQL result set
|
||||||
|
*
|
||||||
|
* @param row The row number to return
|
||||||
|
* @return The row object
|
||||||
|
*/
|
||||||
|
DroidDB_Rows.prototype.item = function(row) {
|
||||||
|
return this.resultSet[row];
|
||||||
};
|
};
|
||||||
|
|
||||||
var dbSetup = function(name, version, display_name, size) {
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
DroidDB_openDatabase = function(name, version, display_name, size) {
|
||||||
PhoneGap.execAsync(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
|
PhoneGap.execAsync(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
|
||||||
db_object = new DatabaseShell();
|
var db = new DatabaseShell();
|
||||||
return db_object;
|
return db;
|
||||||
};
|
};
|
||||||
|
|
||||||
PhoneGap.addConstructor(function() {
|
PhoneGap.addConstructor(function() {
|
||||||
if (typeof window.openDatabase == "undefined") {
|
if (typeof window.openDatabase == "undefined") {
|
||||||
navigator.openDatabase = window.openDatabase = dbSetup;
|
navigator.openDatabase = window.openDatabase = DroidDB_openDatabase;
|
||||||
window.droiddb = new DroidDB();
|
window.droiddb = new DroidDB();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -291,15 +291,6 @@ public class DroidGap extends Activity {
|
|||||||
this.addService("Storage", "com.phonegap.Storage");
|
this.addService("Storage", "com.phonegap.Storage");
|
||||||
this.addService("Temperature", "com.phonegap.TempListener");
|
this.addService("Temperature", "com.phonegap.TempListener");
|
||||||
|
|
||||||
// Add in support for storage for Android 1.X devices
|
|
||||||
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
|
|
||||||
System.out.println("Android 1.X device");
|
|
||||||
|
|
||||||
Package pack = this.getClass().getPackage();
|
|
||||||
String appPackage = pack.getName();
|
|
||||||
this.pluginManager.exec("Storage", "setStorage", null, "["+appPackage+"]", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,21 +2,21 @@ package com.phonegap;
|
|||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
import com.phonegap.api.Plugin;
|
import com.phonegap.api.Plugin;
|
||||||
import com.phonegap.api.PluginResult;
|
import com.phonegap.api.PluginResult;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.*;
|
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 Storage extends Plugin {
|
public class Storage extends Plugin {
|
||||||
|
|
||||||
private static final String LOG_TAG = "SQLite Storage:";
|
SQLiteDatabase myDb = null; // Database object
|
||||||
|
String path = null; // Database path
|
||||||
SQLiteDatabase myDb;
|
String dbName = null; // Database name
|
||||||
String path;
|
|
||||||
String txid = "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -37,6 +37,7 @@ public class Storage extends Plugin {
|
|||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// TODO: Do we want to allow a user to do this, since they could get to other app databases?
|
||||||
if (action.equals("setStorage")) {
|
if (action.equals("setStorage")) {
|
||||||
this.setStorage(args.getString(0));
|
this.setStorage(args.getString(0));
|
||||||
}
|
}
|
||||||
@ -68,55 +69,117 @@ public class Storage extends Plugin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up and close database.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
if (this.myDb != null) {
|
||||||
|
this.myDb.close();
|
||||||
|
this.myDb = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// LOCAL METHODS
|
// 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) {
|
public void setStorage(String appPackage) {
|
||||||
path = "/data/data/" + appPackage + "/databases/";
|
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) {
|
public void openDatabase(String db, String version, String display_name, long size) {
|
||||||
if (path != null) {
|
|
||||||
path += db + ".db";
|
// If database is open, then close it
|
||||||
myDb = SQLiteDatabase.openOrCreateDatabase(path, null);
|
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) {
|
public void executeSql(String query, String[] params, String tx_id) {
|
||||||
try {
|
try {
|
||||||
txid = tx_id;
|
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||||
Cursor myCursor = myDb.rawQuery(query, params);
|
this.processResults(myCursor, tx_id);
|
||||||
processResults(myCursor);
|
myCursor.close();
|
||||||
} catch (SQLiteException ex) {
|
}
|
||||||
Log.d(LOG_TAG, ex.getMessage());
|
catch (SQLiteException ex) {
|
||||||
txid = "";
|
ex.printStackTrace();
|
||||||
this.sendJavascript("droiddb.fail(" + ex.getMessage() + "," + txid + ");");
|
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
|
||||||
|
|
||||||
|
// Send error message back to JavaScript
|
||||||
|
this.sendJavascript("droiddb.fail('" + ex.getMessage() + "','" + tx_id + "');");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processResults(Cursor cur) {
|
/**
|
||||||
|
* Process query results.
|
||||||
|
*
|
||||||
|
* @param cur Cursor into query results
|
||||||
|
* @param tx_id Transaction id
|
||||||
|
*/
|
||||||
|
public void processResults(Cursor cur, String tx_id) {
|
||||||
|
|
||||||
|
// If query result has rows
|
||||||
|
if (cur.moveToFirst()) {
|
||||||
String key = "";
|
String key = "";
|
||||||
String value = "";
|
String value = "";
|
||||||
String resultString = "";
|
|
||||||
if (cur.moveToFirst()) {
|
|
||||||
int colCount = cur.getColumnCount();
|
int colCount = cur.getColumnCount();
|
||||||
|
|
||||||
|
// Build up JSON result object for each row
|
||||||
do {
|
do {
|
||||||
resultString = "{";
|
JSONObject result = new JSONObject();
|
||||||
|
try {
|
||||||
for (int i = 0; i < colCount; ++i) {
|
for (int i = 0; i < colCount; ++i) {
|
||||||
key = cur.getColumnName(i);
|
key = cur.getColumnName(i);
|
||||||
value = cur.getString(i);
|
value = cur.getString(i).replace("\"", "\\\""); // must escape " with \" for JavaScript
|
||||||
resultString += " \"" + key + "\" : \"" + value + "\"";
|
result.put(key, value);
|
||||||
if (i != (colCount - 1)) {
|
|
||||||
resultString += ",";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send row back to JavaScript
|
||||||
|
this.sendJavascript("droiddb.addResult('" + result.toString() + "','" + tx_id + "');");
|
||||||
|
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
resultString += "}";
|
|
||||||
this.sendJavascript("droiddb.addResult('" + resultString + "', " + txid + ");");
|
|
||||||
} while (cur.moveToNext());
|
} while (cur.moveToNext());
|
||||||
this.sendJavascript("droiddb.completeQuery(" + txid + ");");
|
|
||||||
txid = "";
|
// Let JavaScript know that there are no more rows
|
||||||
myDb.close();
|
this.sendJavascript("droiddb.completeQuery('" + tx_id + "');");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user