mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-21 07:02:34 +02:00
1329 lines
52 KiB
PHP
1329 lines
52 KiB
PHP
{%MainUnit customdrawnint.pas}
|
|
|
|
{******************************************************************************
|
|
customdrawnobject_win.inc
|
|
******************************************************************************
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
|
|
const
|
|
// Shared Mouse / Key constants
|
|
ACTION_DOWN = 0;
|
|
ACTION_UP = 1;
|
|
|
|
// Touch constants
|
|
ACTION_MOVE = 2;
|
|
|
|
// Constants from android/view/KeyEvent up to level 8
|
|
ACTION_MULTIPLE = 2;
|
|
// Keys are in KeyCodes.pas
|
|
|
|
// from android.view.KeyCharacterMap
|
|
COMBINING_ACCENT = $80000000;
|
|
|
|
const
|
|
javaConstant_CLIPBOARD_SERVICE = 'clipboard';
|
|
javaConstant_Intent_ACTION_VIEW = 'android.intent.action.VIEW';
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnTouch(env:PJNIEnv;this:jobject; x, y: single; action: jint): jint; cdecl;
|
|
var
|
|
lCurForm: TCDNonNativeForm;
|
|
lTarget: TWinControl;
|
|
lEventPos: TPoint;
|
|
begin
|
|
{$ifdef VerboseCDEvents}
|
|
__android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(Format('LCLOnTouch called x=%f y=%f action=%d', [x, y, action])));
|
|
{$endif}
|
|
eventResult := 0;
|
|
|
|
lCurForm := GetCurrentForm();
|
|
|
|
case action of
|
|
ACTION_DOWN:
|
|
begin
|
|
CallbackMouseDown(lCurForm, Round(X), Round(Y), mbLeft, []);
|
|
end;
|
|
ACTION_UP:
|
|
begin
|
|
CallbackMouseUp(lCurForm, Round(X), Round(Y), mbLeft, []);
|
|
end;
|
|
ACTION_MOVE: CallbackMouseMove(lCurForm, Round(X), Round(Y), []);
|
|
end;
|
|
|
|
// This sends messages like Invalidate requests
|
|
Result := eventResult;
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap(
|
|
env:PJNIEnv;this:jobject; width, height: jint; abitmap: jobject): jint; cdecl;
|
|
var
|
|
pixels: PCardinal;
|
|
lCurForm: TCDNonNativeForm;
|
|
|
|
{$IFDEF VerboseCDPaintProfiler}
|
|
lTimeStart: TDateTime;
|
|
{$ENDIF}
|
|
begin
|
|
Result := 0;
|
|
AndroidBitmap_lockPixels(env, abitmap, @pixels);
|
|
|
|
lCurForm := GetCurrentForm();
|
|
if lCurForm <> nil then
|
|
begin
|
|
{$IFDEF VerboseCDPaintProfiler}
|
|
//lTimeStart := NowUTC();
|
|
{$ENDIF}
|
|
{$IFDEF VerboseCDPaintEvent}
|
|
DebugLn(Format('[Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap] lCurForm:TCDNonNativeForm=%x', [PtrInt(lCurForm)]));
|
|
{$ENDIF}
|
|
|
|
// Prepare the non-native image and canvas
|
|
UpdateControlLazImageAndCanvas(lCurForm.Image, lCurForm.Canvas, Width, Height, clfRGBA32, pixels, True, False);
|
|
|
|
RenderForm(lCurForm.Image, lCurForm.Canvas, lCurForm.LCLForm);
|
|
end;
|
|
|
|
// Now returns the bitmap buffer to LCLActivity so that it can render it
|
|
AndroidBitmap_unlockPixels(env, abitmap);
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnCreate(
|
|
env:PJNIEnv; this:jobject; alclactivity: jobject): jint; cdecl;
|
|
begin
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', 'LCLOnCreate called by LCLActivity.onCreate');
|
|
Result := 0;
|
|
javaActivityObject := alclactivity;
|
|
Screen.UpdateScreen(); // Any values read before LCLOnCreate are wrong
|
|
// Update the font size
|
|
CDWidgetset.DefaultFontAndroidSize := Round(16 * (Screen.PixelsPerInch / 125));
|
|
// Now inform the application
|
|
if Assigned(CDWidgetset.ActivityOnCreate) then CDWidgetset.ActivityOnCreate()
|
|
else Application.Run; // <- Support for older code up to 21 dezember 2011
|
|
end;
|
|
|
|
// This one is for all simple dialogs: MessageBox, PromptUser (MessageDlg) and AskUser
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnMessageBoxFinished(
|
|
env:PJNIEnv; this:jobject; AResult, ADialogType: jint): jint; cdecl;
|
|
begin
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('LCLOnMessageBoxFinished called AResult=%d ADialogType=%d',
|
|
[AResult, ADialogType])));
|
|
Result := 0;
|
|
case ADialogType of
|
|
0: if Assigned(Application.OnMessageDialogFinished) then
|
|
Application.OnMessageDialogFinished(Application, AResult);
|
|
1: if Assigned(OnShowSelectItemDialogResult) then OnShowSelectItemDialogResult(AResult);
|
|
end;
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnKey(
|
|
env:PJNIEnv; this:jobject; AKind: jint; AKeyCode: jint;
|
|
AEvent: jobject; AChar: jint): jint; cdecl;
|
|
var
|
|
lCurForm: TCDNonNativeForm;
|
|
lTarget, lFocusedControl: TWinControl;
|
|
lKey: Word;
|
|
lCombinedAChar: jint;
|
|
lChar: Cardinal;
|
|
AUTF8Text: string;
|
|
AUTF8Char: TUTF8Char;
|
|
lForm: TCDNonNativeForm;
|
|
begin
|
|
lChar := Cardinal(AChar);
|
|
{$ifdef VerboseCDEvents}
|
|
__android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(
|
|
Format('[LCLOnKey] called AKind=%d AKeyCode=%x AChar=%s', [AKind, AKeyCode, UnicodeToUTF8(lChar)])));
|
|
{$endif}
|
|
eventResult := 0;
|
|
|
|
lCurForm := GetCurrentForm();
|
|
lKey := CDWidgetset.AndroidKeyCodeToLCLKeyCode(AKeyCode);
|
|
|
|
case AKind of
|
|
ACTION_DOWN: CallbackKeyDown(lCurForm, lKey);
|
|
-1: // This indicates a key char event
|
|
begin
|
|
AUTF8Text := UnicodeToUTF8(lChar);
|
|
AUTF8Char := AUTF8Text;
|
|
CallbackKeyChar(lCurForm, lKey, AUTF8Char);
|
|
end;
|
|
ACTION_UP:
|
|
begin
|
|
CallbackKeyUp(lCurForm, lKey);
|
|
(* if (lChar <> 0) and ((COMBINING_ACCENT and lChar) = 0) then
|
|
begin
|
|
if CDWidgetset.CombiningAccent <> 0 then
|
|
begin
|
|
// Prepare the input
|
|
lJavaString :=javaEnvRef^^.NewStringUTF(javaEnvRef, Str);
|
|
javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, JavaField_lcltext, lJavaString);
|
|
javaEnvRef^^.SetIntField(javaEnvRef, javaActivityObject, javaField_lcltextsize, lFontSize);
|
|
|
|
// Call the method
|
|
javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoGetTextBounds);
|
|
|
|
// Read the output
|
|
Size.cx := javaEnvRef^^.GetIntField(javaEnvRef, javaActivityObject, javaField_lclwidth);
|
|
Size.cy := javaEnvRef^^.GetIntField(javaEnvRef, javaActivityObject, javaField_lclheight);
|
|
//
|
|
lCombinedAChar := getDeadChar();
|
|
end;
|
|
AUTF8Text := UnicodeToUTF8(lChar);
|
|
AUTF8Char := AUTF8Text;
|
|
CallbackKeyChar(lCurForm, lKey, AUTF8Char);
|
|
CDWidgetset.CombiningAccent := 0;
|
|
end
|
|
else if (lChar <> 0) and ((COMBINING_ACCENT and lChar) <> 0) then
|
|
begin
|
|
CDWidgetset.CombiningAccent := lChar;
|
|
end;*)
|
|
|
|
// Handle the Back hardware key
|
|
if AKeyCode = AKEYCODE_BACK then
|
|
begin
|
|
//DebugLn(Format('CallbackKeyUp D lForm=%x', [PtrInt(lForm)]));
|
|
// The back hardware key hides the current form and shows the one bellow it
|
|
// except if the currently focused control is a text editor, in which case
|
|
// it will take focus out of the text editor
|
|
lForm := lCurForm;
|
|
lFocusedControl := lForm.GetFocusedControl();
|
|
if (lFocusedControl <> nil) and (csRequiresKeyboardInput in lFocusedControl.ControlStyle) then
|
|
begin
|
|
//DebugLn('[LCLOnKey] Sending focus to the form');
|
|
CDWidgetset.CDSetFocusToControl(lForm.LCLForm, nil);
|
|
end
|
|
// If this is the main form, then go back to desktop
|
|
else if (Application.MainForm <> nil) and (lForm = TCDForm(Application.MainForm.Handle)) then
|
|
begin
|
|
//DebugLn('[LCLOnKey] Back key is going to hide the application');
|
|
eventResult := eventResult or 2;
|
|
end
|
|
// for other forms, hide them
|
|
else
|
|
begin
|
|
//DebugLn('[LCLOnKey] Hiding the form');
|
|
HideForm(lForm);
|
|
end;
|
|
end;
|
|
end;
|
|
//ACTION_MULTIPLE:
|
|
end;
|
|
|
|
// This sends messages like Invalidate requests
|
|
Result := eventResult;
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnTimer(
|
|
env:PJNIEnv; this:jobject; ATimer: jobject): jint; cdecl;
|
|
var
|
|
lTimer: TCDTimer;
|
|
begin
|
|
{$ifdef VerboseCDEvents}
|
|
__android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(
|
|
Format('LCLOnTimer called ATimer=%x', [PtrInt(ATimer)])));
|
|
{$endif}
|
|
eventResult := 0;
|
|
|
|
lTimer := FindTimerWithNativeHandle(PtrInt(ATimer));
|
|
|
|
if lTimer <> nil then lTimer.TimerFunc()
|
|
else DebugLn('[LCLOnTimer] OnTimer message sent to unknown timer!');
|
|
|
|
// This sends messages like Invalidate requests
|
|
Result := eventResult;
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnConfigurationChanged(
|
|
env:PJNIEnv; this:jobject; ANewDPI, ANewWidth: jint): jint; cdecl;
|
|
var
|
|
lForm: TCDNonNativeForm;
|
|
lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth: Integer;
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to GetFormCount()-1 do
|
|
begin
|
|
lForm := GetForm(i);
|
|
|
|
if lForm.LayoutAutoAdjusted then lOldDPI := Screen.PixelsPerInch
|
|
else lOldDPI := lForm.LCLForm.DesignTimeDPI;
|
|
lNewDPI := ANewDPI;
|
|
lOldFormWidth := lForm.LCLForm.Width;
|
|
lNewFormWidth := ANewWidth;
|
|
DebugLn(Format('[LCLOnConfigurationChanged] i=%d lOldDPI=%d lNewDPI=%d lOldFormWidth=%d lNewFormWidth=%d',
|
|
[i, lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth]));
|
|
lForm.LCLForm.AutoAdjustLayout(lapAutoAdjustWithoutHorizontalScrolling,
|
|
lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth);
|
|
end;
|
|
|
|
// Update the font size
|
|
CDWidgetset.DefaultFontAndroidSize := Round(16 * (ANewDPI / 125));
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnSensorChanged(
|
|
env:PJNIEnv; this:jobject; ASensorKind: jint; AValues: JDoubleArray): jint; cdecl;
|
|
var
|
|
arraydata: PDouble;
|
|
arraylen: jsize;
|
|
lIsCopy: jboolean;
|
|
lSensorDataInt: Integer;
|
|
lMessagingStatus: TLazMessagingStatus;
|
|
lUnixTimeStamp: Int64;
|
|
begin
|
|
Result := 0;
|
|
|
|
if (javaEnvRef = nil) then Exit;
|
|
|
|
// Get the elements and length
|
|
lIsCopy := 0;
|
|
arraylen := javaEnvRef^^.GetArrayLength(javaEnvRef, AValues);
|
|
arraydata := javaEnvRef^^.GetDoubleArrayElements(javaEnvRef, AValues, lIsCopy);
|
|
|
|
// Send the data to the LCL
|
|
case ASensorKind of
|
|
-11: // Defined by ourselves for Messaging Status
|
|
begin
|
|
lSensorDataInt := Round(arraydata[0]);
|
|
case lSensorDataInt of
|
|
1: lMessagingStatus := mssSentSuccessfully;
|
|
2: lMessagingStatus := mssSendingGeneralError;
|
|
3: lMessagingStatus := mssNoService;
|
|
5: lMessagingStatus := mssRadioOff;
|
|
10:lMessagingStatus := mssReceivedSuccessfully;
|
|
11:lMessagingStatus := mssReceivingGeneralError;
|
|
else
|
|
lMessagingStatus := mssSendingGeneralError;
|
|
end;
|
|
|
|
if Assigned(Messaging.OnMessagingStatus) then
|
|
Messaging.OnMessagingStatus(nil, lMessagingStatus);
|
|
end;
|
|
-10: // Defined by ourselves for PositionInfo
|
|
begin
|
|
PositionInfo.latitude := arraydata[0];
|
|
PositionInfo.longitude := arraydata[1];
|
|
PositionInfo.altitude := arraydata[2];
|
|
PositionInfo.accuracy := arraydata[3];
|
|
PositionInfo.altitudeAccuracy := PositionInfo.accuracy;
|
|
PositionInfo.speed := arraydata[4];
|
|
lUnixTimeStamp := Round(arraydata[5]);
|
|
PositionInfo.timeStamp := UnixToDateTime(lUnixTimeStamp);
|
|
|
|
if Assigned(PositionInfo.OnPositionRetrieved) then
|
|
PositionInfo.OnPositionRetrieved(PositionInfo);
|
|
end;
|
|
1: // ACCELEROMETER
|
|
begin
|
|
Accelerometer.xaxis := -1*arraydata[0];
|
|
Accelerometer.yaxis := -1*arraydata[1];
|
|
Accelerometer.zaxis := -1*arraydata[2];
|
|
if Assigned(Accelerometer.OnSensorChanged) then
|
|
Accelerometer.OnSensorChanged(Accelerometer);
|
|
end;
|
|
end;
|
|
|
|
// Don't forget to release it
|
|
javaEnvRef^^.ReleaseDoubleArrayElements(javaEnvRef, AValues, arraydata, 0);
|
|
|
|
// This sends messages like Invalidate requests
|
|
Result := eventResult;
|
|
end;
|
|
|
|
function Java_com_pascal_lclproject_LCLActivity_LCLOnMenuAction(
|
|
env:PJNIEnv; this:jobject; kind, itemIndex: jint): jint; cdecl;
|
|
var
|
|
javaField_lclmenu_captions: jfieldid;
|
|
javaObject_lclmenu_captions: jobjectarray;
|
|
lJavaString: jstring;
|
|
lCurrentForm: TCDNonNativeForm;
|
|
lMenu: TMainMenu;
|
|
StrPas: string;
|
|
Str: PChar;
|
|
lMenuItem: TMenuItem;
|
|
i, CurIndex, NumMenuItems: Integer;
|
|
begin
|
|
Result := 0;
|
|
|
|
// Very strangely in the emulator it crashes if we don't refresh the Activity class here
|
|
javaActivityClass := javaEnvRef^^.FindClass(javaEnvRef, PChar(CDWidgetset.ActivityClassName));
|
|
|
|
//{$ifdef VerboseCDEvents}
|
|
DebugLn(Format('LCLOnMenuAction called kind=%d itemIndex=%d', [kind, itemIndex]));
|
|
//{$endif}
|
|
|
|
if (javaEnvRef = nil) then Exit;
|
|
|
|
lCurrentForm := GetCurrentForm();
|
|
if lCurrentForm = nil then Exit;
|
|
lMenu := lCurrentForm.LCLForm.Menu;
|
|
if lMenu = nil then Exit;
|
|
|
|
// kind=0 means that we should create the menu items list
|
|
if kind = 0 then
|
|
begin
|
|
// First calculate the number of menu items
|
|
NumMenuItems := 0;
|
|
for i := 0 to lMenu.Items.Count-1 do
|
|
begin
|
|
lMenuItem := lMenu.Items[i];
|
|
// Various things might make a menu item invalid and therefore not part of the list
|
|
if not lMenuItem.Visible then Continue;
|
|
if lMenuItem.Caption = '-' then Continue;
|
|
Inc(NumMenuItems);
|
|
end;
|
|
|
|
// Now fill the items
|
|
javaField_lclmenu_captions := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmenu_captions', '[Ljava/lang/String;');
|
|
// javaObject_lclmenu_captions := javaEnvRef^^.GetObjectField(javaEnvRef, javaActivityClass, javaField_lclmenu_captions);
|
|
javaObject_lclmenu_captions := javaEnvRef^^.NewObjectArray(javaEnvRef, NumMenuItems,
|
|
javaJavaLangStringClass, javaEnvRef^^.NewStringUTF(javaEnvRef, ''));
|
|
// DebugLn(Format('LCLOnMenuAction lclmenu_captions field=%x object=%x', [PtrUInt(javaField_lclmenu_captions), PtrUInt(javaObject_lclmenu_captions)]));
|
|
|
|
CurIndex := 0;
|
|
StrPas := '';
|
|
for i := 0 to lMenu.Items.Count-1 do
|
|
begin
|
|
DebugLn(Format('LCLOnMenuAction item=%d', [i]));
|
|
lMenuItem := lMenu.Items[i];
|
|
// Various things might make a menu item invalid and therefore not part of the list
|
|
if not lMenuItem.Visible then Continue;
|
|
if lMenuItem.Caption = '-' then Continue;
|
|
|
|
StrPas := lMenuItem.Caption;
|
|
Str := PChar(StrPas);
|
|
lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, Str);
|
|
DebugLn(Format('LCLOnMenuAction lJavaString=%x Str=%s javaObject_lclmenu_captions=%x', [PtrUInt(lJavaString), StrPas, PtrUInt(javaObject_lclmenu_captions)]));
|
|
javaEnvRef^^.SetObjectArrayElement(javaEnvRef, javaObject_lclmenu_captions, CurIndex, lJavaString);
|
|
javaEnvRef^^.DeleteLocalRef(javaEnvRef, javaObject_lclmenu_captions);
|
|
|
|
Inc(CurIndex);
|
|
|
|
if CurIndex >= NumMenuItems then Break;
|
|
end;
|
|
|
|
javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, javaField_lclmenu_captions, javaObject_lclmenu_captions);
|
|
end
|
|
// kind=1 means a button click event
|
|
else
|
|
begin
|
|
// Searched for the clicked item
|
|
CurIndex := 0;
|
|
for i := 0 to lMenu.Items.Count-1 do
|
|
begin
|
|
lMenuItem := lMenu.Items[i];
|
|
// Various things might make a menu item invalid and therefore not part of the list
|
|
if not lMenuItem.Visible then Continue;
|
|
if lMenuItem.Caption = '-' then Continue;
|
|
|
|
if itemIndex = CurIndex then Break;
|
|
|
|
Inc(CurIndex);
|
|
end;
|
|
|
|
lMenuItem.Click();
|
|
end;
|
|
|
|
// This sends messages like Invalidate requests
|
|
Result := eventResult;
|
|
DebugLn('Fim');
|
|
end;
|
|
|
|
const NativeMethods: array[0..8] of JNINativeMethod=
|
|
((name:'LCLDrawToBitmap';
|
|
signature:'(IILandroid/graphics/Bitmap;)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap;),
|
|
(name:'LCLOnTouch';
|
|
signature:'(FFI)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnTouch;),
|
|
(name:'LCLOnCreate';
|
|
signature:'(Landroid/app/Activity;)I'; // Don't use a name which includes the package name like com/pascal/lcltest/LCLActivity;
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnCreate;),
|
|
(name:'LCLOnMessageBoxFinished';
|
|
signature:'(II)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnMessageBoxFinished;),
|
|
(name:'LCLOnKey';
|
|
signature:'(IILandroid/view/KeyEvent;I)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnKey;),
|
|
(name:'LCLOnTimer';
|
|
signature:'(Ljava/lang/Runnable;)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnTimer;),
|
|
(name:'LCLOnConfigurationChanged';
|
|
signature:'(II)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnConfigurationChanged;),
|
|
(name:'LCLOnSensorChanged';
|
|
signature:'(I[D)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnSensorChanged;),
|
|
(name:'LCLOnMenuAction';
|
|
signature:'(II)I';
|
|
fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnMenuAction;)
|
|
);
|
|
|
|
function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint; cdecl;
|
|
begin
|
|
javaVMRef := vm;
|
|
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad called');
|
|
{ __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm=%x', [PtrInt(vm)])));
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^=%x', [PtrInt(vm^)])));
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^^.reserved0=%x', [PtrInt(vm^^.reserved0)])));
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^^.GetEnv=%x', [PtrInt(Pointer(@vm^^.GetEnv))]))); }
|
|
{
|
|
vm^^.GetEnv crashes HTC Wildfire, Alcatel and the Emulator if you don't build your project with -CpARMV6
|
|
see: http://groups.google.com/group/android-ndk/browse_thread/thread/ba542483f062a828/ef9077617794e0f5
|
|
}
|
|
if vm^^.GetEnv(vm,@javaEnvRef,JNI_VERSION_1_4)<>JNI_OK then
|
|
begin
|
|
__android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'curVM^.GetEnv failed');
|
|
Exit(JNI_ERR);
|
|
end;
|
|
|
|
// Find our activity class
|
|
__android_log_write(ANDROID_LOG_INFO,'lclapp','Reading our Activity Class');
|
|
javaActivityClass := javaEnvRef^^.FindClass(javaEnvRef, PChar(CDWidgetset.ActivityClassName));
|
|
if not assigned(javaActivityClass) then
|
|
begin
|
|
__android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.FindClass failed');
|
|
Exit(JNI_ERR);
|
|
end;
|
|
// Now other classes
|
|
javaAndroidAppActivityClass := javaEnvRef^^.FindClass(javaEnvRef,'android/app/Activity');
|
|
javaJavaLangSystemClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/System');
|
|
javaAndroidOSBuildClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Build');
|
|
javaAndroidOSVibratorClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Vibrator');
|
|
javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
|
|
javaJavaLangStringClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/String');
|
|
|
|
// Register Pascal exported calls
|
|
if javaEnvRef^^.RegisterNatives(javaEnvRef, javaActivityClass, @NativeMethods[0],length(NativeMethods))<0 then
|
|
begin
|
|
__android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.RegisterNatives failed');
|
|
// Exit(JNI_ERR); Don't exit if exporting the native method fails because it works without this too
|
|
end;
|
|
|
|
// Read all field IDs
|
|
JavaField_lcltext := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltext', 'Ljava/lang/String;');
|
|
JavaField_lcltitle := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltitle', 'Ljava/lang/String;');
|
|
JavaField_lclbutton1str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton1str', 'Ljava/lang/String;');
|
|
JavaField_lclbutton2str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton2str', 'Ljava/lang/String;');
|
|
JavaField_lclbutton3str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton3str', 'Ljava/lang/String;');
|
|
//
|
|
JavaField_lclwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclwidth', 'I');
|
|
JavaField_lclheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclheight', 'I');
|
|
JavaField_lclbutton1 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton1', 'I');
|
|
JavaField_lclbutton2 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton2', 'I');
|
|
JavaField_lclbutton3 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton3', 'I');
|
|
JavaField_lclbitmap := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbitmap', 'Landroid/graphics/Bitmap;');
|
|
JavaField_lcltextsize := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextsize', 'I');
|
|
// Text metrics
|
|
javaField_lcltextascent := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextascent', 'I');
|
|
javaField_lcltextbottom := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextbottom', 'I');
|
|
javaField_lcltextdescent := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextdescent', 'I');
|
|
javaField_lcltextleading := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextleading', 'I');
|
|
javaField_lcltexttop := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltexttop', 'I');
|
|
javaField_lclmaxwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmaxwidth', 'I');
|
|
javaField_lclmaxcount := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmaxcount', 'I');
|
|
javaField_lclpartialwidths := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclpartialwidths', '[F');
|
|
// Timer
|
|
javaField_lcltimerinterval := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltimerinterval', 'I');
|
|
javaField_lcltimerid := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltimerid', 'Ljava/lang/Runnable;');
|
|
// Screen Metrics
|
|
javaField_lclxdpi := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclxdpi', 'I');
|
|
javaField_lclydpi := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclydpi', 'I');
|
|
javaField_lclformwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclformwidth', 'I');
|
|
javaField_lclformheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclformheight', 'I');
|
|
javaField_lclscreenwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclscreenwidth', 'I');
|
|
javaField_lclscreenheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclscreenheight', 'I');
|
|
// For LazDeviceAPIs
|
|
javaField_lcldestination := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcldestination', 'Ljava/lang/String;');
|
|
javaField_lclkind := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclkind', 'I');
|
|
//
|
|
if not assigned(JavaField_lcltext) then
|
|
begin
|
|
__android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.GetFieldID failed for lcltext');
|
|
Exit(JNI_ERR);
|
|
end;
|
|
|
|
// Read all method IDs
|
|
javaMethod_LCLDoGetTextBounds := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoGetTextBounds', '()V');
|
|
javaMethod_LCLDoGetTextPartialWidths := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoGetTextPartialWidths', '()V');
|
|
javaMethod_LCLDoDrawText := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoDrawText', '(I)V');
|
|
javaMethod_LCLDoShowMessageBox := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoShowMessageBox', '()V');
|
|
javaMethod_LCLDoCreateTimer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoCreateTimer', '()V');
|
|
javaMethod_LCLDoDestroyTimer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoDestroyTimer', '()V');
|
|
javaMethod_LCLDoHideVirtualKeyboard := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoHideVirtualKeyboard', '()V');
|
|
javaMethod_LCLDoShowVirtualKeyboard := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoShowVirtualKeyboard', '()V');
|
|
javaMethod_LCLDoStartReadingAccelerometer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoStartReadingAccelerometer', '()V');
|
|
javaMethod_LCLDoStopReadingAccelerometer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoStopReadingAccelerometer', '()V');
|
|
javaMethod_LCLDoSendMessage := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoSendMessage', '()V');
|
|
javaMethod_LCLDoRequestPositionInfo := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoRequestPositionInfo', '()V');
|
|
// Methods from android.app.Activity
|
|
javaMethod_Activity_finish := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidAppActivityClass, 'finish', '()V');
|
|
// Methods from java.lang.System
|
|
javaMethod_System_exit := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaJavaLangSystemClass, 'exit', '(I)V');
|
|
// Generic methods from Context
|
|
javaMethod_getSystemService := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getSystemService', '(Ljava/lang/String;)Ljava/lang/Object;');
|
|
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad finished');
|
|
result:=JNI_VERSION_1_4;// 1_6 is another option
|
|
end;
|
|
|
|
procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer); cdecl;
|
|
begin
|
|
end;
|
|
|
|
{$IFnDEF WithOldDebugln}
|
|
procedure TCDWidgetSet.AndroidDebugLn(ASender: TObject; AStr: string; var AHandled: Boolean;
|
|
Target: TLazLoggerWriteTarget; Data: Pointer);
|
|
begin
|
|
AHandled := Target in [lwtStdOut, lwtStdErr];
|
|
if not AHandled then exit;
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(AccumulatedStr+AStr));
|
|
AccumulatedStr := '';
|
|
end;
|
|
{$ELSE}
|
|
procedure TCDWidgetSet.AndroidDebugLn(AStr: string);
|
|
begin
|
|
__android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(AccumulatedStr+AStr));
|
|
AccumulatedStr := '';
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TCDWidgetSet.AndroidKeyCodeToLCLKeyCode(AAndroidKeyCode: Integer): Word;
|
|
var
|
|
lExtendedKeysSupport: Boolean;
|
|
begin
|
|
lExtendedKeysSupport := Application.ExtendedKeysSupport;
|
|
|
|
case AAndroidKeyCode of
|
|
// First keys which are defined in NDK too
|
|
{ KEYCODE_SOFT_LEFT = 1;
|
|
KEYCODE_SOFT_RIGHT = 2;
|
|
KEYCODE_HOME = 3;}
|
|
KEYCODE_BACK: Result := VK_ESCAPE;
|
|
KEYCODE_CALL: Result := VK_LCL_CALL;
|
|
KEYCODE_ENDCALL: Result := VK_LCL_ENDCALL;
|
|
KEYCODE_0: Result := VK_0;
|
|
KEYCODE_1: Result := VK_1;
|
|
KEYCODE_2: Result := VK_2;
|
|
KEYCODE_3: Result := VK_3;
|
|
KEYCODE_4: Result := VK_4;
|
|
KEYCODE_5: Result := VK_5;
|
|
KEYCODE_6: Result := VK_6;
|
|
KEYCODE_7: Result := VK_7;
|
|
KEYCODE_8: Result := VK_8;
|
|
KEYCODE_9: Result := VK_9;
|
|
{ KEYCODE_STAR = 17;
|
|
KEYCODE_POUND = 18;}
|
|
KEYCODE_DPAD_UP: Result := VK_UP;
|
|
KEYCODE_DPAD_DOWN: Result := VK_DOWN;
|
|
KEYCODE_DPAD_LEFT: Result := VK_LEFT;
|
|
KEYCODE_DPAD_RIGHT: Result := VK_RIGHT;
|
|
KEYCODE_DPAD_CENTER: Result := VK_RETURN;
|
|
KEYCODE_VOLUME_UP: Result := VK_VOLUME_UP;
|
|
KEYCODE_VOLUME_DOWN: Result := VK_VOLUME_DOWN;
|
|
KEYCODE_POWER: Result := VK_LCL_POWER;
|
|
// KEYCODE_CAMERA = 27;}
|
|
KEYCODE_CLEAR: Result := VK_CLEAR;
|
|
KEYCODE_A: Result := VK_A;
|
|
KEYCODE_B: Result := VK_B;
|
|
KEYCODE_C: Result := VK_C;
|
|
KEYCODE_D: Result := VK_D;
|
|
KEYCODE_E: Result := VK_E;
|
|
KEYCODE_F: Result := VK_F;
|
|
KEYCODE_G: Result := VK_G;
|
|
KEYCODE_H: Result := VK_H;
|
|
KEYCODE_I: Result := VK_I;
|
|
KEYCODE_J: Result := VK_J;
|
|
KEYCODE_K: Result := VK_K;
|
|
KEYCODE_L: Result := VK_L;
|
|
KEYCODE_M: Result := VK_M;
|
|
KEYCODE_N: Result := VK_N;
|
|
KEYCODE_O: Result := VK_O;
|
|
KEYCODE_P: Result := VK_P;
|
|
KEYCODE_Q: Result := VK_Q;
|
|
KEYCODE_R: Result := VK_R;
|
|
KEYCODE_S: Result := VK_S;
|
|
KEYCODE_T: Result := VK_T;
|
|
KEYCODE_U: Result := VK_U;
|
|
KEYCODE_V: Result := VK_V;
|
|
KEYCODE_W: Result := VK_W;
|
|
KEYCODE_X: Result := VK_X;
|
|
KEYCODE_Y: Result := VK_Y;
|
|
KEYCODE_Z: Result := VK_Z;
|
|
KEYCODE_COMMA: Result := VK_LCL_COMMA;
|
|
KEYCODE_PERIOD: Result := VK_LCL_POINT;
|
|
KEYCODE_ALT_LEFT: if lExtendedKeysSupport then Result := VK_LMENU else Result := VK_MENU;
|
|
KEYCODE_ALT_RIGHT: if lExtendedKeysSupport then Result := VK_RMENU else Result := VK_MENU;
|
|
KEYCODE_SHIFT_LEFT: if lExtendedKeysSupport then Result := VK_LSHIFT else Result := VK_SHIFT;
|
|
KEYCODE_SHIFT_RIGHT:if lExtendedKeysSupport then Result := VK_RSHIFT else Result := VK_SHIFT;
|
|
KEYCODE_TAB: Result := VK_TAB;
|
|
KEYCODE_SPACE: Result := VK_SPACE;
|
|
{ KEYCODE_SYM = 63;
|
|
KEYCODE_EXPLORER = 64;
|
|
KEYCODE_ENVELOPE = 65;}
|
|
KEYCODE_ENTER: Result := VK_RETURN;
|
|
KEYCODE_DEL: Result := VK_BACK; // The "Backspace" key
|
|
KEYCODE_GRAVE: Result := VK_LCL_TILDE;
|
|
KEYCODE_MINUS: Result := VK_LCL_MINUS;
|
|
KEYCODE_EQUALS:Result := VK_LCL_EQUAL;
|
|
KEYCODE_LEFT_BRACKET: Result := VK_LCL_OPEN_BRAKET;
|
|
KEYCODE_RIGHT_BRACKET: Result := VK_LCL_CLOSE_BRAKET;
|
|
KEYCODE_BACKSLASH: Result := VK_LCL_BACKSLASH;
|
|
KEYCODE_SEMICOLON: Result := VK_LCL_SEMI_COMMA;
|
|
KEYCODE_APOSTROPHE: Result := VK_LCL_QUOTE;
|
|
KEYCODE_SLASH: Result := VK_LCL_SLASH;
|
|
KEYCODE_AT: Result := VK_LCL_AT;
|
|
{ KEYCODE_NUM = 78;
|
|
KEYCODE_HEADSETHOOK = 79; // Headset Hook key. Used to hang up calls and stop media.
|
|
KEYCODE_FOCUS = 80; // *Camera* focus
|
|
KEYCODE_PLUS = 81;}
|
|
KEYCODE_MENU: Result := VK_MENU;
|
|
{ KEYCODE_NOTIFICATION = 83;
|
|
KEYCODE_SEARCH = 84;
|
|
KEYCODE_MEDIA_PLAY_PAUSE = 85;
|
|
KEYCODE_MEDIA_STOP = 86;
|
|
KEYCODE_MEDIA_NEXT = 87;
|
|
KEYCODE_MEDIA_PREVIOUS = 88;
|
|
KEYCODE_MEDIA_REWIND = 89;
|
|
KEYCODE_MEDIA_FAST_FORWARD = 90;
|
|
KEYCODE_MUTE = 91;}
|
|
KEYCODE_PAGE_UP: Result := VK_NEXT;
|
|
KEYCODE_PAGE_DOWN: Result := VK_PRIOR;
|
|
{ KEYCODE_PICTSYMBOLS = 94;
|
|
KEYCODE_SWITCH_CHARSET = 95;
|
|
KEYCODE_BUTTON_A = 96;
|
|
KEYCODE_BUTTON_B = 97;
|
|
KEYCODE_BUTTON_C = 98;
|
|
KEYCODE_BUTTON_X = 99;
|
|
KEYCODE_BUTTON_Y = 100;
|
|
KEYCODE_BUTTON_Z = 101;
|
|
KEYCODE_BUTTON_L1 = 102;
|
|
KEYCODE_BUTTON_R1 = 103;
|
|
KEYCODE_BUTTON_L2 = 104;
|
|
KEYCODE_BUTTON_R2 = 105;
|
|
KEYCODE_BUTTON_THUMBL = 106;
|
|
KEYCODE_BUTTON_THUMBR = 107;
|
|
KEYCODE_BUTTON_START = 108;
|
|
KEYCODE_BUTTON_SELECT = 109;
|
|
KEYCODE_BUTTON_MODE = 110;}
|
|
|
|
// Now keys from the SDK
|
|
|
|
{KEYCODE_3D_MODE = $000000ce; // 3D Mode key. Toggles the display between 2D and 3D mode.
|
|
KEYCODE_APP_SWITCH = $000000bb;
|
|
KEYCODE_AVR_INPUT = $000000b6;
|
|
KEYCODE_AVR_POWER = $000000b5;
|
|
KEYCODE_BOOKMARK = $000000ae;}
|
|
KEYCODE_BREAK: Result := VK_PAUSE;
|
|
{ KEYCODE_BUTTON_1 = $000000bc;
|
|
KEYCODE_BUTTON_10 = $000000c5;
|
|
KEYCODE_BUTTON_11 = $000000c6;
|
|
KEYCODE_BUTTON_12 = $000000c7;
|
|
KEYCODE_BUTTON_13 = $000000c8;
|
|
KEYCODE_BUTTON_14 = $000000c9;
|
|
KEYCODE_BUTTON_15 = $000000ca;
|
|
KEYCODE_BUTTON_16 = $000000cb; // Generic Game Pad Button #16.
|
|
KEYCODE_BUTTON_2 = $000000bd; // Generic Game Pad Button #2.
|
|
KEYCODE_BUTTON_3 = $000000be;
|
|
KEYCODE_BUTTON_4 = $000000bf;
|
|
KEYCODE_BUTTON_5 = $000000c0;
|
|
KEYCODE_BUTTON_6 = $000000c1;
|
|
KEYCODE_BUTTON_7 = $000000c2;
|
|
KEYCODE_BUTTON_8 = $000000c3;
|
|
KEYCODE_BUTTON_9 = $000000c4; // Generic Game Pad Button #9.
|
|
KEYCODE_CALCULATOR = $000000d2; // Calculator special function key. Used to launch a calculator application.
|
|
KEYCODE_CALENDAR = $000000d0; // Calendar special function key. Used to launch a calendar application.}
|
|
KEYCODE_CAPS_LOCK: Result := VK_CAPITAL;
|
|
{ KEYCODE_CAPTIONS = $000000af; // Toggle captions key. Switches the mode for closed-captioning text, for example during television shows.
|
|
KEYCODE_CHANNEL_DOWN = $000000a7; // Channel down key. On TV remotes, decrements the television channel.
|
|
KEYCODE_CHANNEL_UP = $000000a6; // Channel up key. On TV remotes, increments the television channel.
|
|
KEYCODE_CONTACTS = $000000cf; // Contacts special function key. Used to launch an address book application.
|
|
KEYCODE_CTRL_LEFT = $00000071; // Left Control modifier key.
|
|
KEYCODE_CTRL_RIGHT = $00000072; // Right Control modifier key.
|
|
KEYCODE_DVR = $000000ad; // DVR key. On some TV remotes, switches to a DVR mode for recorded shows.
|
|
KEYCODE_ENTER = $00000042; // Enter key.
|
|
KEYCODE_ENVELOPE = $00000041; // Envelope special function key. Used to launch a mail application.
|
|
KEYCODE_EQUALS = $00000046; // '=' key.
|
|
KEYCODE_ESCAPE = $0000006f; // Escape key.
|
|
KEYCODE_EXPLORER = $00000040; // Explorer special function key. Used to launch a browser application.
|
|
KEYCODE_F1 = $00000083;
|
|
KEYCODE_F10 = $0000008c;
|
|
KEYCODE_F11 = $0000008d;
|
|
KEYCODE_F12 = $0000008e;
|
|
KEYCODE_F2 = $00000084;
|
|
KEYCODE_F3 = $00000085;
|
|
KEYCODE_F4 = $00000086;
|
|
KEYCODE_F5 = $00000087;
|
|
KEYCODE_F6 = $00000088;
|
|
KEYCODE_F7 = $00000089;
|
|
KEYCODE_F8 = $0000008a;
|
|
KEYCODE_F9 = $0000008b;
|
|
KEYCODE_FORWARD = $0000007d; // Forward key. Navigates forward in the history stack. Complement of KEYCODE_BACK.}
|
|
KEYCODE_FORWARD_DEL: Result := VK_DELETE;
|
|
{ KEYCODE_FUNCTION = $00000077; // Function modifier key.
|
|
KEYCODE_GUIDE = $000000ac; // Guide key. On TV remotes, shows a programming guide.
|
|
KEYCODE_INFO = $000000a5; // Info key. Common on TV remotes to show additional information related to what is currently being viewed.}
|
|
KEYCODE_INSERT: Result := VK_INSERT;
|
|
{ KEYCODE_LANGUAGE_SWITCH = $000000cc; // Language Switch key. Toggles the current input language such as switching between English and Japanese on a QWERTY keyboard. On some devices, the same function may be performed by pressing Shift+Spacebar.
|
|
KEYCODE_MANNER_MODE = $000000cd; // Manner Mode key. Toggles silent or vibrate mode on and off to make the device behave more politely in certain settings such as on a crowded train. On some devices, the key may only operate when long-pressed.
|
|
KEYCODE_MEDIA_CLOSE = $00000080; // Close media key. May be used to close a CD tray, for example.
|
|
KEYCODE_MEDIA_EJECT = $00000081; // Eject media key. May be used to eject a CD tray, for example.
|
|
KEYCODE_MEDIA_PAUSE = $0000007f; // Pause media key.
|
|
KEYCODE_MEDIA_PLAY = $0000007e; // Play media key.
|
|
KEYCODE_MEDIA_RECORD = $00000082; // Record media key.}
|
|
KEYCODE_META_LEFT: Result := VK_LWIN;
|
|
KEYCODE_META_RIGHT: Result := VK_RWIN;
|
|
{ KEYCODE_MOVE_END = $0000007b; // End Movement key. Used for scrolling or moving the cursor around to the end of a line or to the bottom of a list.
|
|
KEYCODE_MOVE_HOME = $0000007a; // Home Movement key. Used for scrolling or moving the cursor around to the start of a line or to the top of a list.
|
|
KEYCODE_MUSIC = $000000d1; // Music special function key. Used to launch a music player application.}
|
|
KEYCODE_NUMPAD_0: Result := VK_NUMPAD0;
|
|
KEYCODE_NUMPAD_1: Result := VK_NUMPAD1;
|
|
KEYCODE_NUMPAD_2: Result := VK_NUMPAD2;
|
|
KEYCODE_NUMPAD_3: Result := VK_NUMPAD3;
|
|
KEYCODE_NUMPAD_4: Result := VK_NUMPAD4;
|
|
KEYCODE_NUMPAD_5: Result := VK_NUMPAD5;
|
|
KEYCODE_NUMPAD_6: Result := VK_NUMPAD6;
|
|
KEYCODE_NUMPAD_7: Result := VK_NUMPAD7;
|
|
KEYCODE_NUMPAD_8: Result := VK_NUMPAD8;
|
|
KEYCODE_NUMPAD_9: Result := VK_NUMPAD9;
|
|
KEYCODE_NUMPAD_ADD: Result := VK_ADD;
|
|
//KEYCODE_NUMPAD_COMMA: Result := $0000009f;
|
|
KEYCODE_NUMPAD_DIVIDE: Result := VK_DIVIDE;
|
|
KEYCODE_NUMPAD_DOT: Result := VK_DECIMAL;
|
|
KEYCODE_NUMPAD_ENTER: Result := VK_RETURN;
|
|
//KEYCODE_NUMPAD_EQUALS: Result := VK_LCL_EQUAL;
|
|
//KEYCODE_NUMPAD_LEFT_PAREN: Result := $000000a2;
|
|
KEYCODE_NUMPAD_MULTIPLY: Result := VK_MULTIPLY;
|
|
//KEYCODE_NUMPAD_RIGHT_PAREN:Result := $000000a3;
|
|
KEYCODE_NUMPAD_SUBTRACT: Result := VK_LCL_MINUS;
|
|
KEYCODE_NUM_LOCK: Result := VK_NUMLOCK;
|
|
{KEYCODE_PROG_BLUE = $000000ba;
|
|
KEYCODE_PROG_GREEN = $000000b8;
|
|
KEYCODE_PROG_RED = $000000b7;
|
|
KEYCODE_PROG_YELLOW = $000000b9;}
|
|
KEYCODE_SCROLL_LOCK: Result := VK_SCROLL;
|
|
{ KEYCODE_SETTINGS = $000000b0;
|
|
KEYCODE_STB_INPUT = $000000b4;
|
|
KEYCODE_STB_POWER = $000000b3;}
|
|
KEYCODE_SYSRQ: Result := VK_PRINT;
|
|
{ KEYCODE_TV = $000000aa;
|
|
KEYCODE_TV_INPUT = $000000b2;
|
|
KEYCODE_TV_POWER = $000000b1;}
|
|
KEYCODE_VOLUME_MUTE: Result := VK_VOLUME_MUTE;
|
|
{KEYCODE_WINDOW = $000000ab;
|
|
KEYCODE_ZOOM_IN = $000000a8;
|
|
KEYCODE_ZOOM_OUT = $000000a9; }
|
|
else
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TCDWidgetSet.DoOpenURLWidgetsetImplementation(AURL: string): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TCDWidgetSet.DoOpenDocumentWidgetsetImplementation(APath: string): Boolean;
|
|
var
|
|
// Java IDs
|
|
javaAndroidContentContextClass: JClass;
|
|
javaAndroidNetUriClass: JClass;
|
|
javaMethod_Context_getFileStreamPath: jmethodid = nil;
|
|
javaMethod_Uri_fromFile: jmethodid = nil;
|
|
javaMethod_Uri_fromParts: jmethodid = nil;
|
|
// Java Object instances
|
|
lJavaString, lJavaString2: jstring;
|
|
lJavaFileObject: JObject;
|
|
lJavaURIObject: JObject;
|
|
// array for the parameters
|
|
lParams: array[0..2] of JValue;
|
|
//
|
|
begin
|
|
Result := False;
|
|
|
|
if (javaEnvRef = nil) then Exit;
|
|
|
|
// First IDs
|
|
javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
|
|
javaAndroidNetUriClass := javaEnvRef^^.FindClass(javaEnvRef,'android/net/Uri');
|
|
|
|
javaMethod_Context_getFileStreamPath := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getFileStreamPath', '(Ljava/lang/String;)Ljava/io/File;');
|
|
javaMethod_Uri_fromFile := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaAndroidNetUriClass, 'fromFile', '(Ljava/io/File;)Landroid/net/Uri;');
|
|
javaMethod_Uri_fromParts := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaAndroidNetUriClass, 'fromParts', '(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;');
|
|
|
|
{ // File file = this.getFileStreamPath("test.pdf")
|
|
lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(APath));
|
|
lParams[0].l := lJavaString;
|
|
lJavaFileObject := javaEnvRef^^.CallObjectMethodA(javaEnvRef, javaActivityObject, javaMethod_Context_getFileStreamPath, @lParams[0]);
|
|
|
|
// Uri uri = Uri.fromFile(file)
|
|
DebugLn(Format('B APath=%s lJavaFileObject=%x', [APath, PtrInt(lJavaFileObject)]));
|
|
lParams[0].l := lJavaFileObject;
|
|
lJavaURIObject := javaEnvRef^^.CallStaticObjectMethodA(javaEnvRef, javaAndroidNetUriClass, javaMethod_Uri_fromFile, @lParams[0]);}
|
|
|
|
// Uri uri = Uri.fromFile(file)
|
|
DebugLn(Format('[DoOpenDocumentWidgetsetImplementation] APath=%s', [APath]));
|
|
lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, 'file');
|
|
lParams[0].l := lJavaString;
|
|
lJavaString2 := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar('//' + APath));
|
|
lParams[1].l := lJavaString2;
|
|
lParams[2].l := nil;
|
|
lJavaURIObject := javaEnvRef^^.CallStaticObjectMethodA(javaEnvRef, javaAndroidNetUriClass, javaMethod_Uri_fromParts, @lParams[0]);
|
|
|
|
Result := DoOpenAndroidURI(lJavaURIObject, GetMimeTypeFromFileName(APath));
|
|
end;
|
|
|
|
function TCDWidgetSet.DoOpenAndroidURI(AURI: JObject; AMimeType: string): Boolean;
|
|
var
|
|
// Java IDs
|
|
javaAndroidContentContextClass: JClass;
|
|
javaAndroidContentIntentClass: JClass;
|
|
javaAndroidContentPmPackageManagerClass: JClass;
|
|
javaAndroidAppActivityClass: JClass;
|
|
javaMethod_Intent_new: jmethodid = nil;
|
|
javaMethod_Intent_setDataAndType: jmethodid = nil;
|
|
javaMethod_Context_getPackageManager: jmethodid = nil;
|
|
// javaMethod_PmPackageManager_queryIntentActivities: jmethodid = nil;
|
|
javaMethod_Activity_startActivity: jmethodid = nil;
|
|
// Java Object instances
|
|
lJavaString: jstring;
|
|
javaViewDocObject: JObject;
|
|
lJavaPackageManagerObject: JObject;
|
|
// array for the parameters
|
|
lParams: array[0..1] of JValue;
|
|
//
|
|
begin
|
|
Result := False;
|
|
|
|
if (javaEnvRef = nil) then Exit;
|
|
|
|
// First IDs
|
|
DebugLn(Format(':>[DoOpenAndroidURI] AURI=%x', [PtrInt(AURI)]));
|
|
javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
|
|
javaAndroidContentIntentClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Intent');
|
|
javaAndroidContentPmPackageManagerClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/pm/PackageManager');
|
|
javaAndroidAppActivityClass := javaEnvRef^^.FindClass(javaEnvRef,'android/app/Activity');
|
|
|
|
javaMethod_Intent_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentIntentClass, '<init>', '(Ljava/lang/String;)V');
|
|
javaMethod_Intent_setDataAndType := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentIntentClass, 'setDataAndType', '(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;');
|
|
// javaMethod_Context_getPackageManager := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getPackageManager', '()Landroid.content.pm.PackageManager;');
|
|
javaMethod_Activity_startActivity := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidAppActivityClass, 'startActivity', '(Landroid/content/Intent;)V');
|
|
|
|
// Intent viewDoc = new Intent(Intent.ACTION_VIEW);
|
|
lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, javaConstant_Intent_ACTION_VIEW);
|
|
lParams[0].l := lJavaString;
|
|
javaViewDocObject := javaEnvRef^^.NewObjectA(javaEnvRef, javaAndroidContentIntentClass, javaMethod_Intent_new, @lParams[0]);
|
|
|
|
// viewDoc.setDataAndType(uri, "application/pdf");
|
|
lParams[0].l := AURI;
|
|
lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(AMimeType));
|
|
lParams[1].l := lJavaString;
|
|
javaEnvRef^^.CallObjectMethodA(javaEnvRef, javaViewDocObject, javaMethod_Intent_setDataAndType, @lParams[0]);
|
|
|
|
// PackageManager pm = this.getPackageManager();
|
|
//lJavaPackageManagerObject := javaEnvRef^^.CallObjectMethod(javaEnvRef, javaActivityObject, javaMethod_Context_getPackageManager);
|
|
|
|
// List<ResolveInfo> apps = pm.queryIntentActivities(viewDoc, PackageManager.MATCH_DEFAULT_ONLY);
|
|
|
|
// int lSize = apps.size()
|
|
|
|
// if (lSize > 0) this.startActivity(viewDoc);
|
|
lParams[0].l := javaViewDocObject;
|
|
javaEnvRef^^.CallVoidMethodA(javaEnvRef, javaActivityObject, javaMethod_Activity_startActivity, @lParams[0]);
|
|
|
|
Result := True;
|
|
DebugLn(':<[DoOpenAndroidURI]');
|
|
end;
|
|
|
|
function TCDWidgetSet.GetMimeTypeFromFileName(AFileName: string): string;
|
|
var
|
|
lExt: String;
|
|
begin
|
|
lExt := SysUtils.ExtractFileExt(AFileName);
|
|
if lExt = '.png' then Result := 'image/png'
|
|
else if lExt = '.txt' then Result := 'text/plain'
|
|
else if lExt = '.jpg' then Result := 'image/jpeg';
|
|
end;
|
|
|
|
function TCDWidgetSet.GetAppHandle: THandle;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCDWidgetSet.Create
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Constructor for the class.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.BackendCreate;
|
|
begin
|
|
// Setup DebugLn
|
|
{$IFnDEF WithOldDebugln}
|
|
OnWidgetSetDebugLn := @AndroidDebugLn;
|
|
OnWidgetSetDbgOut := @AccumulatingDebugOut;
|
|
{$ELSE}
|
|
DebugLnProc := @AndroidDebugLn;
|
|
DebugOutProc := @AccumulatingDebugOut;
|
|
{$ENDIF}
|
|
|
|
{$ifdef CD_UseNativeText}
|
|
// Create the dummy screen DC
|
|
ScreenBitmapRawImage.Init;
|
|
ScreenBitmapHeight := 100;
|
|
ScreenBitmapWidth := 100;
|
|
ScreenBitmapRawImage.Description.Init_BPP32_A8R8G8B8_BIO_TTB(ScreenBitmapWidth, ScreenBitmapHeight);
|
|
ScreenBitmapRawImage.CreateData(True);
|
|
ScreenImage := TLazIntfImage.Create(0, 0);
|
|
ScreenImage.SetRawImage(ScreenBitmapRawImage);
|
|
ScreenDC := TLazCanvas.Create(ScreenImage);
|
|
|
|
DefaultFontAndroidSize := 16;
|
|
{$endif}
|
|
|
|
// Android support for OpenURL and OpenDocument
|
|
LCLIntf.OpenURLWidgetsetImplementation := @DoOpenURLWidgetsetImplementation;
|
|
LCLIntf.OpenDocumentWidgetsetImplementation := @DoOpenDocumentWidgetsetImplementation;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.Destroy
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
destructor for the class.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.BackendDestroy;
|
|
begin
|
|
{$ifdef CD_UseNativeText}
|
|
// Free the dummy screen DC
|
|
ScreenImage.Free;
|
|
ScreenDC.Free;
|
|
{$endif}
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppInit
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
initialize Windows
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
|
|
begin
|
|
{$ifdef VerboseCDApplication}
|
|
DebugLn('TCDWidgetSet.AppInit');
|
|
{$endif}
|
|
|
|
Forms.MessageBoxFunction := @CDMessageBoxFunction;
|
|
|
|
if Application.LayoutAdjustmentPolicy = lapDefault then
|
|
Application.LayoutAdjustmentPolicy := lapAutoAdjustWithoutHorizontalScrolling;
|
|
|
|
// Generic
|
|
GenericAppInit();
|
|
end;
|
|
|
|
procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
|
|
begin
|
|
{$ifdef VerboseCDApplication}
|
|
DebugLn('TCDWidgetSet.AppRun');
|
|
{$endif}
|
|
end;
|
|
|
|
(*
|
|
function TWinCEWidgetSet.GetAppHandle: THandle;
|
|
begin
|
|
Result:= FAppHandle;
|
|
end;
|
|
|
|
procedure TWinCEWidgetSet.SetAppHandle(const AValue: THandle);
|
|
begin
|
|
// Do it only if handle is not yet created (for example for DLL initialization)
|
|
// if handle is already created we can't reassign it
|
|
if AppHandle = 0 then
|
|
FAppHandle := AValue;
|
|
end;*)
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppMinimize
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Minimizes the whole application to the taskbar
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.AppMinimize;
|
|
begin
|
|
// calling Activity.Free doesnt close the app, only hides it, so it is good for AppMinimize
|
|
javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_Activity_finish);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppRestore
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Restore minimized whole application from taskbar
|
|
------------------------------------------------------------------------------}
|
|
|
|
procedure TCDWidgetSet.AppRestore;
|
|
begin
|
|
// Windows.SendMessage(FAppHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppBringToFront
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Brings the entire application on top of all other non-topmost programs
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.AppBringToFront;
|
|
begin
|
|
end;
|
|
|
|
(*
|
|
procedure TWinCEWidgetSet.SetDesigning(AComponent: TComponent);
|
|
begin
|
|
//if Data<>nil then EnableWindow((AComponent As TWinControl).Handle, boolean(Data^));
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.SetCallback
|
|
Params: Msg - message for which to set a callback
|
|
Sender - object to which callback will be sent
|
|
Returns: nothing
|
|
|
|
Applies a Message to the sender
|
|
------------------------------------------------------------------------------}
|
|
procedure TWinCEWidgetSet.SetCallback(Msg: LongInt; Sender: TObject);
|
|
var
|
|
Window: HWnd;
|
|
begin
|
|
//DebugLn('Trace:TWinCEWidgetSet.SetCallback - Start');
|
|
//DebugLn(Format('Trace:TWinCEWidgetSet.SetCallback - Class Name --> %S', [Sender.ClassName]));
|
|
//DebugLn(Format('Trace:TWinCEWidgetSet.SetCallback - Message Name --> %S', [GetMessageName(Msg)]));
|
|
if Sender Is TControlCanvas then
|
|
Window := TControlCanvas(Sender).Handle
|
|
else if Sender Is TCustomForm then
|
|
Window := TCustomForm(Sender).Handle
|
|
else
|
|
Window := TWinControl(Sender).Handle;
|
|
if Window=0 then exit;
|
|
|
|
//DebugLn('Trace:TWinCEWidgetSet.SetCallback - Exit');
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.RemoveCallbacks
|
|
Params: Sender - object from which to remove callbacks
|
|
Returns: nothing
|
|
|
|
Removes Call Back Signals from the sender
|
|
------------------------------------------------------------------------------}
|
|
procedure TWinCEWidgetSet.RemoveCallbacks(Sender: TObject);
|
|
var
|
|
Window: HWnd;
|
|
begin
|
|
if Sender Is TControlCanvas then
|
|
Window := TControlCanvas(Sender).Handle
|
|
else if Sender Is TCustomForm then
|
|
Window := TCustomForm(Sender).Handle
|
|
else
|
|
Window := (Sender as TWinControl).Handle;
|
|
if Window=0 then exit;
|
|
end;*)
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppProcessMessages
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Handle all pending messages
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.AppProcessMessages;
|
|
begin
|
|
end;
|
|
(*
|
|
procedure TWinCEWidgetSet.CheckPipeEvents;
|
|
var
|
|
lHandler: PPipeEventInfo;
|
|
// lBytesAvail: dword;
|
|
// SomethingChanged: Boolean;
|
|
ChangedCount:integer;
|
|
begin
|
|
lHandler := FWaitPipeHandlers;
|
|
ChangedCount := 0;
|
|
while (lHandler <> nil) and (ChangedCount < 10) do
|
|
begin
|
|
{
|
|
roozbeh : ooops not supported
|
|
SomethingChanged:=true;
|
|
if Windows.PeekNamedPipe(lHandler^.Handle, nil, 0, nil, @lBytesAvail, nil) then
|
|
begin
|
|
if lBytesAvail <> 0 then
|
|
lHandler^.OnEvent(lHandler^.UserData, [prDataAvailable])
|
|
else
|
|
SomethingChanged := false;
|
|
end else
|
|
lHandler^.OnEvent(lHandler^.UserData, [prBroken]);
|
|
if SomethingChanged then
|
|
lHandler := FWaitPipeHandlers
|
|
else begin
|
|
lHandler := lHandler^.Next;
|
|
ChangedCount := 0;
|
|
end;
|
|
inc(ChangedCount);}
|
|
end;
|
|
end;*)
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TWinCEWidgetSet.AppWaitMessage
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Passes execution control to Windows
|
|
------------------------------------------------------------------------------}
|
|
//roozbeh:new update...whole procedure body is added.what is it?
|
|
procedure TCDWidgetSet.AppWaitMessage;
|
|
begin
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCDWidgetSet.AppTerminate
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Terminates the application
|
|
------------------------------------------------------------------------------}
|
|
procedure TCDWidgetSet.AppTerminate;
|
|
var
|
|
lParams: array[0..0] of JValue;
|
|
begin
|
|
DebugLn('[TCDWidgetSet.AppTerminate] Start');
|
|
|
|
// Call the method
|
|
lParams[0].i := 0;
|
|
javaEnvRef^^.CallStaticVoidMethodA(javaEnvRef, javaJavaLangSystemClass, javaMethod_System_exit, @lParams[0]);
|
|
|
|
DebugLn('[TCDWidgetSet.AppTerminate] End');
|
|
end;
|
|
|
|
procedure TCDWidgetSet.AppSetIcon(const Small, Big: HICON);
|
|
begin
|
|
end;
|
|
|
|
procedure TCDWidgetSet.AppSetTitle(const ATitle: string);
|
|
begin
|
|
end;
|
|
|
|
procedure TCDWidgetSet.AppSetVisible(const AVisible: Boolean);
|
|
begin
|
|
end;
|
|
|
|
function TCDWidgetSet.AppRemoveStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
|
|
begin
|
|
end;
|
|
|
|
function TCDWidgetSet.AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
|
|
begin
|
|
end;
|
|
|
|
procedure TCDWidgetSet.AppSetMainFormOnTaskBar(const DoSet: Boolean);
|
|
begin
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function: CreateTimer
|
|
Params: Interval:
|
|
TimerFunc: Callback
|
|
Returns: a Timer id (use this ID to destroy timer)
|
|
|
|
Design: A timer which calls TimerCallBackProc, is created.
|
|
The TimerCallBackProc calls the TimerFunc.
|
|
------------------------------------------------------------------------------}
|
|
function TCDWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc) : THandle;
|
|
var
|
|
lTimer: TCDTimer;
|
|
begin
|
|
lTimer := TCDTimer.Create;
|
|
|
|
Result := THandle(lTimer);
|
|
|
|
lTimer.Interval := Interval;
|
|
lTimer.TimerFunc := TimerFunc;
|
|
|
|
// Prepare the input
|
|
javaEnvRef^^.SetIntField(javaEnvRef, javaActivityObject, javaField_lcltimerinterval, Interval);
|
|
|
|
// Call the method
|
|
javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoCreateTimer);
|
|
|
|
// Read the output
|
|
lTimer.NativeHandle := PtrInt(javaEnvRef^^.GetObjectField(javaEnvRef, javaActivityObject, javaField_lcltimerid));
|
|
|
|
// Add it to our list
|
|
AddTimer(lTimer);
|
|
DebugLn(Format('[TCDWidgetSet.CreateTimer] Result=%x', [PtrInt(Result)]));
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function: DestroyTimer
|
|
Params: TimerHandle
|
|
Returns:
|
|
------------------------------------------------------------------------------}
|
|
function TCDWidgetSet.DestroyTimer(TimerHandle: THandle) : boolean;
|
|
var
|
|
lTimer: TCDTimer;
|
|
begin
|
|
DebugLn(Format('[TCDWidgetSet.DestroyTimer] TimerHandle=%x', [PtrInt(TimerHandle)]));
|
|
Result := False;
|
|
|
|
lTimer := TCDTimer(TimerHandle);
|
|
|
|
if lTimer = nil then Exit;
|
|
|
|
// Prepare the input
|
|
javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, javaField_lcltimerid, jobject(lTimer.NativeHandle));
|
|
|
|
// Call the method
|
|
javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoDestroyTimer);
|
|
|
|
// Remove from the list
|
|
RemoveTimer(lTimer);
|
|
lTimer.Free;
|
|
|
|
Result := True;
|
|
end;
|
|
(*
|
|
procedure TWinCEWidgetSet.HandleWakeMainThread(Sender: TObject);
|
|
begin
|
|
// wake up GUI thread by sending a message to it
|
|
Windows.PostMessage(AppHandle, WM_NULL, 0, 0);
|
|
end;
|
|
*)
|
|
|
|
// This code is unnecessary in FPC 2.6+,
|
|
// it was required when the 2.5.1 snapshot was created
|
|
{$ifdef ver2_5}
|
|
procedure PASCALMAIN; external name 'PASCALMAIN';
|
|
|
|
procedure FPC_SHARED_LIB_START; [public, alias: 'FPC_SHARED_LIB_START'];
|
|
begin
|
|
PASCALMAIN;
|
|
end;
|
|
{$endif}
|
|
|