lazarus/lcl/interfaces/customdrawn/customdrawnobject_android.inc

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}