LCL-CustomDrawn-Android: Adds code to store the Android API level at startup and advances the SQLite code

git-svn-id: trunk@39429 -
This commit is contained in:
sekelsenmat 2012-12-02 11:00:03 +00:00
parent 37d52863c7
commit a322953370
3 changed files with 115 additions and 77 deletions

View File

@ -46,13 +46,14 @@ type
TSqliteJNIDataset = class(TCustomSqliteDataset) TSqliteJNIDataset = class(TCustomSqliteDataset)
private private
FLastInsertRowId: Int64;
// Java Classes // Java Classes
FSqliteClosableClass, FSQLiteDatabaseClass, FSQLiteCursor: JClass; FSqliteClosableClass, FSQLiteDatabaseClass, FDBCursorClass: JClass;
// Java Methods // Java Methods
FSqliteClosable_releaseReference: JMethodID; FSqliteClosable_releaseReference: JMethodID;
FSqliteDatabase_ExecSQLMethod, FSqliteDatabase_openOrCreateDatabase, FSqliteDatabase_ExecSQLMethod, FSqliteDatabase_openOrCreateDatabase,
FSqliteDatabase_getVersion, FSqliteDatabase_query: JMethodID; FSqliteDatabase_getVersion, FSqliteDatabase_query: JMethodID;
FSqliteCursor_getColumnCount: JMethodID; FDBCursor_getColumnCount, FDBCursor_getColumnName, FDBCursor_getType: JMethodID;
// Java Objects // Java Objects
AndroidDB: jobject; // SQLiteDatabase AndroidDB: jobject; // SQLiteDatabase
procedure FindJavaClassesAndMethods; procedure FindJavaClassesAndMethods;
@ -76,6 +77,16 @@ implementation
uses uses
db, strutils, lclproc; db, strutils, lclproc;
const
//
// from android.database.Cursor
//
FIELD_TYPE_BLOB = 4; // Added in API level 11
FIELD_TYPE_FLOAT = 2; // Added in API level 11
FIELD_TYPE_INTEGER = 1;// Added in API level 11
FIELD_TYPE_NULL = 0; // Added in API level 11
FIELD_TYPE_STRING = 3; // Added in API level 11
{ {
Java code example Java code example
Docs: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html Docs: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
@ -199,9 +210,12 @@ end;
procedure TSqliteJNIDataset.RetrieveFieldDefs; procedure TSqliteJNIDataset.RetrieveFieldDefs;
var var
vm: Pointer; vm: Pointer;
ColumnStr: String; ColumnName: string;
i, ColumnCount, DataSize: Integer; i, ColumnCount, DataSize: Integer;
lColumnType: JInt;
lJavaString: JString;
AType: TFieldType; AType: TFieldType;
lNativeString: PChar;
// //
dbCursor: JObject; dbCursor: JObject;
lParams: array[0..7] of JValue; lParams: array[0..7] of JValue;
@ -228,99 +242,97 @@ begin
Exit; Exit;
end; end;
// int num = c.getColumnCount();
// for (int i = 0; i < num; ++i)
{
String colname = c.getColumnName(i);
}
//FReturnCode := sqlite3_prepare(FSqliteHandle, PChar(FEffectiveSQL), -1, @vm, nil); //FReturnCode := sqlite3_prepare(FSqliteHandle, PChar(FEffectiveSQL), -1, @vm, nil);
//if FReturnCode <> SQLITE_OK then //if FReturnCode <> SQLITE_OK then
// DatabaseError(ReturnString, Self); // DatabaseError(ReturnString, Self);
//sqlite3_step(vm); //sqlite3_step(vm);
//ColumnCount := sqlite3_column_count(vm); //ColumnCount := sqlite3_column_count(vm);
//
// Obtain the number of columns
//
// abstract String getColumnName(int columnIndex)
// int ColumnCount = c.getColumnCount();
ColumnCount := javaEnvRef^^.CallIntMethod(javaEnvRef, AndroidDB, FDBCursor_getColumnCount);
//Prepare the array of pchar2sql functions //Prepare the array of pchar2sql functions
{ SetLength(FGetSqlStr, ColumnCount); SetLength(FGetSqlStr, ColumnCount);
for i := 0 to ColumnCount - 1 do for i := 0 to ColumnCount - 1 do
begin begin
//
// First get the column name
//
// abstract String getColumnName(int columnIndex)
lParams[0].i := i;
lJavaString := javaEnvRef^^.CallObjectMethodA(javaEnvRef, AndroidDB, FDBCursor_getColumnName, @lParams[0]);
lNativeString := javaEnvRef^^.GetStringUTFChars(javaEnvRef, lJavaString, nil);
ColumnName := lNativeString;
javaEnvRef^^.ReleaseStringUTFChars(javaEnvRef, lJavaString, lNativeString);
javaEnvRef^^.DeleteLocalRef(javaEnvRef, lJavaString);
//
// Now obtain the data size and type
//
DataSize := 0; DataSize := 0;
ColumnStr := UpperCase(String(sqlite3_column_decltype(vm, i)));
if (ColumnStr = 'INTEGER') or (ColumnStr = 'INT') then // Before Android 3.0 there is no way to know the type of the field, so just suppose it is string
begin if android_os_Build_VERSION_SDK_INT < 11 then
if AutoIncrementKey and (UpperCase(String(sqlite3_column_name(vm, i))) = UpperCase(PrimaryKey)) then
begin
AType := ftAutoInc;
FAutoIncFieldNo := i;
end
else
AType := ftInteger;
end else if Pos('VARCHAR', ColumnStr) = 1 then
begin begin
AType := ftString; AType := ftString;
DataSize := StrToIntDef(Trim(ExtractDelimited(2, ColumnStr, ['(', ')'])), DefaultStringSize); DataSize := DefaultStringSize;
end else if Pos('BOOL', ColumnStr) = 1 then end
else
// In Android 3.0 we can use Cursor.getType
begin begin
AType := ftBoolean; // public abstract int getType (int columnIndex) // Added in API level 11
end else if Pos('AUTOINC', ColumnStr) = 1 then lParams[0].i := i;
begin lColumnType := javaEnvRef^^.CallIntMethodA(javaEnvRef, AndroidDB, FDBCursor_getType, @lParams[0]);
AType := ftAutoInc;
if FAutoIncFieldNo = -1 then case lColumnType of
FAutoIncFieldNo := i; FIELD_TYPE_BLOB:
end else if (Pos('FLOAT', ColumnStr) = 1) or (Pos('NUMERIC', ColumnStr) = 1) then begin
begin
AType := ftFloat;
end else if (ColumnStr = 'DATETIME') then
begin
AType := ftDateTime;
end else if (ColumnStr = 'DATE') then
begin
AType := ftDate;
end else if (ColumnStr = 'LARGEINT') or (ColumnStr = 'BIGINT') then
begin
AType := ftLargeInt;
end else if (ColumnStr = 'TIME') then
begin
AType := ftTime;
end else if (ColumnStr = 'TEXT') then
begin
AType := ftMemo;
end else if (ColumnStr = 'CURRENCY') then
begin
AType := ftCurrency;
end else if (ColumnStr = 'WORD') then
begin
AType := ftWord;
end else if (ColumnStr = '') then
begin
case sqlite3_column_type(vm, i) of
SQLITE_INTEGER:
AType := ftInteger;
SQLITE_FLOAT:
AType := ftFloat;
else
begin
AType := ftString; AType := ftString;
DataSize := DefaultStringSize; DataSize := DefaultStringSize;
end; end;
FIELD_TYPE_FLOAT:
begin
AType := ftFloat;
end;
FIELD_TYPE_INTEGER:
begin
{if AutoIncrementKey and (UpperCase(String(sqlite3_column_name(vm, i))) = UpperCase(PrimaryKey)) then
begin
AType := ftAutoInc;
FAutoIncFieldNo := i;
end
else}
AType := ftInteger;
end;
FIELD_TYPE_NULL:
begin
AType := ftString;
DataSize := DefaultStringSize;
end;
FIELD_TYPE_STRING:
begin
AType := ftString;
DataSize := DefaultStringSize;
end;
end; end;
end else
begin
AType := ftString;
DataSize := DefaultStringSize;
end; end;
FieldDefs.Add(String(sqlite3_column_name(vm, i)), AType, DataSize);
FieldDefs.Add(ColumnName, AType, DataSize);
//Set the pchar2sql function //Set the pchar2sql function
if AType in [ftString, ftMemo] then if AType in [ftString, ftMemo] then
FGetSqlStr[i] := @Char2SQLStr FGetSqlStr[i] := @Char2SQLStr
else else
FGetSqlStr[i] := @Num2SQLStr; FGetSqlStr[i] := @Num2SQLStr;
{$ifdef DEBUG_SQLITEDS} {$ifdef DEBUG_SQLITEDS}
WriteLn(' Field[', i, '] Name: ', sqlite3_column_name(vm, i)); DebugLn(' Field[', i, '] Name: ', sqlite3_column_name(vm, i));
WriteLn(' Field[', i, '] Type: ', sqlite3_column_decltype(vm, i)); DebugLn(' Field[', i, '] Type: ', sqlite3_column_decltype(vm, i));
{$endif} {$endif}
end; end;
sqlite3_finalize(vm);} //sqlite3_finalize(vm);
end; end;
function TSqliteJNIDataset.GetRowsAffected: Integer; function TSqliteJNIDataset.GetRowsAffected: Integer;
@ -345,7 +357,7 @@ procedure TSqliteJNIDataset.FindJavaClassesAndMethods;
begin begin
FSQLiteDatabaseClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/sqlite/SQLiteDatabase'); FSQLiteDatabaseClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/sqlite/SQLiteDatabase');
FSQLiteClosableClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/sqlite/SQLiteClosable'); FSQLiteClosableClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/sqlite/SQLiteClosable');
FSQLiteCursor := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/Cursor'); FDBCursorClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/Cursor');
// //
// Methods from SqliteDatabase // Methods from SqliteDatabase
@ -361,10 +373,24 @@ begin
FSqliteDatabase_query := javaEnvRef^^.GetMethodID(javaEnvRef, FSQLiteDatabaseClass, 'query', FSqliteDatabase_query := javaEnvRef^^.GetMethodID(javaEnvRef, FSQLiteDatabaseClass, 'query',
'(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;'); '(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;');
// //
// Methods from FSQLiteCursor // Methods from FDBClosable
// //
FSqliteCursor_getColumnCount := javaEnvRef^^.GetMethodID(javaEnvRef, FSQLiteCursor, 'getColumnCount', FSqliteClosable_releaseReference := javaEnvRef^^.GetMethodID(javaEnvRef, FSQLiteClosableClass, 'releaseReference',
'()V');
//
// Methods from FDBCursor
//
FDBCursor_getColumnCount := javaEnvRef^^.GetMethodID(javaEnvRef, FDBCursorClass, 'getColumnCount',
'()I'); '()I');
// abstract String getColumnName(int columnIndex)
FDBCursor_getColumnName := javaEnvRef^^.GetMethodID(javaEnvRef, FDBCursorClass, 'getColumnName',
'(I)Ljava/lang/String;');
// public abstract int getType (int columnIndex) // Added in API level 11
if android_os_Build_VERSION_SDK_INT >= 11 then
begin
FDBCursor_getType := javaEnvRef^^.GetMethodID(javaEnvRef, FDBCursorClass, 'getType',
'(I)I');
end;
end; end;
procedure TSqliteJNIDataset.BuildLinkedList; procedure TSqliteJNIDataset.BuildLinkedList;
@ -427,7 +453,8 @@ end;
function TSqliteJNIDataset.GetLastInsertRowId: Int64; function TSqliteJNIDataset.GetLastInsertRowId: Int64;
begin begin
DebugLn('[TSqliteJNIDataset.GetLastInsertRowId]'); Result := FLastInsertRowId;
DebugLn('[TSqliteJNIDataset.GetLastInsertRowId] Result='+IntToStr(Result));
//f/Result := sqlite3_last_insert_rowid(FSqliteHandle); //f/Result := sqlite3_last_insert_rowid(FSqliteHandle);
end; end;

View File

@ -370,6 +370,9 @@ var
javaActivityClass: JClass = nil; javaActivityClass: JClass = nil;
javaActivityObject: jobject = nil; javaActivityObject: jobject = nil;
// The SDK Version
android_os_Build_VERSION_SDK_INT: jint;
// Other classes and objects // Other classes and objects
javaAndroidAppActivityClass: JClass = nil; javaAndroidAppActivityClass: JClass = nil;
javaJavaLangSystemClass: JClass = nil; javaJavaLangSystemClass: JClass = nil;
@ -377,7 +380,10 @@ var
javaAndroidOSVibratorClass: JClass = nil; javaAndroidOSVibratorClass: JClass = nil;
javaAndroidContentContextClass: JClass = nil; javaAndroidContentContextClass: JClass = nil;
javaJavaLangStringClass: JClass = nil; javaJavaLangStringClass: JClass = nil;
javaAndroidOSBuildVERSIONClass: JClass = nil;
// Other fields
javaField_VERSION_SDK_INT: JFieldID = nil;
// Fields of our Activity // Fields of our Activity
// Strings // Strings
javaField_lcltext: JfieldID=nil; javaField_lcltext: JfieldID=nil;

View File

@ -535,6 +535,7 @@ begin
javaAndroidOSVibratorClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Vibrator'); javaAndroidOSVibratorClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Vibrator');
javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context'); javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
javaJavaLangStringClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/String'); javaJavaLangStringClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/String');
javaAndroidOSBuildVERSIONClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/os/Build$VERSION');
// Register Pascal exported calls // Register Pascal exported calls
if javaEnvRef^^.RegisterNatives(javaEnvRef, javaActivityClass, @NativeMethods[0],length(NativeMethods))<0 then if javaEnvRef^^.RegisterNatives(javaEnvRef, javaActivityClass, @NativeMethods[0],length(NativeMethods))<0 then
@ -606,6 +607,10 @@ begin
// Generic methods from Context // Generic methods from Context
javaMethod_getSystemService := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getSystemService', '(Ljava/lang/String;)Ljava/lang/Object;'); javaMethod_getSystemService := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getSystemService', '(Ljava/lang/String;)Ljava/lang/Object;');
// Read the SDK Version and store it
javaField_VERSION_SDK_INT := javaEnvRef^^.GetStaticFieldID(javaEnvRef, javaAndroidOSBuildVERSIONClass, 'SDK_INT', 'I');
android_os_Build_VERSION_SDK_INT := javaEnvRef^^.GetStaticIntField(javaEnvRef, javaAndroidOSBuildVERSIONClass, javaField_VERSION_SDK_INT);
__android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad finished'); __android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad finished');
result:=JNI_VERSION_1_4;// 1_6 is another option result:=JNI_VERSION_1_4;// 1_6 is another option
end; end;