1{%MainUnit customdrawnint.pas}
2
3{******************************************************************************
4                                   customdrawnobject_win.inc
5 ******************************************************************************
6
7 *****************************************************************************
8  This file is part of the Lazarus Component Library (LCL)
9
10  See the file COPYING.modifiedLGPL.txt, included in this distribution,
11  for details about the license.
12 *****************************************************************************
13}
14
15const
16  // Shared Mouse / Key constants
17  ACTION_DOWN = 0;
18  ACTION_UP = 1;
19
20  // Touch constants
21  ACTION_MOVE = 2;
22
23  // Constants from android/view/KeyEvent up to level 8
24  ACTION_MULTIPLE = 2;
25  // Keys are in KeyCodes.pas
26
27  // from android.view.KeyCharacterMap
28  COMBINING_ACCENT = $80000000;
29
30const
31  javaConstant_CLIPBOARD_SERVICE = 'clipboard';
32  javaConstant_Intent_ACTION_VIEW = 'android.intent.action.VIEW';
33
34  javaConstant_PackageManager_MATCH_DEFAULT_ONLY = $00010000;
35
36function Java_com_pascal_lclproject_LCLActivity_LCLOnTouch(env:PJNIEnv;this:jobject; x, y: single; action: jint): jint; cdecl;
37var
38  lCurForm: TCDNonNativeForm;
39  lTarget: TWinControl;
40  lEventPos: TPoint;
41begin
42  {$ifdef VerboseCDEvents}
43  __android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(Format('LCLOnTouch called x=%f y=%f action=%d', [x, y, action])));
44  {$endif}
45  eventResult := 0;
46
47  lCurForm := GetCurrentForm();
48
49  case action of
50    ACTION_DOWN:
51    begin
52      CallbackMouseDown(lCurForm, Round(X), Round(Y), mbLeft, []);
53    end;
54    ACTION_UP:
55    begin
56      CallbackMouseUp(lCurForm, Round(X), Round(Y), mbLeft, []);
57    end;
58    ACTION_MOVE: CallbackMouseMove(lCurForm, Round(X), Round(Y), []);
59  end;
60
61  // This sends messages like Invalidate requests
62  Result := eventResult;
63end;
64
65function Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap(
66    env:PJNIEnv;this:jobject; width, height: jint; abitmap: jobject): jint; cdecl;
67var
68  pixels: PCardinal;
69  lCurForm: TCDNonNativeForm;
70
71  {$IFDEF VerboseCDPaintProfiler}
72  lTimeStart: TDateTime;
73  {$ENDIF}
74begin
75  Result := 0;
76  AndroidBitmap_lockPixels(env, abitmap, @pixels);
77
78  lCurForm := GetCurrentForm();
79  if lCurForm <> nil then
80  begin
81    {$IFDEF VerboseCDPaintProfiler}
82    //lTimeStart := NowUTC();
83    {$ENDIF}
84    {$IFDEF VerboseCDPaintEvent}
85    DebugLn(Format('[Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap] lCurForm:TCDNonNativeForm=%x', [PtrInt(lCurForm)]));
86    {$ENDIF}
87
88    // Prepare the non-native image and canvas
89    UpdateControlLazImageAndCanvas(lCurForm.Image, lCurForm.Canvas, Width, Height, clfRGBA32, pixels, True, False);
90
91    RenderForm(lCurForm.Image, lCurForm.Canvas, lCurForm.LCLForm);
92  end;
93
94  // Now returns the bitmap buffer to LCLActivity so that it can render it
95  AndroidBitmap_unlockPixels(env, abitmap);
96end;
97
98function Java_com_pascal_lclproject_LCLActivity_LCLOnCreate(
99    env:PJNIEnv; this:jobject; alclactivity: jobject): jint; cdecl;
100begin
101  __android_log_write(ANDROID_LOG_INFO, 'lclapp', 'LCLOnCreate called by LCLActivity.onCreate');
102  Result := 0;
103  javaActivityObject := alclactivity;
104  Screen.UpdateScreen(); // Any values read before LCLOnCreate are wrong
105  // Update the font size
106  CDWidgetset.DefaultFontAndroidSize := Round(16 * (Screen.PixelsPerInch / 125));
107  // Now inform the application
108  if Assigned(CDWidgetset.ActivityOnCreate) then CDWidgetset.ActivityOnCreate()
109  else Application.Run; // <- Support for older code up to 21 dezember 2011
110end;
111
112// This one is for all simple dialogs: MessageBox, PromptUser (MessageDlg) and AskUser
113function Java_com_pascal_lclproject_LCLActivity_LCLOnMessageBoxFinished(
114    env:PJNIEnv; this:jobject; AResult, ADialogType: jint): jint; cdecl;
115begin
116  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('LCLOnMessageBoxFinished called AResult=%d ADialogType=%d',
117    [AResult, ADialogType])));
118  Result := 0;
119  case ADialogType of
120  0: if Assigned(Application.OnMessageDialogFinished) then
121       Application.OnMessageDialogFinished(Application, AResult);
122  1: if Assigned(OnShowSelectItemDialogResult) then OnShowSelectItemDialogResult(AResult);
123  2: if Assigned(OnListViewDialogResult) then OnListViewDialogResult(AResult);
124  end;
125end;
126
127function Java_com_pascal_lclproject_LCLActivity_LCLOnKey(
128    env:PJNIEnv; this:jobject; AKind: jint; AKeyCode: jint;
129    AEvent: jobject; AChar: jint): jint; cdecl;
130var
131  lCurForm: TCDNonNativeForm;
132  lTarget, lFocusedControl: TWinControl;
133  lKey: Word;
134  lCombinedAChar: jint;
135  lChar: Cardinal;
136  AUTF8Text: string;
137  AUTF8Char: TUTF8Char;
138  lForm: TCDNonNativeForm;
139begin
140  lChar := Cardinal(AChar);
141  {$ifdef VerboseCDKeyInput}
142  __android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(
143    Format('[LCLOnKey] called AKind=%d AKeyCode=%x AChar=%s', [AKind, AKeyCode, UnicodeToUTF8(lChar)])));
144  {$endif}
145  eventResult := 0;
146
147  lCurForm := GetCurrentForm();
148  lKey := CDWidgetset.AndroidKeyCodeToLCLKeyCode(AKeyCode);
149
150  case AKind of
151    ACTION_DOWN:
152    begin
153      CallbackKeyDown(lCurForm, lKey);
154
155      // Galaxy Nexus S with Android 4.0 sends numbers only as key down/up events,
156      // it doesn't send them to commit text
157      //
158      // Wildfire with Android 2.2 sends the numbers only to commit text
159      //
160      // So if we get any numbers here, generate KeyPress too
161      case lKey of
162        VK_0..VK_9:
163        begin
164          AUTF8Char := VK2Char(lKey);
165          CallbackKeyChar(lCurForm, lKey, AUTF8Char);
166        end;
167      end;
168    end;
169    // This indicates a key char event, created with commitText
170    // We don't get KeyDown/KeyUp when we get this, so generate them
171    -1:
172    begin
173      AUTF8Text := UnicodeToUTF8(lChar);
174      AUTF8Char := AUTF8Text;
175
176      if Length(AUTF8Text) = 1 then
177      begin
178        lKey := Char2VK(AUTF8Text[1]);
179        CallbackKeyDown(lCurForm, lKey);
180      end;
181
182      CallbackKeyChar(lCurForm, lKey, AUTF8Char);
183
184      if Length(AUTF8Text) = 1 then
185        CallbackKeyUp(lCurForm, lKey);
186    end;
187    ACTION_UP:
188    begin
189      CallbackKeyUp(lCurForm, lKey);
190(*      if (lChar <> 0) and ((COMBINING_ACCENT and lChar) = 0) then
191      begin
192        if CDWidgetset.CombiningAccent <> 0 then
193        begin
194          // Prepare the input
195          lJavaString :=javaEnvRef^^.NewStringUTF(javaEnvRef, Str);
196          javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, JavaField_lcltext, lJavaString);
197          javaEnvRef^^.SetIntField(javaEnvRef, javaActivityObject, javaField_lcltextsize, lFontSize);
198
199          // Call the method
200          javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoGetTextBounds);
201
202          // Read the output
203          Size.cx := javaEnvRef^^.GetIntField(javaEnvRef, javaActivityObject, javaField_lclwidth);
204          Size.cy := javaEnvRef^^.GetIntField(javaEnvRef, javaActivityObject, javaField_lclheight);
205          //
206          lCombinedAChar := getDeadChar();
207        end;
208        AUTF8Text := UnicodeToUTF8(lChar);
209        AUTF8Char := AUTF8Text;
210        CallbackKeyChar(lCurForm, lKey, AUTF8Char);
211        CDWidgetset.CombiningAccent := 0;
212      end
213      else if (lChar <> 0) and ((COMBINING_ACCENT and lChar) <> 0) then
214      begin
215        CDWidgetset.CombiningAccent := lChar;
216      end;*)
217
218      // Handle the Back hardware key
219      if AKeyCode = AKEYCODE_BACK then
220      begin
221        //DebugLn(Format('CallbackKeyUp D lForm=%x', [PtrInt(lForm)]));
222        // The back hardware key hides the current form and shows the one bellow it
223        // except if the currently focused control is a text editor, in which case
224        // it will take focus out of the text editor
225        lForm := lCurForm;
226        lFocusedControl := lForm.GetFocusedControl();
227        if (lFocusedControl <> nil) and (csRequiresKeyboardInput in lFocusedControl.ControlStyle) then
228        begin
229          //DebugLn('[LCLOnKey] Sending focus to the form');
230          CDWidgetset.CDSetFocusToControl(lForm.LCLForm, nil);
231        end
232        // If this is the main form, then go back to desktop
233        else if (Application.MainForm <> nil) and (lForm = TCDForm(Application.MainForm.Handle)) then
234        begin
235          //DebugLn('[LCLOnKey] Back key is going to hide the application');
236          eventResult := eventResult or 2;
237        end
238        // for other forms, hide them
239        else
240        begin
241          //DebugLn('[LCLOnKey] Hiding the form');
242          HideForm(lForm);
243        end;
244      end;
245    end;
246    //ACTION_MULTIPLE:
247  end;
248
249  // This sends messages like Invalidate requests
250  Result := eventResult;
251end;
252
253function Java_com_pascal_lclproject_LCLActivity_LCLOnTimer(
254    env:PJNIEnv; this:jobject; ATimer: jobject; ATimerIDIndex: jint): jint; cdecl;
255var
256  lTimer: TCDTimer;
257begin
258  {$ifdef VerboseCDEvents}
259  __android_log_write(ANDROID_LOG_INFO,'lclapp',PChar(
260    Format('LCLOnTimer called ATimer=%x', [PtrInt(ATimer)])));
261  {$endif}
262  eventResult := 0;
263
264  lTimer := FindTimerWithNativeHandle(PtrInt(ATimer));
265
266  if lTimer <> nil then lTimer.TimerFunc()
267  else DebugLn('[LCLOnTimer] OnTimer message sent to unknown timer!');
268
269  // This sends messages like Invalidate requests
270  Result := eventResult;
271end;
272
273function Java_com_pascal_lclproject_LCLActivity_LCLOnConfigurationChanged(
274  env:PJNIEnv; this:jobject; ANewDPI, ANewWidth: jint): jint; cdecl;
275var
276  lForm: TCDNonNativeForm;
277  lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth: Integer;
278  i: Integer;
279begin
280  for i := 0 to GetFormCount()-1 do
281  begin
282    lForm := GetForm(i);
283
284    if lForm.LayoutAutoAdjusted then lOldDPI := Screen.PixelsPerInch
285    else lOldDPI := lForm.LCLForm.DesignTimePPI;
286    lNewDPI := ANewDPI;
287    lOldFormWidth := lForm.LCLForm.Width;
288    lNewFormWidth := ANewWidth;
289    DebugLn(Format('[LCLOnConfigurationChanged] i=%d lOldDPI=%d lNewDPI=%d lOldFormWidth=%d lNewFormWidth=%d',
290      [i, lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth]));
291    lForm.LCLForm.AutoAdjustLayout(lapAutoAdjustWithoutHorizontalScrolling,
292      lOldDPI, lNewDPI, lOldFormWidth, lNewFormWidth);
293  end;
294
295  // Update the font size
296  CDWidgetset.DefaultFontAndroidSize := Round(16 * (ANewDPI / 125));
297end;
298
299function Java_com_pascal_lclproject_LCLActivity_LCLOnSensorChanged(
300  env:PJNIEnv; this:jobject; ASensorKind: jint; AValues: JDoubleArray): jint; cdecl;
301var
302  arraydata: PDouble;
303  arraylen: jsize;
304  lIsCopy: jboolean;
305  lSensorDataInt: Integer;
306  lMessagingStatus: TLazMessagingStatus;
307  lUnixTimeStamp: Int64;
308begin
309  Result := 0;
310
311  if (javaEnvRef = nil) then Exit;
312
313  // Get the elements and length
314  lIsCopy := 0;
315  arraylen := javaEnvRef^^.GetArrayLength(javaEnvRef, AValues);
316  arraydata := javaEnvRef^^.GetDoubleArrayElements(javaEnvRef, AValues, lIsCopy);
317
318  // Send the data to the LCL
319  case ASensorKind of
320    -11: // Defined by ourselves for Messaging Status
321    begin
322      lSensorDataInt := Round(arraydata[0]);
323      case lSensorDataInt of
324        1: lMessagingStatus := mssSentSuccessfully;
325        2: lMessagingStatus := mssSendingGeneralError;
326        3: lMessagingStatus := mssNoService;
327        5: lMessagingStatus := mssRadioOff;
328        10:lMessagingStatus := mssReceivedSuccessfully;
329        11:lMessagingStatus := mssReceivingGeneralError;
330      else
331        lMessagingStatus := mssSendingGeneralError;
332      end;
333
334      if Assigned(Messaging.OnMessagingStatus) then
335        Messaging.OnMessagingStatus(nil, lMessagingStatus);
336    end;
337    -10: // Defined by ourselves for PositionInfo
338    begin
339      PositionInfo.latitude := arraydata[0];
340      PositionInfo.longitude := arraydata[1];
341      PositionInfo.altitude := arraydata[2];
342      PositionInfo.accuracy := arraydata[3];
343      PositionInfo.altitudeAccuracy := PositionInfo.accuracy;
344      PositionInfo.speed := arraydata[4];
345      lUnixTimeStamp := Round(arraydata[5]);
346      PositionInfo.timeStamp :=  UnixToDateTime(lUnixTimeStamp);
347
348      if Assigned(PositionInfo.OnPositionRetrieved) then
349        PositionInfo.OnPositionRetrieved(PositionInfo);
350    end;
351    1: // ACCELEROMETER
352    begin
353      Accelerometer.xaxis := -1*arraydata[0];
354      Accelerometer.yaxis := -1*arraydata[1];
355      Accelerometer.zaxis := -1*arraydata[2];
356      if Assigned(Accelerometer.OnSensorChanged) then
357        Accelerometer.OnSensorChanged(Accelerometer);
358    end;
359  end;
360
361  // Don't forget to release it
362  javaEnvRef^^.ReleaseDoubleArrayElements(javaEnvRef, AValues, arraydata, 0);
363
364  // This sends messages like Invalidate requests
365  Result := eventResult;
366end;
367
368function Java_com_pascal_lclproject_LCLActivity_LCLOnMenuAction(
369  env:PJNIEnv; this:jobject; kind, itemIndex: jint): jint; cdecl;
370var
371  javaField_lclmenu_captions: jfieldid;
372  javaObject_lclmenu_captions: jobjectarray;
373  lJavaString: jstring;
374  lCurrentForm: TCDNonNativeForm;
375  lMenu: TMainMenu;
376  StrPas: string;
377  Str: PChar;
378  lMenuItem: TMenuItem;
379  i, CurIndex, NumMenuItems: Integer;
380begin
381  Result := 0;
382
383  // Very strangely in the emulator it crashes if we don't refresh the Activity class here
384  javaActivityClass := javaEnvRef^^.FindClass(javaEnvRef, PChar(CDWidgetset.ActivityClassName));
385
386  //{$ifdef VerboseCDEvents}
387  DebugLn(Format('LCLOnMenuAction called kind=%d itemIndex=%d', [kind, itemIndex]));
388  //{$endif}
389
390  if (javaEnvRef = nil) then Exit;
391
392  lCurrentForm := GetCurrentForm();
393  if lCurrentForm = nil then Exit;
394  lMenu := lCurrentForm.LCLForm.Menu;
395  if lMenu = nil then Exit;
396
397  // kind=0 means that we should create the menu items list
398  if kind = 0 then
399  begin
400    // First calculate the number of menu items
401    NumMenuItems := 0;
402    for i := 0 to lMenu.Items.Count-1 do
403    begin
404      lMenuItem := lMenu.Items[i];
405      // Various things might make a menu item invalid and therefore not part of the list
406      if not lMenuItem.Visible then Continue;
407      if lMenuItem.Caption = '-' then Continue;
408      Inc(NumMenuItems);
409    end;
410
411    // Now fill the items
412    javaField_lclmenu_captions := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmenu_captions', '[Ljava/lang/String;');
413//    javaObject_lclmenu_captions := javaEnvRef^^.GetObjectField(javaEnvRef, javaActivityClass, javaField_lclmenu_captions);
414    javaObject_lclmenu_captions := javaEnvRef^^.NewObjectArray(javaEnvRef, NumMenuItems,
415      javaJavaLangStringClass, javaEnvRef^^.NewStringUTF(javaEnvRef, ''));
416//     DebugLn(Format('LCLOnMenuAction lclmenu_captions field=%x object=%x', [PtrUInt(javaField_lclmenu_captions), PtrUInt(javaObject_lclmenu_captions)]));
417
418    CurIndex := 0;
419    StrPas := '';
420    for i := 0 to lMenu.Items.Count-1 do
421    begin
422      DebugLn(Format('LCLOnMenuAction item=%d', [i]));
423      lMenuItem := lMenu.Items[i];
424      // Various things might make a menu item invalid and therefore not part of the list
425      if not lMenuItem.Visible then Continue;
426      if lMenuItem.Caption = '-' then Continue;
427
428      StrPas := lMenuItem.Caption;
429      Str := PChar(StrPas);
430      lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, Str);
431      DebugLn(Format('LCLOnMenuAction lJavaString=%x Str=%s javaObject_lclmenu_captions=%x', [PtrUInt(lJavaString), StrPas, PtrUInt(javaObject_lclmenu_captions)]));
432      javaEnvRef^^.SetObjectArrayElement(javaEnvRef, javaObject_lclmenu_captions, CurIndex, lJavaString);
433      javaEnvRef^^.DeleteLocalRef(javaEnvRef, lJavaString);
434
435      Inc(CurIndex);
436
437      if CurIndex >= NumMenuItems then Break;
438    end;
439
440    javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, javaField_lclmenu_captions, javaObject_lclmenu_captions);
441    javaEnvRef^^.DeleteLocalRef(javaEnvRef, javaObject_lclmenu_captions);
442  end
443  // kind=1 means a button click event
444  else
445  begin
446    // Searched for the clicked item
447    CurIndex := 0;
448    for i := 0 to lMenu.Items.Count-1 do
449    begin
450      lMenuItem := lMenu.Items[i];
451      // Various things might make a menu item invalid and therefore not part of the list
452      if not lMenuItem.Visible then Continue;
453      if lMenuItem.Caption = '-' then Continue;
454
455      if itemIndex = CurIndex then Break;
456
457      Inc(CurIndex);
458    end;
459
460    lMenuItem.Click();
461  end;
462
463  // This sends messages like Invalidate requests
464  Result := eventResult;
465  DebugLn('Fim');
466end;
467
468const NativeMethods: array[0..8] of JNINativeMethod=
469  ((name:'LCLDrawToBitmap';
470    signature:'(IILandroid/graphics/Bitmap;)I';
471    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLDrawToBitmap;),
472   (name:'LCLOnTouch';
473    signature:'(FFI)I';
474    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnTouch;),
475   (name:'LCLOnCreate';
476    signature:'(Landroid/app/Activity;)I'; // Don't use a name which includes the package name like com/pascal/lcltest/LCLActivity;
477    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnCreate;),
478   (name:'LCLOnMessageBoxFinished';
479    signature:'(II)I';
480    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnMessageBoxFinished;),
481   (name:'LCLOnKey';
482    signature:'(IILandroid/view/KeyEvent;I)I';
483    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnKey;),
484   (name:'LCLOnTimer';
485    signature:'(Ljava/lang/Runnable;I)I';
486    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnTimer;),
487   (name:'LCLOnConfigurationChanged';
488    signature:'(II)I';
489    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnConfigurationChanged;),
490   (name:'LCLOnSensorChanged';
491    signature:'(I[D)I';
492    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnSensorChanged;),
493   (name:'LCLOnMenuAction';
494    signature:'(II)I';
495    fnPtr:@Java_com_pascal_lclproject_LCLActivity_LCLOnMenuAction;)
496  );
497
498function JNI_OnLoad(vm:PJavaVM;reserved:pointer):jint; cdecl;
499begin
500  javaVMRef := vm;
501
502  __android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad called');
503{  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm=%x', [PtrInt(vm)])));
504  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^=%x', [PtrInt(vm^)])));
505  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^^.reserved0=%x', [PtrInt(vm^^.reserved0)])));
506  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(Format('vm^^.GetEnv=%x', [PtrInt(Pointer(@vm^^.GetEnv))])));  }
507  {
508    vm^^.GetEnv crashes HTC Wildfire, Alcatel and the Emulator if you don't build your project with -CpARMV6
509    see: http://groups.google.com/group/android-ndk/browse_thread/thread/ba542483f062a828/ef9077617794e0f5
510  }
511  if vm^^.GetEnv(vm,@javaEnvRef,JNI_VERSION_1_4)<>JNI_OK then
512  begin
513    __android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'curVM^.GetEnv failed');
514    Exit(JNI_ERR);
515  end;
516
517  // Find our activity class
518  __android_log_write(ANDROID_LOG_INFO,'lclapp','Reading our Activity Class');
519  javaActivityClass := javaEnvRef^^.FindClass(javaEnvRef, PChar(CDWidgetset.ActivityClassName));
520  if not assigned(javaActivityClass) then
521  begin
522    __android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.FindClass failed');
523    Exit(JNI_ERR);
524  end;
525  // Now other classes
526  javaAndroidAppActivityClass := javaEnvRef^^.FindClass(javaEnvRef,'android/app/Activity');
527  javaJavaLangSystemClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/System');
528  javaAndroidOSBuildClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Build');
529  javaAndroidOSVibratorClass := javaEnvRef^^.FindClass(javaEnvRef,'android/os/Vibrator');
530  javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
531  javaJavaLangStringClass := javaEnvRef^^.FindClass(javaEnvRef,'java/lang/String');
532  javaAndroidOSBuildVERSIONClass := javaEnvRef^^.FindClass(javaEnvRef, 'android/os/Build$VERSION');
533
534  // Register Pascal exported calls
535  if javaEnvRef^^.RegisterNatives(javaEnvRef, javaActivityClass, @NativeMethods[0],length(NativeMethods))<0 then
536  begin
537    __android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.RegisterNatives failed');
538    // Exit(JNI_ERR); Don't exit if exporting the native method fails because it works without this too
539  end;
540
541  // Read all field IDs
542  JavaField_lcltext := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltext', 'Ljava/lang/String;');
543  JavaField_lcltitle := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltitle', 'Ljava/lang/String;');
544  JavaField_lclbutton1str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton1str', 'Ljava/lang/String;');
545  JavaField_lclbutton2str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton2str', 'Ljava/lang/String;');
546  JavaField_lclbutton3str := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton3str', 'Ljava/lang/String;');
547  //
548  JavaField_lclwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclwidth', 'I');
549  JavaField_lclheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclheight', 'I');
550  JavaField_lclbutton1 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton1', 'I');
551  JavaField_lclbutton2 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton2', 'I');
552  JavaField_lclbutton3 := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbutton3', 'I');
553  JavaField_lclbitmap := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclbitmap', 'Landroid/graphics/Bitmap;');
554  JavaField_lcltextsize := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextsize', 'I');
555  // Text metrics
556  javaField_lcltextascent := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextascent', 'I');
557  javaField_lcltextbottom := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextbottom', 'I');
558  javaField_lcltextdescent := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextdescent', 'I');
559  javaField_lcltextleading := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltextleading', 'I');
560  javaField_lcltexttop := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltexttop', 'I');
561  javaField_lclmaxwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmaxwidth', 'I');
562  javaField_lclmaxcount := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclmaxcount', 'I');
563  javaField_lclpartialwidths := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclpartialwidths', '[F');
564  // Timer
565  javaField_lcltimerinterval := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltimerinterval', 'I');
566  javaField_lcltimerid := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcltimerid', 'Ljava/lang/Runnable;');
567  // Screen Metrics
568  javaField_lclxdpi := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclxdpi', 'I');
569  javaField_lclydpi := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclydpi', 'I');
570  javaField_lclformwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclformwidth', 'I');
571  javaField_lclformheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclformheight', 'I');
572  javaField_lclscreenwidth := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclscreenwidth', 'I');
573  javaField_lclscreenheight := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclscreenheight', 'I');
574  // For LazDeviceAPIs
575  javaField_lcldestination := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lcldestination', 'Ljava/lang/String;');
576  javaField_lclkind := javaEnvRef^^.GetFieldID(javaEnvRef, javaActivityClass, 'lclkind', 'I');
577  //
578  if not assigned(JavaField_lcltext) then
579  begin
580    __android_log_write(ANDROID_LOG_FATAL, 'lclapp', 'javaEnvRef^.GetFieldID failed for lcltext');
581    Exit(JNI_ERR);
582  end;
583
584  // Read all method IDs
585  javaMethod_LCLDoGetTextBounds := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoGetTextBounds', '()V');
586  javaMethod_LCLDoGetTextPartialWidths := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoGetTextPartialWidths', '()V');
587  javaMethod_LCLDoDrawText := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoDrawText', '(I)V');
588  javaMethod_LCLDoShowMessageBox := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoShowMessageBox', '()V');
589  javaMethod_LCLDoCreateTimer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoCreateTimer', '()V');
590  javaMethod_LCLDoDestroyTimer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoDestroyTimer', '()V');
591  javaMethod_LCLDoHideVirtualKeyboard := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoHideVirtualKeyboard', '()V');
592  javaMethod_LCLDoShowVirtualKeyboard := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoShowVirtualKeyboard', '()V');
593  javaMethod_LCLDoStartReadingAccelerometer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoStartReadingAccelerometer', '()V');
594  javaMethod_LCLDoStopReadingAccelerometer := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoStopReadingAccelerometer', '()V');
595  javaMethod_LCLDoSendMessage := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoSendMessage', '()V');
596  javaMethod_LCLDoRequestPositionInfo := javaEnvRef^^.GetMethodID(javaEnvRef, javaActivityClass, 'LCLDoRequestPositionInfo', '()V');
597  // Methods from android.app.Activity
598  javaMethod_Activity_finish := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidAppActivityClass, 'finish', '()V');
599  // Methods from java.lang.System
600  javaMethod_System_exit := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaJavaLangSystemClass, 'exit', '(I)V');
601  // Generic methods from Context
602  javaMethod_getSystemService := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getSystemService', '(Ljava/lang/String;)Ljava/lang/Object;');
603
604  // Read the SDK Version and store it
605  javaField_VERSION_SDK_INT := javaEnvRef^^.GetStaticFieldID(javaEnvRef, javaAndroidOSBuildVERSIONClass, 'SDK_INT', 'I');
606  android_os_Build_VERSION_SDK_INT := javaEnvRef^^.GetStaticIntField(javaEnvRef, javaAndroidOSBuildVERSIONClass, javaField_VERSION_SDK_INT);
607
608  __android_log_write(ANDROID_LOG_INFO, 'lclapp', 'JNI_OnLoad finished');
609  result:=JNI_VERSION_1_4;// 1_6 is another option
610end;
611
612procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer); cdecl;
613begin
614end;
615
616{$IFnDEF WithOldDebugln}
617procedure TCDWidgetSet.AndroidDebugLn(ASender: TObject; AStr: string; var AHandled: Boolean;
618  Target: TLazLoggerWriteTarget; Data: Pointer);
619begin
620  AHandled := Target in [lwtStdOut, lwtStdErr];
621  if not AHandled then exit;
622  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(AccumulatedStr+AStr));
623  AccumulatedStr := '';
624end;
625{$ELSE}
626procedure TCDWidgetSet.AndroidDebugLn(AStr: string);
627begin
628  __android_log_write(ANDROID_LOG_INFO, 'lclapp', PChar(AccumulatedStr+AStr));
629  AccumulatedStr := '';
630end;
631{$ENDIF}
632
633function TCDWidgetSet.AndroidKeyCodeToLCLKeyCode(AAndroidKeyCode: Integer): Word;
634var
635  lExtendedKeysSupport: Boolean;
636begin
637  lExtendedKeysSupport := Application.ExtendedKeysSupport;
638
639  case AAndroidKeyCode of
640    // First keys which are defined in NDK too
641{    KEYCODE_SOFT_LEFT = 1;
642    KEYCODE_SOFT_RIGHT = 2;
643    KEYCODE_HOME = 3;}
644    KEYCODE_BACK: Result := VK_ESCAPE;
645    KEYCODE_CALL: Result := VK_LCL_CALL;
646    KEYCODE_ENDCALL: Result := VK_LCL_ENDCALL;
647    KEYCODE_0: Result := VK_0;
648    KEYCODE_1: Result := VK_1;
649    KEYCODE_2: Result := VK_2;
650    KEYCODE_3: Result := VK_3;
651    KEYCODE_4: Result := VK_4;
652    KEYCODE_5: Result := VK_5;
653    KEYCODE_6: Result := VK_6;
654    KEYCODE_7: Result := VK_7;
655    KEYCODE_8: Result := VK_8;
656    KEYCODE_9: Result := VK_9;
657{   KEYCODE_STAR = 17;
658    KEYCODE_POUND = 18;}
659    KEYCODE_DPAD_UP:     Result := VK_UP;
660    KEYCODE_DPAD_DOWN:   Result := VK_DOWN;
661    KEYCODE_DPAD_LEFT:   Result := VK_LEFT;
662    KEYCODE_DPAD_RIGHT:  Result := VK_RIGHT;
663    KEYCODE_DPAD_CENTER: Result := VK_RETURN;
664    KEYCODE_VOLUME_UP:   Result := VK_VOLUME_UP;
665    KEYCODE_VOLUME_DOWN: Result := VK_VOLUME_DOWN;
666    KEYCODE_POWER: Result := VK_LCL_POWER;
667//    KEYCODE_CAMERA = 27;}
668    KEYCODE_CLEAR: Result := VK_CLEAR;
669    KEYCODE_A: Result := VK_A;
670    KEYCODE_B: Result := VK_B;
671    KEYCODE_C: Result := VK_C;
672    KEYCODE_D: Result := VK_D;
673    KEYCODE_E: Result := VK_E;
674    KEYCODE_F: Result := VK_F;
675    KEYCODE_G: Result := VK_G;
676    KEYCODE_H: Result := VK_H;
677    KEYCODE_I: Result := VK_I;
678    KEYCODE_J: Result := VK_J;
679    KEYCODE_K: Result := VK_K;
680    KEYCODE_L: Result := VK_L;
681    KEYCODE_M: Result := VK_M;
682    KEYCODE_N: Result := VK_N;
683    KEYCODE_O: Result := VK_O;
684    KEYCODE_P: Result := VK_P;
685    KEYCODE_Q: Result := VK_Q;
686    KEYCODE_R: Result := VK_R;
687    KEYCODE_S: Result := VK_S;
688    KEYCODE_T: Result := VK_T;
689    KEYCODE_U: Result := VK_U;
690    KEYCODE_V: Result := VK_V;
691    KEYCODE_W: Result := VK_W;
692    KEYCODE_X: Result := VK_X;
693    KEYCODE_Y: Result := VK_Y;
694    KEYCODE_Z: Result := VK_Z;
695    KEYCODE_COMMA:  Result := VK_LCL_COMMA;
696    KEYCODE_PERIOD: Result := VK_LCL_POINT;
697    KEYCODE_ALT_LEFT:   if lExtendedKeysSupport then Result := VK_LMENU else Result := VK_MENU;
698    KEYCODE_ALT_RIGHT:  if lExtendedKeysSupport then Result := VK_RMENU else Result := VK_MENU;
699    KEYCODE_SHIFT_LEFT: if lExtendedKeysSupport then Result := VK_LSHIFT else Result := VK_SHIFT;
700    KEYCODE_SHIFT_RIGHT:if lExtendedKeysSupport then Result := VK_RSHIFT else Result := VK_SHIFT;
701    KEYCODE_TAB: Result := VK_TAB;
702    KEYCODE_SPACE: Result := VK_SPACE;
703{    KEYCODE_SYM = 63;
704    KEYCODE_EXPLORER = 64;
705    KEYCODE_ENVELOPE = 65;}
706    KEYCODE_ENTER: Result := VK_RETURN;
707    KEYCODE_DEL:   Result := VK_BACK; // The "Backspace" key
708    KEYCODE_GRAVE: Result := VK_LCL_TILDE;
709    KEYCODE_MINUS: Result := VK_LCL_MINUS;
710    KEYCODE_EQUALS:Result := VK_LCL_EQUAL;
711    KEYCODE_LEFT_BRACKET:  Result := VK_LCL_OPEN_BRAKET;
712    KEYCODE_RIGHT_BRACKET: Result := VK_LCL_CLOSE_BRAKET;
713    KEYCODE_BACKSLASH:     Result := VK_LCL_BACKSLASH;
714    KEYCODE_SEMICOLON:     Result := VK_LCL_SEMI_COMMA;
715    KEYCODE_APOSTROPHE:    Result := VK_LCL_QUOTE;
716    KEYCODE_SLASH: Result := VK_LCL_SLASH;
717    KEYCODE_AT:    Result := VK_LCL_AT;
718{    KEYCODE_NUM = 78;
719    KEYCODE_HEADSETHOOK = 79; // Headset Hook key. Used to hang up calls and stop media.
720    KEYCODE_FOCUS = 80;  // *Camera* focus
721    KEYCODE_PLUS = 81;}
722    KEYCODE_MENU: Result := VK_MENU;
723{    KEYCODE_NOTIFICATION = 83;
724    KEYCODE_SEARCH = 84;
725    KEYCODE_MEDIA_PLAY_PAUSE = 85;
726    KEYCODE_MEDIA_STOP = 86;
727    KEYCODE_MEDIA_NEXT = 87;
728    KEYCODE_MEDIA_PREVIOUS = 88;
729    KEYCODE_MEDIA_REWIND = 89;
730    KEYCODE_MEDIA_FAST_FORWARD = 90;
731    KEYCODE_MUTE = 91;}
732    KEYCODE_PAGE_UP: Result := VK_NEXT;
733    KEYCODE_PAGE_DOWN: Result := VK_PRIOR;
734{    KEYCODE_PICTSYMBOLS = 94;
735    KEYCODE_SWITCH_CHARSET = 95;
736    KEYCODE_BUTTON_A = 96;
737    KEYCODE_BUTTON_B = 97;
738    KEYCODE_BUTTON_C = 98;
739    KEYCODE_BUTTON_X = 99;
740    KEYCODE_BUTTON_Y = 100;
741    KEYCODE_BUTTON_Z = 101;
742    KEYCODE_BUTTON_L1 = 102;
743    KEYCODE_BUTTON_R1 = 103;
744    KEYCODE_BUTTON_L2 = 104;
745    KEYCODE_BUTTON_R2 = 105;
746    KEYCODE_BUTTON_THUMBL = 106;
747    KEYCODE_BUTTON_THUMBR = 107;
748    KEYCODE_BUTTON_START = 108;
749    KEYCODE_BUTTON_SELECT = 109;
750    KEYCODE_BUTTON_MODE = 110;}
751
752    // Now keys from the SDK
753
754    {KEYCODE_3D_MODE = $000000ce; // 3D Mode key. Toggles the display between 2D and 3D mode.
755    KEYCODE_APP_SWITCH = $000000bb;
756    KEYCODE_AVR_INPUT = $000000b6;
757    KEYCODE_AVR_POWER = $000000b5;
758    KEYCODE_BOOKMARK = $000000ae;}
759    KEYCODE_BREAK: Result := VK_PAUSE;
760{    KEYCODE_BUTTON_1 = $000000bc;
761    KEYCODE_BUTTON_10 = $000000c5;
762    KEYCODE_BUTTON_11 = $000000c6;
763    KEYCODE_BUTTON_12 = $000000c7;
764    KEYCODE_BUTTON_13 = $000000c8;
765    KEYCODE_BUTTON_14 = $000000c9;
766    KEYCODE_BUTTON_15 = $000000ca;
767    KEYCODE_BUTTON_16 = $000000cb; // Generic Game Pad Button #16.
768    KEYCODE_BUTTON_2 = $000000bd; // Generic Game Pad Button #2.
769    KEYCODE_BUTTON_3 = $000000be;
770    KEYCODE_BUTTON_4 = $000000bf;
771    KEYCODE_BUTTON_5 = $000000c0;
772    KEYCODE_BUTTON_6 = $000000c1;
773    KEYCODE_BUTTON_7 = $000000c2;
774    KEYCODE_BUTTON_8 = $000000c3;
775    KEYCODE_BUTTON_9 = $000000c4; // Generic Game Pad Button #9.
776    KEYCODE_CALCULATOR = $000000d2; // Calculator special function key. Used to launch a calculator application.
777    KEYCODE_CALENDAR = $000000d0; // Calendar special function key. Used to launch a calendar application.}
778    KEYCODE_CAPS_LOCK: Result := VK_CAPITAL;
779{    KEYCODE_CAPTIONS = $000000af; // Toggle captions key. Switches the mode for closed-captioning text, for example during television shows.
780    KEYCODE_CHANNEL_DOWN = $000000a7; // Channel down key. On TV remotes, decrements the television channel.
781    KEYCODE_CHANNEL_UP = $000000a6; // Channel up key. On TV remotes, increments the television channel.
782    KEYCODE_CONTACTS = $000000cf; // Contacts special function key. Used to launch an address book application.
783    KEYCODE_CTRL_LEFT = $00000071; // Left Control modifier key.
784    KEYCODE_CTRL_RIGHT = $00000072; // Right Control modifier key.
785    KEYCODE_DVR = $000000ad; // DVR key. On some TV remotes, switches to a DVR mode for recorded shows.
786    KEYCODE_ENTER = $00000042; // Enter key.
787    KEYCODE_ENVELOPE = $00000041; // Envelope special function key. Used to launch a mail application.
788    KEYCODE_EQUALS = $00000046; // '=' key.
789    KEYCODE_ESCAPE = $0000006f; // Escape key.
790    KEYCODE_EXPLORER = $00000040; // Explorer special function key. Used to launch a browser application.
791    KEYCODE_F1 = $00000083;
792    KEYCODE_F10 = $0000008c;
793    KEYCODE_F11 = $0000008d;
794    KEYCODE_F12 = $0000008e;
795    KEYCODE_F2 = $00000084;
796    KEYCODE_F3 = $00000085;
797    KEYCODE_F4 = $00000086;
798    KEYCODE_F5 = $00000087;
799    KEYCODE_F6 = $00000088;
800    KEYCODE_F7 = $00000089;
801    KEYCODE_F8 = $0000008a;
802    KEYCODE_F9 = $0000008b;
803    KEYCODE_FORWARD = $0000007d; // Forward key. Navigates forward in the history stack. Complement of KEYCODE_BACK.}
804    KEYCODE_FORWARD_DEL: Result := VK_DELETE;
805{    KEYCODE_FUNCTION = $00000077; // Function modifier key.
806    KEYCODE_GUIDE = $000000ac; // Guide key. On TV remotes, shows a programming guide.
807    KEYCODE_INFO = $000000a5; // Info key. Common on TV remotes to show additional information related to what is currently being viewed.}
808    KEYCODE_INSERT:      Result := VK_INSERT;
809{    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.
810    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.
811    KEYCODE_MEDIA_CLOSE = $00000080; // Close media key. May be used to close a CD tray, for example.
812    KEYCODE_MEDIA_EJECT = $00000081; // Eject media key. May be used to eject a CD tray, for example.
813    KEYCODE_MEDIA_PAUSE = $0000007f; // Pause media key.
814    KEYCODE_MEDIA_PLAY = $0000007e; // Play media key.
815    KEYCODE_MEDIA_RECORD = $00000082; // Record media key.}
816    KEYCODE_META_LEFT:  Result := VK_LWIN;
817    KEYCODE_META_RIGHT: Result := VK_RWIN;
818{    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.
819    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.
820    KEYCODE_MUSIC = $000000d1; // Music special function key. Used to launch a music player application.}
821    KEYCODE_NUMPAD_0: Result := VK_NUMPAD0;
822    KEYCODE_NUMPAD_1: Result := VK_NUMPAD1;
823    KEYCODE_NUMPAD_2: Result := VK_NUMPAD2;
824    KEYCODE_NUMPAD_3: Result := VK_NUMPAD3;
825    KEYCODE_NUMPAD_4: Result := VK_NUMPAD4;
826    KEYCODE_NUMPAD_5: Result := VK_NUMPAD5;
827    KEYCODE_NUMPAD_6: Result := VK_NUMPAD6;
828    KEYCODE_NUMPAD_7: Result := VK_NUMPAD7;
829    KEYCODE_NUMPAD_8: Result := VK_NUMPAD8;
830    KEYCODE_NUMPAD_9: Result := VK_NUMPAD9;
831    KEYCODE_NUMPAD_ADD:        Result := VK_ADD;
832    //KEYCODE_NUMPAD_COMMA:      Result := $0000009f;
833    KEYCODE_NUMPAD_DIVIDE:     Result := VK_DIVIDE;
834    KEYCODE_NUMPAD_DOT:        Result := VK_DECIMAL;
835    KEYCODE_NUMPAD_ENTER:      Result := VK_RETURN;
836    //KEYCODE_NUMPAD_EQUALS:     Result := VK_LCL_EQUAL;
837    //KEYCODE_NUMPAD_LEFT_PAREN: Result := $000000a2;
838    KEYCODE_NUMPAD_MULTIPLY:   Result := VK_MULTIPLY;
839    //KEYCODE_NUMPAD_RIGHT_PAREN:Result := $000000a3;
840    KEYCODE_NUMPAD_SUBTRACT:   Result := VK_LCL_MINUS;
841    KEYCODE_NUM_LOCK:          Result := VK_NUMLOCK;
842    {KEYCODE_PROG_BLUE = $000000ba;
843    KEYCODE_PROG_GREEN = $000000b8;
844    KEYCODE_PROG_RED = $000000b7;
845    KEYCODE_PROG_YELLOW = $000000b9;}
846    KEYCODE_SCROLL_LOCK: Result := VK_SCROLL;
847{    KEYCODE_SETTINGS = $000000b0;
848    KEYCODE_STB_INPUT = $000000b4;
849    KEYCODE_STB_POWER = $000000b3;}
850    KEYCODE_SYSRQ:       Result := VK_PRINT;
851{    KEYCODE_TV = $000000aa;
852    KEYCODE_TV_INPUT = $000000b2;
853    KEYCODE_TV_POWER = $000000b1;}
854    KEYCODE_VOLUME_MUTE: Result := VK_VOLUME_MUTE;
855    {KEYCODE_WINDOW = $000000ab;
856    KEYCODE_ZOOM_IN = $000000a8;
857    KEYCODE_ZOOM_OUT = $000000a9; }
858  else
859    Result := 0;
860  end;
861end;
862
863function TCDWidgetSet.DoOpenURLWidgetsetImplementation(AURL: string): Boolean;
864var
865  // Java IDs
866  javaAndroidContentContextClass: JClass;
867  javaAndroidNetUriClass: JClass;
868  javaMethod_Uri_fromParts: jmethodid = nil;
869  // Java Object instances
870  lJavaString, lJavaString2: jstring;
871  lJavaFileObject: JObject;
872  lJavaURIObject: JObject;
873  // array for the parameters
874  lParams: array[0..2] of JValue;
875  //
876  lURLProtocol, lURLAfterDoublePoint: string;
877  lDoublePointPos: SizeInt;
878begin
879  Result := True;
880
881  lDoublePointPos := Pos(':', AURL);
882  lURLProtocol := Copy(AURL, 1, lDoublePointPos-1);
883  lURLAfterDoublePoint := Copy(AURL, lDoublePointPos+1, Length(AURL));
884  DebugLn(Format('[DoOpenURLWidgetsetImplementation] AURL=%s lURLProtocol=%s lURLAfterDoublePoint=%s',
885    [AURL, lURLProtocol, lURLAfterDoublePoint]));
886
887  // First IDs
888  javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
889  javaAndroidNetUriClass := javaEnvRef^^.FindClass(javaEnvRef,'android/net/Uri');
890
891  javaMethod_Uri_fromParts := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaAndroidNetUriClass, 'fromParts', '(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;');
892
893  // Uri uri = Uri.fromParts("file", "dest", null);
894  lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(lURLProtocol));
895  lParams[0].l := lJavaString;
896  lJavaString2 := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(lURLAfterDoublePoint));
897  lParams[1].l := lJavaString2;
898  lParams[2].l := nil;
899  lJavaURIObject := javaEnvRef^^.CallStaticObjectMethodA(javaEnvRef, javaAndroidNetUriClass, javaMethod_Uri_fromParts, @lParams[0]);
900
901  Result := DoOpenAndroidURI(lJavaURIObject, 'text/html');
902end;
903
904function TCDWidgetSet.DoOpenDocumentWidgetsetImplementation(APath: string): Boolean;
905var
906  // Java IDs
907  javaAndroidContentContextClass: JClass;
908  javaAndroidNetUriClass: JClass;
909  javaJavaIoFileClass: JClass;
910  javaMethod_Uri_fromFile: jmethodid = nil;
911  javaMethod_File_new: jmethodid = nil;
912  // Java Object instances
913  lJavaString: jstring;
914  lJavaFileObject: JObject;
915  lJavaURIObject: JObject;
916  // array for the parameters
917  lParams: array[0..2] of JValue;
918  //
919begin
920  Result := False;
921
922  if (javaEnvRef = nil) then Exit;
923
924  // First IDs
925  javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
926  javaAndroidNetUriClass := javaEnvRef^^.FindClass(javaEnvRef,'android/net/Uri');
927  javaJavaIoFileClass := javaEnvRef^^.FindClass(javaEnvRef,'java/io/File');
928
929  javaMethod_Uri_fromFile := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaAndroidNetUriClass, 'fromFile', '(Ljava/io/File;)Landroid/net/Uri;');
930  javaMethod_File_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaJavaIoFileClass, '<init>', '(Ljava/lang/String;)V');
931
932  // File file = new File("/sdcard/test.mp4");
933  lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(APath));
934  lParams[0].l := lJavaString;
935  lJavaFileObject := javaEnvRef^^.NewObjectA(javaEnvRef, javaJavaIoFileClass, javaMethod_File_new, @lParams[0]);
936
937  // Uri uri = Uri.fromFile(file);
938  DebugLn(Format('[DoOpenDocumentWidgetsetImplementation] APath=%s lJavaFileObject=%x', [APath, PtrInt(lJavaFileObject)]));
939  lParams[0].l := lJavaFileObject;
940  lJavaURIObject := javaEnvRef^^.CallStaticObjectMethodA(javaEnvRef, javaAndroidNetUriClass, javaMethod_Uri_fromFile, @lParams[0]);
941
942  Result := DoOpenAndroidURI(lJavaURIObject, GetMimeTypeFromFileName(APath));
943end;
944
945function TCDWidgetSet.DoOpenAndroidURI(AURI: JObject; AMimeType: string): Boolean;
946var
947  // Java IDs
948  javaAndroidContentContextClass: JClass;
949  javaAndroidContentIntentClass: JClass;
950  javaAndroidContentPmPackageManagerClass: JClass;
951  javaAndroidAppActivityClass: JClass;
952  javaJavaUtilListClass: JClass;
953  javaMethod_Intent_new: jmethodid = nil;
954  javaMethod_Intent_setDataAndType: jmethodid = nil;
955  javaMethod_Context_getPackageManager: jmethodid = nil;
956  javaMethod_PmPackageManager_queryIntentActivities: jmethodid = nil;
957  javaMethod_Activity_startActivity: jmethodid = nil;
958  javaMethod_List_size: JMethodID = nil;
959  // Java Object instances
960  lJavaString: jstring;
961  javaViewDocObject: JObject;
962  lJavaPackageManagerObject: JObject;
963  lJavaListObject: JObject;
964  lJavaArray: JArray;
965  lJavaInt: JInt;
966  // array for the parameters
967  lParams: array[0..1] of JValue;
968  //
969begin
970  Result := False;
971
972  if (javaEnvRef = nil) then Exit;
973
974  // First IDs
975  DebugLn(Format(':>[DoOpenAndroidURI] AURI=%x', [PtrInt(AURI)]));
976  javaAndroidContentContextClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Context');
977  javaAndroidContentIntentClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/Intent');
978  javaAndroidContentPmPackageManagerClass := javaEnvRef^^.FindClass(javaEnvRef,'android/content/pm/PackageManager');
979  javaAndroidAppActivityClass := javaEnvRef^^.FindClass(javaEnvRef,'android/app/Activity');
980  javaJavaUtilListClass := javaEnvRef^^.FindClass(javaEnvRef,'java/util/List');
981
982  javaMethod_Intent_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentIntentClass, '<init>', '(Ljava/lang/String;)V');
983  javaMethod_Intent_setDataAndType := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentIntentClass, 'setDataAndType', '(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;');
984  javaMethod_Context_getPackageManager := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentContextClass, 'getPackageManager', '()Landroid/content/pm/PackageManager;');
985  javaMethod_PmPackageManager_queryIntentActivities := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidContentPmPackageManagerClass, 'queryIntentActivities', '(Landroid/content/Intent;I)Ljava/util/List;');
986  javaMethod_Activity_startActivity := javaEnvRef^^.GetMethodID(javaEnvRef, javaAndroidAppActivityClass, 'startActivity', '(Landroid/content/Intent;)V');
987  javaMethod_List_size := javaEnvRef^^.GetMethodID(javaEnvRef, javaJavaUtilListClass, 'size', '()I');
988
989  // Intent viewDoc = new Intent(Intent.ACTION_VIEW);
990  lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, javaConstant_Intent_ACTION_VIEW);
991  lParams[0].l := lJavaString;
992  javaViewDocObject := javaEnvRef^^.NewObjectA(javaEnvRef, javaAndroidContentIntentClass, javaMethod_Intent_new, @lParams[0]);
993
994  // viewDoc.setDataAndType(uri, "application/pdf");
995  lParams[0].l := AURI;
996  lJavaString := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(AMimeType));
997  lParams[1].l := lJavaString;
998  javaEnvRef^^.CallObjectMethodA(javaEnvRef, javaViewDocObject, javaMethod_Intent_setDataAndType, @lParams[0]);
999
1000  // PackageManager pm = this.getPackageManager();
1001  lJavaPackageManagerObject := javaEnvRef^^.CallObjectMethod(javaEnvRef, javaActivityObject, javaMethod_Context_getPackageManager);
1002
1003  // List<ResolveInfo> apps = pm.queryIntentActivities(viewDoc, PackageManager.MATCH_DEFAULT_ONLY);
1004  lParams[0].l := javaViewDocObject;
1005  lParams[1].i := javaConstant_PackageManager_MATCH_DEFAULT_ONLY;
1006  lJavaListObject := javaEnvRef^^.CallObjectMethodA(javaEnvRef, lJavaPackageManagerObject, javaMethod_PmPackageManager_queryIntentActivities, @lParams[0]);
1007
1008  // int lSize = apps.size()
1009  lJavaInt := javaEnvRef^^.CallIntMethod(javaEnvRef, lJavaListObject, javaMethod_List_size);
1010
1011  // if (lSize > 0) this.startActivity(viewDoc);
1012  if lJavaInt > 0 then
1013  begin
1014    lParams[0].l := javaViewDocObject;
1015    javaEnvRef^^.CallVoidMethodA(javaEnvRef, javaActivityObject, javaMethod_Activity_startActivity, @lParams[0]);
1016    Result := True;
1017    DebugLn(':<[DoOpenAndroidURI] Success');
1018  end
1019  else
1020    DebugLn(':<[DoOpenAndroidURI] There are no activities registered for the mimetype ' + AMimeType);
1021end;
1022
1023function TCDWidgetSet.GetMimeTypeFromFileName(AFileName: string): string;
1024var
1025  lExt: String;
1026begin
1027  lExt := SysUtils.ExtractFileExt(AFileName);
1028  // First the most common formats
1029  if AnsiCompareText(lExt, '.png') = 0 then Result := 'image/png'
1030  else if AnsiCompareText(lExt, '.txt') = 0 then Result := 'text/plain'
1031  else if AnsiCompareText(lExt, '.jpg') = 0 then Result := 'image/jpeg'
1032  else if AnsiCompareText(lExt, '.jpeg') = 0 then Result := 'image/jpeg'
1033  else if AnsiCompareText(lExt, '.pdf') = 0 then Result := 'application/pdf'
1034  else if AnsiCompareText(lExt, '.xml') = 0 then Result := 'application/xml'
1035  else if AnsiCompareText(lExt, '.svg') = 0 then Result := 'image/svg+xml'
1036  else if AnsiCompareText(lExt, '.swf') = 0 then Result := 'application/x-shockwave-flash'
1037  else if AnsiCompareText(lExt, '.htm') = 0 then Result := 'text/html'
1038  else if AnsiCompareText(lExt, '.html') = 0 then Result := 'text/html'
1039  // Now all images
1040  else if AnsiCompareText(lExt, '.xpm') = 0 then Result := 'image/x-xpixmap'
1041  else if AnsiCompareText(lExt, '.gif') = 0 then Result := 'image/gif'
1042  else if AnsiCompareText(lExt, '.tiff') = 0 then Result := 'image/tiff'
1043  else if AnsiCompareText(lExt, '.tif') = 0 then Result := 'image/tiff'
1044  else if AnsiCompareText(lExt, '.ico') = 0 then Result := 'image/x-icon'
1045  else if AnsiCompareText(lExt, '.icns') = 0 then Result := 'image/icns'
1046  else if AnsiCompareText(lExt, '.ppm') = 0 then Result := 'image/x-portable-pixmap'
1047  else if AnsiCompareText(lExt, '.bmp') = 0 then Result := 'image/bmp'
1048  // Now all textual formats
1049  else if AnsiCompareText(lExt, '.pas') = 0 then Result := 'text/plain'
1050  else if AnsiCompareText(lExt, '.pp') = 0 then Result := 'text/plain'
1051  else if AnsiCompareText(lExt, '.inc') = 0 then Result := 'text/plain'
1052  else if AnsiCompareText(lExt, '.c') = 0 then Result := 'text/plain'
1053  else if AnsiCompareText(lExt, '.cpp') = 0 then Result := 'text/plain'
1054  else if AnsiCompareText(lExt, '.java') = 0 then Result := 'text/plain'
1055  else if AnsiCompareText(lExt, '.log') = 0 then Result := 'text/plain'
1056  // Now all videos
1057  else if AnsiCompareText(lExt, '.mp4') = 0 then Result := 'video/*'
1058  else if AnsiCompareText(lExt, '.avi') = 0 then Result := 'video/vnd.avi' // also possible video/x-msvideo
1059  else if AnsiCompareText(lExt, '.mpeg') = 0 then Result := 'video/MPEG'
1060  else if AnsiCompareText(lExt, '.mpg') = 0 then Result := 'video/MPEG'
1061  else if AnsiCompareText(lExt, '.mov') = 0 then Result := 'video/quicktime'
1062  // Now all sounds
1063  else if AnsiCompareText(lExt, '.mp3') = 0 then Result := 'audio/mpeg'
1064  else if AnsiCompareText(lExt, '.ogg') = 0 then Result := 'audio/ogg'
1065  else if AnsiCompareText(lExt, '.wav') = 0 then Result := 'audio/x-wav'
1066  else if AnsiCompareText(lExt, '.mid') = 0 then Result := 'audio/midi'
1067  else if AnsiCompareText(lExt, '.midi') = 0 then Result := 'audio/midi'
1068  else if AnsiCompareText(lExt, '.au') = 0 then Result := 'audio/basic'
1069  else if AnsiCompareText(lExt, '.snd') = 0 then Result := 'audio/basic'
1070  // Now all documents
1071  else if AnsiCompareText(lExt, '.rtf') = 0 then Result := 'text/rtf'
1072  else if AnsiCompareText(lExt, '.eps') = 0 then Result := 'application/Postscript'
1073  else if AnsiCompareText(lExt, '.ps') = 0 then Result := 'application/Postscript'
1074  //
1075  else if AnsiCompareText(lExt, '.xls') = 0 then Result := 'application/vnd.ms-excel'
1076  else if AnsiCompareText(lExt, '.doc') = 0 then Result := 'application/msword'
1077  else if AnsiCompareText(lExt, '.ppt') = 0 then Result := 'application/vnd.ms-powerpoint'
1078  //
1079  else if AnsiCompareText(lExt, '.odt') = 0 then Result := 'application/vnd.oasis.opendocument.text'
1080  else if AnsiCompareText(lExt, '.ods') = 0 then Result := 'application/vnd.oasis.opendocument.spreadsheet'
1081  else if AnsiCompareText(lExt, '.odp') = 0 then Result := 'application/vnd.oasis.opendocument.presentation'
1082  else if AnsiCompareText(lExt, '.odg') = 0 then Result := 'application/vnd.oasis.opendocument.graphics'
1083  else if AnsiCompareText(lExt, '.odc') = 0 then Result := 'application/vnd.oasis.opendocument.chart'
1084  else if AnsiCompareText(lExt, '.odf') = 0 then Result := 'application/vnd.oasis.opendocument.formula'
1085  else if AnsiCompareText(lExt, '.odi') = 0 then Result := 'application/vnd.oasis.opendocument.image'
1086  //
1087  else if AnsiCompareText(lExt, '.xlsx') = 0 then Result := 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
1088  else if AnsiCompareText(lExt, '.pptx') = 0 then Result := 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
1089  else if AnsiCompareText(lExt, '.docx') = 0 then Result := 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
1090  // Now compressed archives
1091  else if AnsiCompareText(lExt, '.zip') = 0 then Result := 'application/zip'
1092  else if AnsiCompareText(lExt, '.tar') = 0 then Result := 'application/x-tar'
1093  // If we can't auto-detect just suppose it is text!
1094  else Result := 'text/plain';
1095end;
1096
1097procedure TCDWidgetSet.ShowListViewDialog(ATitle: string; ATitles,
1098  ADescriptions: array of string;
1099  AColorOddRow: jint = $ff292C29; AColorEvenRow: jint = $ff424542);
1100var
1101  javaClass_LCLActivity, javaClass_String: jclass;
1102  javaMethod_LCLActivity_LCLDoShowListViewDialog: jmethodid;
1103  javaString: jstring;
1104  lParams: array[0..4] of JValue;
1105  lNativeString: PChar;
1106  i: Integer;
1107begin
1108  // Here we call this routine:
1109  // public void LCLDoShowListViewDialog(String ATitle, String[] AItems, String[] ASubItems)
1110  DebugLn(':>ShowListViewDialog');
1111  // First call FindClass for all required classes
1112  javaClass_LCLActivity := javaEnvRef^^.FindClass(javaEnvRef, PChar(CDWidgetset.ActivityClassName));
1113  javaClass_String := javaEnvRef^^.FindClass(javaEnvRef, 'java/lang/String');
1114
1115  // Now all Method IDs
1116  //DebugLn(':ShowListViewDialog 1');
1117  javaMethod_LCLActivity_LCLDoShowListViewDialog := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_LCLACtivity,
1118    'LCLDoShowListViewDialog',
1119    '(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;II)V');
1120
1121  //DebugLn(':ShowListViewDialog 2');
1122  // Create a new instance for the HTTP request object
1123  // HttpGet javaRequest = new HttpGet();
1124  lParams[0].l := javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(ATitle));
1125  lParams[1].l := javaEnvRef^^.NewObjectArray(javaEnvRef, Length(ATitles), javaClass_String, javaEnvRef^^.NewStringUTF(javaEnvRef, ''));
1126  for i := 0 to Length(ATitles)-1 do
1127    javaEnvRef^^.SetObjectArrayElement(javaEnvRef, lParams[1].l, i, javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(ATitles[i])));
1128  lParams[2].l := javaEnvRef^^.NewObjectArray(javaEnvRef, Length(ADescriptions), javaClass_String, javaEnvRef^^.NewStringUTF(javaEnvRef, ''));
1129  for i := 0 to Length(ADescriptions)-1 do
1130    javaEnvRef^^.SetObjectArrayElement(javaEnvRef, lParams[2].l, i, javaEnvRef^^.NewStringUTF(javaEnvRef, PChar(ADescriptions[i])));
1131  lParams[3].i := AColorOddRow;
1132  lParams[4].i := AColorEvenRow;
1133  //
1134  javaEnvRef^^.CallVoidMethodA(javaEnvRef, javaActivityObject,
1135    javaMethod_LCLActivity_LCLDoShowListViewDialog, @lParams[0]);
1136  javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[0].l);
1137  javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[1].l);
1138  javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[2].l);
1139  DebugLn(':<ShowListViewDialog END');
1140end;
1141
1142function TCDWidgetSet.GetAppHandle: THandle;
1143begin
1144  Result := 0;
1145end;
1146
1147{------------------------------------------------------------------------------
1148  Method: TCDWidgetSet.Create
1149  Params:  None
1150  Returns: Nothing
1151
1152  Constructor for the class.
1153 ------------------------------------------------------------------------------}
1154procedure TCDWidgetSet.BackendCreate;
1155begin
1156  // Setup DebugLn
1157  {$IFnDEF WithOldDebugln}
1158  OnWidgetSetDebugLn := @AndroidDebugLn;
1159  OnWidgetSetDbgOut := @AccumulatingDebugOut;
1160  {$ELSE}
1161  DebugLnProc := @AndroidDebugLn;
1162  DebugOutProc := @AccumulatingDebugOut;
1163  {$ENDIF}
1164
1165  {$ifdef CD_UseNativeText}
1166  // Create the dummy screen DC
1167  ScreenBitmapRawImage.Init;
1168  ScreenBitmapHeight := 100;
1169  ScreenBitmapWidth := 100;
1170  ScreenBitmapRawImage.Description.Init_BPP32_A8R8G8B8_BIO_TTB(ScreenBitmapWidth, ScreenBitmapHeight);
1171  ScreenBitmapRawImage.CreateData(True);
1172  ScreenImage := TLazIntfImage.Create(0, 0);
1173  ScreenImage.SetRawImage(ScreenBitmapRawImage);
1174  ScreenDC := TLazCanvas.Create(ScreenImage);
1175
1176  DefaultFontAndroidSize := 16;
1177  {$endif}
1178
1179  // Android support for OpenURL and OpenDocument
1180  LCLIntf.OpenURLWidgetsetImplementation := @DoOpenURLWidgetsetImplementation;
1181  LCLIntf.OpenDocumentWidgetsetImplementation := @DoOpenDocumentWidgetsetImplementation;
1182end;
1183
1184{------------------------------------------------------------------------------
1185  Method: TWinCEWidgetSet.Destroy
1186  Params:  None
1187  Returns: Nothing
1188
1189  destructor for the class.
1190 ------------------------------------------------------------------------------}
1191procedure TCDWidgetSet.BackendDestroy;
1192begin
1193  {$ifdef CD_UseNativeText}
1194  // Free the dummy screen DC
1195  ScreenImage.Free;
1196  ScreenDC.Free;
1197  {$endif}
1198end;
1199
1200{------------------------------------------------------------------------------
1201  Method: TWinCEWidgetSet.AppInit
1202  Params:  None
1203  Returns: Nothing
1204
1205  initialize Windows
1206 ------------------------------------------------------------------------------}
1207procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
1208begin
1209  {$ifdef VerboseCDApplication}
1210  DebugLn('TCDWidgetSet.AppInit');
1211  {$endif}
1212
1213  Forms.MessageBoxFunction := @CDMessageBoxFunction;
1214
1215  if Application.LayoutAdjustmentPolicy = lapDefault then
1216    Application.LayoutAdjustmentPolicy := lapAutoAdjustWithoutHorizontalScrolling;
1217
1218  // Generic
1219  GenericAppInit();
1220end;
1221
1222procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
1223begin
1224  {$ifdef VerboseCDApplication}
1225  DebugLn('TCDWidgetSet.AppRun');
1226  {$endif}
1227end;
1228
1229(*
1230function TWinCEWidgetSet.GetAppHandle: THandle;
1231begin
1232  Result:= FAppHandle;
1233end;
1234
1235procedure TWinCEWidgetSet.SetAppHandle(const AValue: THandle);
1236begin
1237  // Do it only if handle is not yet created (for example for DLL initialization)
1238  // if handle is already created we can't reassign it
1239  if AppHandle = 0 then
1240    FAppHandle := AValue;
1241end;*)
1242
1243{------------------------------------------------------------------------------
1244  Method: TWinCEWidgetSet.AppMinimize
1245  Params:  None
1246  Returns: Nothing
1247
1248  Minimizes the whole application to the taskbar
1249 ------------------------------------------------------------------------------}
1250procedure TCDWidgetSet.AppMinimize;
1251begin
1252  // calling Activity.Free doesnt close the app, only hides it, so it is good for AppMinimize
1253   javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_Activity_finish);
1254end;
1255
1256{------------------------------------------------------------------------------
1257  Method: TWinCEWidgetSet.AppRestore
1258  Params:  None
1259  Returns: Nothing
1260
1261  Restore minimized whole application from taskbar
1262 ------------------------------------------------------------------------------}
1263
1264procedure TCDWidgetSet.AppRestore;
1265begin
1266//  Windows.SendMessage(FAppHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
1267end;
1268
1269
1270{------------------------------------------------------------------------------
1271  Method: TWinCEWidgetSet.AppBringToFront
1272  Params:  None
1273  Returns: Nothing
1274
1275  Brings the entire application on top of all other non-topmost programs
1276 ------------------------------------------------------------------------------}
1277procedure TCDWidgetSet.AppBringToFront;
1278begin
1279end;
1280
1281(*
1282procedure TWinCEWidgetSet.SetDesigning(AComponent: TComponent);
1283begin
1284  //if Data<>nil then EnableWindow((AComponent As TWinControl).Handle, boolean(Data^));
1285end;
1286
1287{------------------------------------------------------------------------------
1288  Method: TWinCEWidgetSet.SetCallback
1289  Params: Msg    - message for which to set a callback
1290          Sender - object to which callback will be sent
1291  Returns:  nothing
1292
1293  Applies a Message to the sender
1294 ------------------------------------------------------------------------------}
1295procedure TWinCEWidgetSet.SetCallback(Msg: LongInt; Sender: TObject);
1296var
1297  Window: HWnd;
1298begin
1299  //DebugLn('Trace:TWinCEWidgetSet.SetCallback - Start');
1300  //DebugLn(Format('Trace:TWinCEWidgetSet.SetCallback - Class Name --> %S', [Sender.ClassName]));
1301  //DebugLn(Format('Trace:TWinCEWidgetSet.SetCallback - Message Name --> %S', [GetMessageName(Msg)]));
1302  if Sender Is TControlCanvas then
1303    Window := TControlCanvas(Sender).Handle
1304  else if Sender Is TCustomForm then
1305    Window := TCustomForm(Sender).Handle
1306  else
1307    Window := TWinControl(Sender).Handle;
1308  if Window=0 then exit;
1309
1310  //DebugLn('Trace:TWinCEWidgetSet.SetCallback - Exit');
1311end;
1312
1313{------------------------------------------------------------------------------
1314  Method: TWinCEWidgetSet.RemoveCallbacks
1315  Params:   Sender - object from which to remove callbacks
1316  Returns:  nothing
1317
1318  Removes Call Back Signals from the sender
1319 ------------------------------------------------------------------------------}
1320procedure TWinCEWidgetSet.RemoveCallbacks(Sender: TObject);
1321var
1322  Window: HWnd;
1323begin
1324  if Sender Is TControlCanvas then
1325    Window := TControlCanvas(Sender).Handle
1326  else if Sender Is TCustomForm then
1327    Window := TCustomForm(Sender).Handle
1328  else
1329    Window := (Sender as TWinControl).Handle;
1330  if Window=0 then exit;
1331end;*)
1332
1333{------------------------------------------------------------------------------
1334  Method: TWinCEWidgetSet.AppProcessMessages
1335  Params:  None
1336  Returns: Nothing
1337
1338  Handle all pending messages
1339 ------------------------------------------------------------------------------}
1340procedure TCDWidgetSet.AppProcessMessages;
1341begin
1342end;
1343(*
1344procedure TWinCEWidgetSet.CheckPipeEvents;
1345var
1346  lHandler: PPipeEventInfo;
1347//  lBytesAvail: dword;
1348//  SomethingChanged: Boolean;
1349  ChangedCount:integer;
1350begin
1351  lHandler := FWaitPipeHandlers;
1352  ChangedCount := 0;
1353  while (lHandler <> nil) and (ChangedCount < 10) do
1354  begin
1355    {
1356    roozbeh : ooops not supported
1357    SomethingChanged:=true;
1358    if Windows.PeekNamedPipe(lHandler^.Handle, nil, 0, nil, @lBytesAvail, nil) then
1359    begin
1360      if lBytesAvail <> 0 then
1361        lHandler^.OnEvent(lHandler^.UserData, [prDataAvailable])
1362      else
1363        SomethingChanged := false;
1364    end else
1365      lHandler^.OnEvent(lHandler^.UserData, [prBroken]);
1366    if SomethingChanged then
1367      lHandler := FWaitPipeHandlers
1368    else begin
1369      lHandler := lHandler^.Next;
1370      ChangedCount := 0;
1371    end;
1372    inc(ChangedCount);}
1373  end;
1374end;*)
1375
1376{------------------------------------------------------------------------------
1377  Method: TWinCEWidgetSet.AppWaitMessage
1378  Params:  None
1379  Returns: Nothing
1380
1381  Passes execution control to Windows
1382 ------------------------------------------------------------------------------}
1383//roozbeh:new update...whole procedure body is added.what is it?
1384procedure TCDWidgetSet.AppWaitMessage;
1385begin
1386end;
1387
1388{------------------------------------------------------------------------------
1389  Method: TCDWidgetSet.AppTerminate
1390  Params:  None
1391  Returns: Nothing
1392
1393  Terminates the application
1394 ------------------------------------------------------------------------------}
1395procedure TCDWidgetSet.AppTerminate;
1396var
1397  lParams: array[0..0] of JValue;
1398begin
1399  DebugLn('[TCDWidgetSet.AppTerminate] Start');
1400
1401  // Call the method
1402  lParams[0].i := 0;
1403  javaEnvRef^^.CallStaticVoidMethodA(javaEnvRef, javaJavaLangSystemClass, javaMethod_System_exit, @lParams[0]);
1404
1405  DebugLn('[TCDWidgetSet.AppTerminate] End');
1406end;
1407
1408procedure TCDWidgetSet.AppSetIcon(const Small, Big: HICON);
1409begin
1410end;
1411
1412procedure TCDWidgetSet.AppSetTitle(const ATitle: string);
1413begin
1414end;
1415
1416procedure TCDWidgetSet.AppSetVisible(const AVisible: Boolean);
1417begin
1418end;
1419
1420function TCDWidgetSet.AppRemoveStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
1421begin
1422end;
1423
1424function TCDWidgetSet.AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
1425begin
1426end;
1427
1428procedure TCDWidgetSet.AppSetMainFormOnTaskBar(const DoSet: Boolean);
1429begin
1430end;
1431
1432{------------------------------------------------------------------------------
1433  function: CreateTimer
1434  Params: Interval:
1435          TimerFunc: Callback
1436  Returns: a Timer id (use this ID to destroy timer)
1437
1438  Design: A timer which calls TimerCallBackProc, is created.
1439    The TimerCallBackProc calls the TimerFunc.
1440 ------------------------------------------------------------------------------}
1441function TCDWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc) : THandle;
1442var
1443  lTimer: TCDTimer;
1444  lTimerObject, lGlobalTimerObject: JObject;
1445begin
1446  lTimer := TCDTimer.Create;
1447
1448  Result := THandle(lTimer);
1449
1450  lTimer.Interval := Interval;
1451  lTimer.TimerFunc := TimerFunc;
1452
1453  // Prepare the input
1454  javaEnvRef^^.SetIntField(javaEnvRef, javaActivityObject, javaField_lcltimerinterval, Interval);
1455
1456  // Call the method
1457  javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoCreateTimer);
1458
1459  // Read the output
1460  lTimerObject := javaEnvRef^^.GetObjectField(javaEnvRef, javaActivityObject, javaField_lcltimerid);
1461  lGlobalTimerObject := javaEnvRef^^.NewGlobalRef(javaEnvRef, lTimerObject);
1462  lTimer.NativeHandle := PtrInt(lTimerObject);
1463  lTimer.NativeGlobalReference := PtrInt(lGlobalTimerObject);
1464
1465  // Add it to our list
1466  AddTimer(lTimer);
1467  DebugLn(Format('[TCDWidgetSet.CreateTimer] Result=%x', [PtrInt(Result)]));
1468end;
1469
1470{------------------------------------------------------------------------------
1471  function: DestroyTimer
1472  Params: TimerHandle
1473  Returns:
1474 ------------------------------------------------------------------------------}
1475function TCDWidgetSet.DestroyTimer(TimerHandle: THandle) : boolean;
1476var
1477  lTimer: TCDTimer;
1478begin
1479  lTimer := TCDTimer(TimerHandle);
1480
1481  DebugLn(Format('[TCDWidgetSet.DestroyTimer] TimerHandle=%x lTimer.NativeHandle=%x lTimer.NativeGlobalReference=%x',
1482    [PtrInt(TimerHandle), PtrInt(lTimer.NativeHandle), PtrInt(lTimer.NativeGlobalReference)]));
1483  Result := False;
1484
1485  if lTimer = nil then Exit;
1486
1487  // Prepare the input
1488  javaEnvRef^^.SetObjectField(javaEnvRef, javaActivityObject, javaField_lcltimerid, jobject(lTimer.NativeGlobalReference));
1489
1490  // Call the method
1491  javaEnvRef^^.CallVoidMethod(javaEnvRef, javaActivityObject, javaMethod_LCLDoDestroyTimer);
1492  javaEnvRef^^.DeleteGlobalRef(javaEnvRef, JObject(lTimer.NativeGlobalReference));
1493
1494  // Remove from the list
1495  RemoveTimer(lTimer);
1496  lTimer.Free;
1497
1498  Result := True;
1499end;
1500(*
1501procedure TWinCEWidgetSet.HandleWakeMainThread(Sender: TObject);
1502begin
1503  // wake up GUI thread by sending a message to it
1504  Windows.PostMessage(AppHandle, WM_NULL, 0, 0);
1505end;
1506*)
1507
1508