* * *

Author Topic: Android Module Wizard  (Read 345252 times)

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Android Module Wizard
« on: September 01, 2013, 04:35:04 pm »
   Lazarus Android Module Wizard
                 "Form Designer and Components development model!"
      
   "A wizard to create JNI Android loadable module (.so) in Lazarus/Free Pascal using
   [datamodule like] Form Designer and Components!"

   Author: Jose Marques Pessoa : jmpessoa__hotmail_com

      https://github.com/jmpessoa/lazandroidmodulewizard

Please, to start:
   "readme.txt"
   "install_tutorial_ant_users.txt"
   "install_tutorial_eclipse_users.txt"

Acknowledgements: Eny and Phil for the Project wizard hints...
                  http://forum.lazarus.freepascal.org/index.php/topic,20763.msg120823.html#msg120823

                  Felipe for Android support....

                  TrueTom for Laz4Android Package (laz4android1.1-41139)...
                  https://skydrive.live.com/?cid=89ae6b50650182c6&id=89AE6B50650182C6%21149

                  Lazarus forum community!

version 0.1 - August 2013

[1]Warning: at the moment this code is just a *proof-of-concept*

I. INSTALL LAZARUS PACKAGE (laz4android1.1-41139)

   1. From lazarus IDE

      1.1 Package -> Open Package -> "lazandroidwizardpack.lpk"
   
      1.2 From Package Wizard
          1.2.1 Compile
          1.2.2 Use -> Install

II. USE

1. From Eclipse IDE

  1.1. File -> New -> Android Application Project

  1.2. From Package Explore -> src
   
       Right click your recent created package -> new -> class 
   
       Enter new class name... (ex. JNIHello)
   
       Edit class code for wrapper native methods (ex...)

Code: [Select]

                package org.jmpessoa.app1;
 
public class JNIHello {

   public native String getString(int flag);
   public native int getSum(int x, int y);

                   static {
try {
          System.loadLibrary("jnihello");           
} catch(UnsatisfiedLinkError ule) {
    ule.printStackTrace();
}
                   }
             } 


  1.3. warning: System.loadLibrary("...") must match class Name lower case...
       ex. JNIHello -> "jnihello"

2. From lazarus IDE (laz4android1.1-41139)

   2.1 Project -> New Project
   2.2 JNI Android Module

2.1. From JNI Android Module set Paths
   2.1.1 Path to Eclipse Workspace
       ex. C:\adt32\eclipse\workspace
           
   2.1.2 Path to Ndk Plataforms
       ex. C:\adt32\ndk7\platforms\android-8\arch-arm\usr\lib
 
   2.1.3 Path to Ndk Toolchain 
       ex. C:\adt32\ndk7\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.4.3

2.2. From JNI Android Module select Java wrapper class for native methods.... (ex JNIHello)

2.3. OK! 

2.3.1 - Data Module Form Code:

Code: [Select]
{Hint: save all files to location: C:\adt32\eclipse\workspace\App1\jni }
unit unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
type
  TAndroidModule1 = class(TDataModule)
    private
      {private declarations}
    public
      {public declarations}
  end;
 
var
  AndroidModule1: TAndroidModule1;

implementation
 
{$R *.lfm}
 
end.

2.3.2. Library Code:
Code: [Select]
{hint: save all files to location: C:\adt32\eclipse\workspace\App1\jni }
library jnihello;
 
{$mode delphi}
 
uses
  Classes, SysUtils, CustApp, jni, Unit1;
 
const
  curClassPathName: string='';
  curClass: JClass=nil;
  curVM: PJavaVM=nil;
  curEnv: PJNIEnv=nil;
 
type
 
  TAndroidApplication = class(TCustomApplication)
   public
     procedure CreateForm(InstanceClass: TComponentClass; out Reference);
     constructor Create(TheOwner: TComponent); override;
     destructor Destroy; override;
  end;
 
procedure TAndroidApplication.CreateForm(InstanceClass: TComponentClass; out Reference);
var
  Instance: TComponent;
begin
  Instance := TComponent(InstanceClass.NewInstance);
  TComponent(Reference):= Instance;
  Instance.Create(Self);
end;
 
constructor TAndroidApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;
 
destructor TAndroidApplication.Destroy;
begin
  inherited Destroy;
end;
 
var
  Application: TAndroidApplication;
 
{ Class:     org_jmpessoa_app1_JNIHello
  Method:    getString
  Signature: (I)Ljava/lang/String; }
function getString(PEnv: PJNIEnv; this: JObject; flag: JInt): JString; cdecl;
begin
  {your code....}
  {Result:=;}
end;

{ Class:     org_jmpessoa_app1_JNIHello
  Method:    getSum
  Signature: (II)I }
function getSum(PEnv: PJNIEnv; this: JObject; x: JInt; y: JInt): JInt; cdecl;
begin
  {your code....}
  {Result:=;}
end;

const NativeMethods:array[0..1] of JNINativeMethod = (
   (name:'getString';
    signature:'(I)Ljava/lang/String;';
    fnPtr:@getString;),
   (name:'getSum';
    signature:'(II)I';
    fnPtr:@getSum;)
);

function RegisterNativeMethodsArray(PEnv: PJNIEnv; className: PChar; methods: PJNINativeMethod; countMethods:integer):integer;
begin
  Result:= JNI_FALSE;
  curClass:= (PEnv^).FindClass(PEnv, className);
  if curClass <> nil then
  begin
    if (PEnv^).RegisterNatives(PEnv, curClass, methods, countMethods) > 0 then Result:= JNI_TRUE;
  end;
end;
 
function RegisterNativeMethods(PEnv: PJNIEnv): integer;
begin
  curClassPathName:= 'org/jmpessoa/app1/JNIHello';
  Result:= RegisterNativeMethodsArray(PEnv, PChar(curClassPathName), @NativeMethods[0], Length(NativeMethods));
end;
 
function JNI_OnLoad(VM: PJavaVM; reserved: pointer): JInt; cdecl;
var
  PEnv: PPointer {PJNIEnv};
begin
  PEnv:= nil;
  Result:= JNI_VERSION_1_6;
  (VM^).GetEnv(VM, @PEnv, Result);
  if PEnv <> nil then RegisterNativeMethods(PJNIEnv(PEnv));
  curVM:= VM {PJavaVM};
  curEnv:= PJNIEnv(PEnv);
end;
 
procedure JNI_OnUnload(VM: PJavaVM; reserved: pointer); cdecl;
begin
  if curEnv <> nil then (curEnv^).UnregisterNatives(curEnv, curClass);
  curClass:= nil;
  curEnv:= nil;
  curVM:= nil;
  Application.Terminate;
  FreeAndNil(Application);
end;

exports
  JNI_OnLoad name 'JNI_OnLoad',
  JNI_OnUnload name 'JNI_OnUnload',
  getString name 'Java_org_jmpessoa_app1_JNIHello_getString',
  getSum name 'Java_org_jmpessoa_app1_JNIHello_getSum';
 
begin
  Application:= TAndroidApplication.Create(nil);
  Application.Title:= 'My Android Library';
  Application.Initialize;
  Application.CreateForm(TAndroidModule1, AndroidModule1);
end.

2.4. follow the code hint: "save all files to location....."

2.5. From Lazarus IDE (laz4android1.1-41139)
     Run -> Build

III. BUILD AND RUN ANDROID APPLICATION

     1.  From Eclipse IDE

     1.1 right click your recent created project -> Run as -> Android Application

IV.  GIT HUB

     https://github.com/jmpessoa/lazandroidmodulewizard

     To facilitate follows first code release on attachment (*.rar) and some interface pictures...

     Have Fun!
« Last Edit: December 21, 2014, 07:01:00 pm by jmpessoa »
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #1 on: September 11, 2013, 05:27:16 pm »
Hi There,

I made some improvements on parse (and bug fix  :-[).

Now Java method signature like this:

Code: [Select]
public native int getGraphics(ByteBuffer graphicsBuffer, int w, int h);   

Is handled correctly:

Code: [Select]
{ Class:     org_jmpessoa_pascalgraphics_GraphicsBoard
  Method:    getGraphics
  Signature: (Ljava/nio/ByteBuffer;II)I }

function getGraphics(PEnv: PJNIEnv; this: JObject; graphicsBuffer: JObject; w: JInt; h: JInt): JInt; cdecl;
begin

end;

Code: [Select]
const NativeMethods:array[0..0] of JNINativeMethod = (
   (name:'getGraphics';
    signature:'(Ljava/nio/ByteBuffer;II)I';
    fnPtr:@getGraphics;)
);

Follows some example picture..... and the package (*.rar)

Greetings!

https://github.com/jmpessoa/lazandroidmodulewizard
« Last Edit: September 11, 2013, 05:33:51 pm by jmpessoa »
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

engkin

  • Hero Member
  • *****
  • Posts: 1759
Re: Android Module Wizard
« Reply #2 on: October 10, 2013, 04:28:33 pm »
Thank you for sharing your code.   :) It did help me learn a few things like Lazarus project wizards and  Android ARM v7 needed compiler options.

I had only one simple problem using it due to hard-coded path "C:\adt32\eclipse\workspace" in:

uformandroidproject.pas (FormAndroidProject) --> ShellTreeView1 --> Root

it worked after creating these folders and allowed my to change it to my actual folder  ;D

While working on your wizard did you have to re-build Lazarus every time you made a small change? or am I missing something?  ::)

Is it possible to use Build Modes to add compiler settings for both Arm v6 and v7 and maybe i386 to the same project using your project wizard?

Thanks again.

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #3 on: October 10, 2013, 05:09:09 pm »
Hi engkin, thank you!

Actually when you modify a package you need re-install (this is
a Lazarus question)...

Hint: for install and re-intall package in Lazarus4Android close any cross-compile-android project and open a window project!

Please get  more updated version from:

https://github.com/jmpessoa/lazandroidmodulewizard

I will fix the hard path today!

Sorry, I have not learned about Build Modes... :-[

Greetings!
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

picstart

  • Full Member
  • ***
  • Posts: 236
Re: Android Module Wizard
« Reply #4 on: October 10, 2013, 06:04:35 pm »
With the risk of being shot as the messenger...this development is the the lifeboat for Lazarus.
Android is a significant market and is growing. Future apps will be on handheld devices. Lazarus needs a robust path to Android. Many have given up already on Lazarus sure they could spend weeks trying to get Lazarus  to compile a single app but it is smarter to go another route. The originator of this smart approach admits the reason for this direction is that they realized the futility of the existing approach. This effort is trying to bring smart back and bury the obtuse solutions offered to date. Smart work!

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #5 on: October 10, 2013, 08:26:42 pm »
Hi All,

At the moment I am working hard to bring

Android Controls for Lazarus  by simonsayz

(http://forum.lazarus.freepascal.org/index.php/topic,22079.0.html)
 
to talk with my Android Module Wizard.... follows some figures.

Thanks to all!

Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

Leledumbo

  • Hero Member
  • *****
  • Posts: 7745
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Android Module Wizard
« Reply #6 on: October 14, 2013, 12:06:11 am »
Quote
At the moment I am working hard to bring

Android Controls for Lazarus  by simonsayz
That looks delicious, I'll be waiting...

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #7 on: November 17, 2013, 03:32:36 pm »
Hi All,

I can already anticipate some information about what we're talking about: very little code, just design ( without form design) ... that is: component model, LazAndroidWizard and  Object Inspector does the task....

The first part of my task is almost ready .... I hope to make available my code very soon!

Follow some results just for curiosity ...

happy Sunday day!


*.lfm
Code: [Select]
object AndroidModule6: TAndroidModule6
  OnCreate = DataModuleCreate
  OldCreateOrder = False
  BackButton = True
  Title = 'jForm'
  BackgroundColor = colbrBlack
  OnCloseQuery = DataModuleCloseQuery
  OnRotate = DataModuleRotate
  OnJNIPrompt = DataModuleJNIPrompt
  Height = 443
  HorizontalOffset = 319
  VerticalOffset = 145
  Width = 224
  object jTextView1: jTextView
    Id = 26515
    PosRelativeToAnchor = []
    PosRelativeToParent = [rpCenterHorizontal]
    LayoutParamWidth = lpWrapContent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 10
    MarginTop = 10
    MarginRight = 10
    MarginBottom = 10
    Alignment = taLeft
    Visible = True
    Enabled = True
    BackgroundColor = colbrDefault
    FontColor = colbrYellow
    FontSize = 0
    Text = 'List View Demo'
    left = 104
    top = 24
  end
  object jTextView2: jTextView
    Id = 36024
    Anchor = jTextView1
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = [rpLeft]
    LayoutParamWidth = lpWrapContent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 10
    MarginTop = 10
    MarginRight = 10
    MarginBottom = 10
    Alignment = taLeft
    Visible = True
    Enabled = True
    BackgroundColor = colbrDefault
    FontColor = colbrSilver
    FontSize = 0
    Text = 'Enter New Item:'
    left = 48
    top = 96
  end
  object jEditText1: jEditText
    Id = 53166
    Anchor = jTextView2
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = [rpLeft]
    LayoutParamWidth = lpTwoThirdOfParent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 10
    MarginTop = 10
    MarginRight = 10
    MarginBottom = 10
    Alignment = taLeft
    InputTypeEx = itxText
    LineMaxLength = 360
    Visible = True
    BackgroundColor = colbrWhite
    FontColor = colbrDefault
    FontSize = 0
    SingleLine = True
    ScrollBarStyle = scrNone
    MaxLines = 1
    HorScrollBar = False
    VerScrollBar = False
    WrappingLine = True
    left = 48
    top = 152
  end
  object jButton1: jButton
    Id = 0
    Anchor = jEditText1
    PosRelativeToAnchor = [raToRightOf, raAlignBaseline]
    PosRelativeToParent = []
    LayoutParamWidth = lpOneThirdOfParent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 5
    MarginTop = 5
    MarginRight = 5
    MarginBottom = 5
    Visible = True
    BackgroundColor = colbrDefault
    Text = 'Add'
    FontColor = colbrLightSteelBlue
    FontSize = 0
    OnClick = jButton1Click
    left = 144
    top = 152
  end
  object jEditText2: jEditText
    Id = 80017
    Anchor = jTextView3
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = [rpLeft]
    LayoutParamWidth = lpOneThirdOfParent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 10
    MarginTop = 10
    MarginRight = 10
    MarginBottom = 10
    Alignment = taLeft
    InputTypeEx = itxText
    LineMaxLength = 360
    Visible = True
    BackgroundColor = colbrWhite
    FontColor = colbrDefault
    FontSize = 0
    SingleLine = True
    ScrollBarStyle = scrNone
    MaxLines = 1
    HorScrollBar = False
    VerScrollBar = False
    WrappingLine = True
    left = 48
    top = 320
  end
  object jTextView3: jTextView
    Id = 5036
    Anchor = jListView1
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = [rpLeft]
    LayoutParamWidth = lpWrapContent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 10
    MarginTop = 10
    MarginRight = 10
    MarginBottom = 10
    Alignment = taLeft
    Visible = True
    Enabled = True
    BackgroundColor = colbrDefault
    FontColor = colbrSilver
    FontSize = 0
    Text = 'Enter Item Index:'
    left = 48
    top = 264
  end
  object jButton2: jButton
    Id = 63804
    Anchor = jEditText2
    PosRelativeToAnchor = [raToRightOf, raAlignBaseline]
    PosRelativeToParent = []
    LayoutParamWidth = lpTwoThirdOfParent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 5
    MarginTop = 5
    MarginRight = 5
    MarginBottom = 5
    Visible = True
    BackgroundColor = colbrDefault
    Text = 'Delete'
    FontColor = colbrLightSteelBlue
    FontSize = 0
    OnClick = jButton2Click
    left = 144
    top = 320
  end
  object jListView1: jListView
    Id = 8951
    Anchor = jEditText1
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = []
    LayoutParamWidth = lpMatchParent
    LayoutParamHeight = lpOneThirdOfParent
    MarginLeft = 10
    MarginTop = 0
    MarginRight = 10
    MarginBottom = 0
    Items.Strings = (
      'Lazarus'
      'Pascal'
      'Android'
    )
    Visible = True
    BackgroundColor = colbrLightSteelBlue
    FontColor = colbrRed
    FontSize = 0
    OnClickItem = jListView1ClickItem
    left = 96
    top = 208
  end
  object jButton3: jButton
    Id = 0
    Anchor = jEditText2
    PosRelativeToAnchor = [raBelow]
    PosRelativeToParent = []
    LayoutParamWidth = lpMatchParent
    LayoutParamHeight = lpWrapContent
    MarginLeft = 5
    MarginTop = 5
    MarginRight = 5
    MarginBottom = 5
    Visible = True
    BackgroundColor = colbrDefault
    Text = 'ListView Items Clear '
    FontColor = colbrLightSteelBlue
    FontSize = 0
    OnClick = jButton3Click
    left = 96
    top = 376
  end
end

*.pas
Code: [Select]
{Hint: save all files to location: \jni }
unit unit6;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, And_jni, And_jni_Bridge, Laz_And_Controls;
 
type

  { TAndroidModule6 }

  TAndroidModule6 = class(jForm)
      jButton1: jButton;
      jButton2: jButton;
      jButton3: jButton;
      jEditText1: jEditText;
      jEditText2: jEditText;
      jListView1: jListView;
      jTextView1: jTextView;
      jTextView2: jTextView;
      jTextView3: jTextView;
      procedure DataModuleCloseQuery(Sender: TObject; var CanClose: boolean);
      procedure DataModuleCreate(Sender: TObject);
      procedure DataModuleJNIPrompt(Sender: TObject);
      procedure DataModuleRotate(Sender: TObject; rotate: integer;
        var rstRotate: integer);
      procedure jButton1Click(Sender: TObject);
      procedure jButton2Click(Sender: TObject);
      procedure jButton3Click(Sender: TObject);
      procedure jListView1ClickItem(Sender: TObject; Item: Integer);
    private
      {private declarations}
    public
      {public declarations}
  end;
 
var
  AndroidModule6: TAndroidModule6;

implementation
 
{$R *.lfm}

{ TAndroidModule6 }

procedure TAndroidModule6.DataModuleCloseQuery(Sender: TObject;
  var CanClose: boolean);
begin
   CanClose:= True;
end;

 //need here only to fix *.lfm parse fail on Lazarus4android...
procedure TAndroidModule6.DataModuleCreate(Sender: TObject);
begin
  Self.BackgroundColor:= colbrBlack;
  Self.OnJNIPrompt:= @DataModuleJNIPrompt;
  Self.OnRotate:= @DataModuleRotate;
  Self.OnCloseQuery:= @DataModuleCloseQuery;
end;

procedure TAndroidModule6.DataModuleJNIPrompt(Sender: TObject);
begin
  Self.Show;
end;

procedure TAndroidModule6.DataModuleRotate(Sender: TObject; rotate: integer; var rstRotate: integer);
begin
  Self.UpdateLayout;
end;

procedure TAndroidModule6.jButton1Click(Sender: TObject);
begin
  if jEditText1.Text <> '' then
    jListView1.Items.Add(jEditText1.Text)
  else
    jListView1.Items.Add('item_'+ IntToStr(Random(100)));
end;

procedure TAndroidModule6.jButton2Click(Sender: TObject);
begin
   jListView1.Items.Delete(StrToInt(jEditText2.Text));
end;

procedure TAndroidModule6.jButton3Click(Sender: TObject);
begin
  jListView1.Items.Clear;
end;

procedure TAndroidModule6.jListView1ClickItem(Sender: TObject; Item: Integer);
begin
  ShowMessage(IntToStr(Item));
end;

end.

 
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

Leledumbo

  • Hero Member
  • *****
  • Posts: 7745
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Android Module Wizard
« Reply #8 on: November 17, 2013, 03:50:49 pm »
So it will look like a data module, no visual design? The layout must be done through code then, right? No problem actually, it's already a big step. The visual designer could wait :D

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #9 on: November 17, 2013, 04:24:19 pm »
@Leledumbo: 
Quote
The layout must be done through code then, right?

Yes, too. But basically I am using just the Object Inspector to configure the layout, in this sense no coding!

Thank you!
« Last Edit: November 17, 2013, 07:38:00 pm by jmpessoa »
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

exdatis

  • Hero Member
  • *****
  • Posts: 662
    • exdatis
Re: Android Module Wizard
« Reply #10 on: November 17, 2013, 04:27:06 pm »
Thank you very much for your effort.

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #11 on: November 17, 2013, 04:34:15 pm »
And thanks too @simonsayz's  effort!  O:-)
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

engkin

  • Hero Member
  • *****
  • Posts: 1759
Re: Android Module Wizard
« Reply #12 on: November 17, 2013, 08:24:41 pm »
The image you posted for your list view demo looks impressive!. I'm standing in the queue with other eager people that want to try it, patiently.

jmpessoa

  • Hero Member
  • *****
  • Posts: 1013
Re: Android Module Wizard
« Reply #13 on: November 17, 2013, 08:36:51 pm »

Hi engkin,

Thanks for your interest .... I will need help for the next step: build the entire cycle of application without Eclipse!

Greetings!
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

engkin

  • Hero Member
  • *****
  • Posts: 1759
Re: Android Module Wizard
« Reply #14 on: November 17, 2013, 08:53:16 pm »
I'm willing to help, assuming that I'm able to.  :-[

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus