mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 14:16:25 +02:00
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:
parent
37d52863c7
commit
a322953370
@ -46,13 +46,14 @@ type
|
||||
|
||||
TSqliteJNIDataset = class(TCustomSqliteDataset)
|
||||
private
|
||||
FLastInsertRowId: Int64;
|
||||
// Java Classes
|
||||
FSqliteClosableClass, FSQLiteDatabaseClass, FSQLiteCursor: JClass;
|
||||
FSqliteClosableClass, FSQLiteDatabaseClass, FDBCursorClass: JClass;
|
||||
// Java Methods
|
||||
FSqliteClosable_releaseReference: JMethodID;
|
||||
FSqliteDatabase_ExecSQLMethod, FSqliteDatabase_openOrCreateDatabase,
|
||||
FSqliteDatabase_getVersion, FSqliteDatabase_query: JMethodID;
|
||||
FSqliteCursor_getColumnCount: JMethodID;
|
||||
FDBCursor_getColumnCount, FDBCursor_getColumnName, FDBCursor_getType: JMethodID;
|
||||
// Java Objects
|
||||
AndroidDB: jobject; // SQLiteDatabase
|
||||
procedure FindJavaClassesAndMethods;
|
||||
@ -76,6 +77,16 @@ implementation
|
||||
uses
|
||||
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
|
||||
Docs: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
|
||||
@ -199,9 +210,12 @@ end;
|
||||
procedure TSqliteJNIDataset.RetrieveFieldDefs;
|
||||
var
|
||||
vm: Pointer;
|
||||
ColumnStr: String;
|
||||
ColumnName: string;
|
||||
i, ColumnCount, DataSize: Integer;
|
||||
lColumnType: JInt;
|
||||
lJavaString: JString;
|
||||
AType: TFieldType;
|
||||
lNativeString: PChar;
|
||||
//
|
||||
dbCursor: JObject;
|
||||
lParams: array[0..7] of JValue;
|
||||
@ -228,99 +242,97 @@ begin
|
||||
Exit;
|
||||
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);
|
||||
//if FReturnCode <> SQLITE_OK then
|
||||
// DatabaseError(ReturnString, Self);
|
||||
//sqlite3_step(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
|
||||
{ SetLength(FGetSqlStr, ColumnCount);
|
||||
SetLength(FGetSqlStr, ColumnCount);
|
||||
for i := 0 to ColumnCount - 1 do
|
||||
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;
|
||||
ColumnStr := UpperCase(String(sqlite3_column_decltype(vm, i)));
|
||||
if (ColumnStr = 'INTEGER') or (ColumnStr = 'INT') then
|
||||
begin
|
||||
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
|
||||
|
||||
// Before Android 3.0 there is no way to know the type of the field, so just suppose it is string
|
||||
if android_os_Build_VERSION_SDK_INT < 11 then
|
||||
begin
|
||||
AType := ftString;
|
||||
DataSize := StrToIntDef(Trim(ExtractDelimited(2, ColumnStr, ['(', ')'])), DefaultStringSize);
|
||||
end else if Pos('BOOL', ColumnStr) = 1 then
|
||||
DataSize := DefaultStringSize;
|
||||
end
|
||||
else
|
||||
// In Android 3.0 we can use Cursor.getType
|
||||
begin
|
||||
AType := ftBoolean;
|
||||
end else if Pos('AUTOINC', ColumnStr) = 1 then
|
||||
begin
|
||||
AType := ftAutoInc;
|
||||
if FAutoIncFieldNo = -1 then
|
||||
FAutoIncFieldNo := i;
|
||||
end else if (Pos('FLOAT', ColumnStr) = 1) or (Pos('NUMERIC', ColumnStr) = 1) then
|
||||
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
|
||||
// public abstract int getType (int columnIndex) // Added in API level 11
|
||||
lParams[0].i := i;
|
||||
lColumnType := javaEnvRef^^.CallIntMethodA(javaEnvRef, AndroidDB, FDBCursor_getType, @lParams[0]);
|
||||
|
||||
case lColumnType of
|
||||
FIELD_TYPE_BLOB:
|
||||
begin
|
||||
AType := ftString;
|
||||
DataSize := DefaultStringSize;
|
||||
end;
|
||||
DataSize := DefaultStringSize;
|
||||
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 else
|
||||
begin
|
||||
AType := ftString;
|
||||
DataSize := DefaultStringSize;
|
||||
end;
|
||||
FieldDefs.Add(String(sqlite3_column_name(vm, i)), AType, DataSize);
|
||||
|
||||
FieldDefs.Add(ColumnName, AType, DataSize);
|
||||
//Set the pchar2sql function
|
||||
if AType in [ftString, ftMemo] then
|
||||
FGetSqlStr[i] := @Char2SQLStr
|
||||
else
|
||||
FGetSqlStr[i] := @Num2SQLStr;
|
||||
{$ifdef DEBUG_SQLITEDS}
|
||||
WriteLn(' Field[', i, '] Name: ', sqlite3_column_name(vm, i));
|
||||
WriteLn(' Field[', i, '] Type: ', sqlite3_column_decltype(vm, i));
|
||||
DebugLn(' Field[', i, '] Name: ', sqlite3_column_name(vm, i));
|
||||
DebugLn(' Field[', i, '] Type: ', sqlite3_column_decltype(vm, i));
|
||||
{$endif}
|
||||
end;
|
||||
sqlite3_finalize(vm);}
|
||||
//sqlite3_finalize(vm);
|
||||
end;
|
||||
|
||||
function TSqliteJNIDataset.GetRowsAffected: Integer;
|
||||
@ -345,7 +357,7 @@ procedure TSqliteJNIDataset.FindJavaClassesAndMethods;
|
||||
begin
|
||||
FSQLiteDatabaseClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/database/sqlite/SQLiteDatabase');
|
||||
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
|
||||
@ -361,10 +373,24 @@ begin
|
||||
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;');
|
||||
//
|
||||
// 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');
|
||||
// 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;
|
||||
|
||||
procedure TSqliteJNIDataset.BuildLinkedList;
|
||||
@ -427,7 +453,8 @@ end;
|
||||
|
||||
function TSqliteJNIDataset.GetLastInsertRowId: Int64;
|
||||
begin
|
||||
DebugLn('[TSqliteJNIDataset.GetLastInsertRowId]');
|
||||
Result := FLastInsertRowId;
|
||||
DebugLn('[TSqliteJNIDataset.GetLastInsertRowId] Result='+IntToStr(Result));
|
||||
//f/Result := sqlite3_last_insert_rowid(FSqliteHandle);
|
||||
end;
|
||||
|
||||
|
@ -370,6 +370,9 @@ var
|
||||
javaActivityClass: JClass = nil;
|
||||
javaActivityObject: jobject = nil;
|
||||
|
||||
// The SDK Version
|
||||
android_os_Build_VERSION_SDK_INT: jint;
|
||||
|
||||
// Other classes and objects
|
||||
javaAndroidAppActivityClass: JClass = nil;
|
||||
javaJavaLangSystemClass: JClass = nil;
|
||||
@ -377,7 +380,10 @@ var
|
||||
javaAndroidOSVibratorClass: JClass = nil;
|
||||
javaAndroidContentContextClass: JClass = nil;
|
||||
javaJavaLangStringClass: JClass = nil;
|
||||
javaAndroidOSBuildVERSIONClass: JClass = nil;
|
||||
|
||||
// Other fields
|
||||
javaField_VERSION_SDK_INT: JFieldID = nil;
|
||||
// Fields of our Activity
|
||||
// Strings
|
||||
javaField_lcltext: JfieldID=nil;
|
||||
|
@ -535,6 +535,7 @@ begin
|
||||
javaAndroidOSVibratorClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Vibrator');
|
||||
javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
|
||||
javaJavaLangStringClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/String');
|
||||
javaAndroidOSBuildVERSIONClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/os/Build$VERSION');
|
||||
|
||||
// Register Pascal exported calls
|
||||
if javaEnvRef^^.RegisterNatives(javaEnvRef, javaActivityClass, @NativeMethods[0],length(NativeMethods))<0 then
|
||||
@ -606,6 +607,10 @@ begin
|
||||
// Generic methods from Context
|
||||
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');
|
||||
result:=JNI_VERSION_1_4;// 1_6 is another option
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user