Calling apps from the web with Android Intent


How to call the Delphi Firemonkey App from a web page via Android Intent.

At this point, the URL parameter values are sent to the App.


1. Create an html page and install it on the web. (callapp.html)
<a href="delphiapp://callType1?title=This is a Type1&data1=1111&data2=2222">call Type1</a><BR><BR>

<a href="delphiapp://callType2?title=This is a Type2&data1=3333&data2=4444&data3=5555">call Type2</a><BR><BR>

<a href="delphiapp://callType2?title=Type2 : 한글로 된 제목&data1=6666&data2=7777&data3=3번째 데이터">call Type2 한글</a><BR><BR>



2. Add the same intent-filter entry to the html page's uri entry in the AndroidManifest.template.xml file.



3. Create a Delphi Project.
procedure TForm1.FormCreate(Sender: TObject);
{$IFDEF ANDROID}
var
  intent: JIntent;
  uri: Jnet_Uri;
  uriStr: String;
  rValue : TStringList;
  i : integer;
{$ENDIF}

begin
  {$IFDEF ANDROID}
  intent := SharedActivity.getIntent;
  if intent <> nil then
  begin
    if TJIntent.JavaClass.ACTION_VIEW.equals(intent.getAction) then
    begin
      uri := intent.getData;
      uriStr := JStringToString(uri.toString);  // read uriStr

      rValue := Get_URL_String( uriStr );  // parsing value

      for i := 0 to rValue.Count-1 do
         Memo1.Lines.Add( rValue[i] );
    end;
  end;
  {$ENDIF}
end;



Demo Video

Firemonkey 2D/3D Graph Chart Demo Project

I release the project that draws charts using various Firemonkey's  graphical components and objects.
The Demo Project reads the data from the SQLite Database Table and draws a graph chart.

It has the following features.

  • Demo Project built with Delphi Berlin update2.
  • Multi Platform Support: Windows / Mac OS X / Android / iOS.
  • Demo uses SQLite but uses FireDAC, so all databases can be linked.
  • Database Table Generates graphs that match the aspect ratio automatically, regardless of the number of records.
  • The Demo draws two charts, but you can easily draw multiple charts simultaneously.
  • Graph range is based on maximum value of record value and can be specified at runtime.
  • 2D Graph can draw on all Firemonkey's visible objects (TControl). Demo created above Rectangle object.
  • The total size of the 2D Graph is automatically set to match the size of the dynamically generated TLayout.
  • 3D Graph can be changed by mouse or touch Viewpoint.
  • 3D Graph size is set as camera Z coordinate value.
  • The 3D Graph range is automatically set to match the size of the dynamically generated TLayout3D.
  • The front and back positions of the screen reference of the 3D chart which is generated redundant are designated as the Z coordinate value of TLayout3D.
  • For Demo, 3D Graph Chart can be easily called from other projects using TFrame.

 2D chart creation method


 3D chart creation method

Sample data (SQLite Table)









Draw Line any direction with TPath

Draw Line any direction with TPath

TLine object of firemonkey can draw a line to one direction.
If you want to draw line to any direction, you can use TPath.
TPath can be used drawing a curve normally.
But it is simple for line.



Sample Source

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects, FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    Rectangle1: TRectangle;
    Button2: TButton;
    Button1: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    procedure Draw_Line(pBase: TControl; x1, y1, x2, y2,thikness:single; color:Cardinal );
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Draw_Line(pBase: TControl; x1, y1, x2, y2,thikness:single; color:Cardinal );
var
  LinePath : TPath;
  p1, p2 : TPointF;
begin
  LinePath := TPath.Create(pBase);
  LinePath.Parent := pBase;

  // p1 and p2 number is a only Direction
  // Drawing line of length is set by width and height of TPath.
  if ( x1 < x2 ) and ( y1 < y2 ) then
  begin
    p1.X := 0;     p1.Y := 0;        //  \
    p2.X := 100;   p2.Y := 100;

    LinePath.Position.X := x1;
    LinePath.Position.Y := y1;
    LinePath.Width  := x2 - x1;
    LinePath.Height := y2 - y1;
  end
  else if y1 = y2 then
  begin
    p1.X := 0;    p1.Y := 0;        //  -
    p2.X := 100;  p2.Y := 0;

    LinePath.Position.X := x1;
    LinePath.Position.Y := y1;
    LinePath.Width  := x2 - x1;
    LinePath.Height := 100;  // any value
  end
  else if x1 = x2 then
  begin
    p1.X := 0;   p1.Y := 0;        //  |
    p2.X := 0;   p2.Y := 100;

    LinePath.Position.X := x1;
    LinePath.Position.Y := y1;
    LinePath.Width  := 100;  // any value
    LinePath.Height := y2- y1
  end
  else if ( x1 < x2 ) and ( y1 > y2 ) then
  begin
    p1.X := 100;  p1.Y := 0;        //  /
    p2.X := 0;    p2.Y := 100;

    LinePath.Width  := x2 - x1;
    LinePath.Height := y1 - y2;

    LinePath.Position.X := x1;
    LinePath.Position.Y := y1 - LinePath.Height;
  end;

  LinePath.Stroke.Thickness := thikness;
  LinePath.Stroke.Color := color;
  LinePath.Data.MoveTo( p1 );
  LinePath.Data.LineTo( p2 );
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  Draw_Line( Rectangle1, 0,0, 500,300, 2, $FFFF0000 );
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Draw_Line( Rectangle1, 0,0, 500,0, 4, $FFF0000FF);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Draw_Line( Rectangle1, 0,0, 0,300, 6, $FFFF00FF);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  Draw_Line( Rectangle1, 0,300, 500,0, 4, $FF00FF00 );
end;



System Layout built with Delphi Firemonkey

KOREA JOBWORLD 119 Center




Major Function

- http protocol communication with Adobe Flash apps(6 User) by WebBroker.
- My-SQL database control
- Firemonkey Screen Alarm Application in MS-Windows.
- FastReport Print Solution.
- Print Server of Mobile through Tethering Server.
- Android Tablet App
- RS-232C Serial Communication for Multi Screen Controll Device.

Rad Studio 10.1 Berlin Dialog API Sample Source

Simplified Dialog API

Several procedures and functions to show dialog boxes are now deprecated, and have been replaced by the procedures and functions of the new IFMXDialogServiceAsync and IFMXDialogServiceSync platform services that provide support for synchronous and asynchronous dialog boxes, respectively.
The following table summarizes the API changes:

Deprecated Members New Members
  • FMX.Dialogs.MessageDlg
  • FMX.Dialogs.MessageDlgPos
  • FMX.Dialogs.MessageDlgPosHelp
  • FMX.Platform.IFMXDialogService.MessageDialog
  • FMX.Dialogs.InputBox
  • FMX.Dialogs.InputQuery
  • FMX.Platform.IFMXDialogService.InputQuery
Docwiki Link


Sample Source

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.ListBox, FMX.Layouts,
  FMX.Platform, FMX.StdCtrls, FMX.Controls.Presentation, FMX.DialogService, FMX.ScrollBox, FMX.Memo;

type
  TForm1 = class(TForm)
    ToolBar1: TToolBar;
    Label1: TLabel;
    ListBox1: TListBox;
    ListBoxItem1: TListBoxItem;
    ListBoxItem2: TListBoxItem;
    ListBoxItem3: TListBoxItem;
    ListBoxItem4: TListBoxItem;
    ListBoxItem5: TListBoxItem;
    ListBoxItem6: TListBoxItem;
    Memo1: TMemo;
    procedure ListBoxItem1Click(Sender: TObject);
    procedure ListBoxItem2Click(Sender: TObject);
    procedure ListBoxItem3Click(Sender: TObject);
    procedure ListBoxItem4Click(Sender: TObject);
    procedure ListBoxItem5Click(Sender: TObject);
    procedure ListBoxItem6Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

// uses  FMX.Platform, FMX.DialogService
//**************************************************************************************************
procedure TForm1.ListBoxItem1Click(Sender: TObject);
var
  ASyncService : IFMXDialogServiceASync;
begin
  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceAsync, IInterface (ASyncService)) then
  begin
    ASyncService.ShowMessageAsync ( ( Sender as TListBoxItem ).Text );
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'ShowMessageAsync Displayed' );
end;


procedure TForm1.ListBoxItem2Click(Sender: TObject);
var
  SyncService : IFMXDialogServiceSync;
begin
  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceAsync, IInterface (SyncService)) then
  begin
    SyncService.ShowMessageSync ( ( Sender as TListBoxItem ).Text );
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'ShowMessageSync Displayed' );
end;

//**************************************************************************************************
procedure TForm1.ListBoxItem3Click(Sender: TObject);
var
  ASyncService : IFMXDialogServiceASync;
  caption, inData : array[0..1] of string;
begin
  caption[0]   := 'ID :';
  caption[1] := #1 + 'Pass :';  // #1 앞에 붙이면 마스킹 기능

  inData[0] := 'admin';  // 초기값
  inData[1] := '1234';

  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceAsync, IInterface (ASyncService)) then
  begin
    ASyncService.InputQueryAsync( 'Input String', caption, inData,
      procedure (const AResult : TModalResult; const AValues : array of string)
      begin
         case AResult of
           mrOk: ( Sender as TListBoxItem ).Text := AValues[0] + '/' + AValues[1];
         end;
      end );
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'InputQueryAsync Displayed' );
end;


procedure TForm1.ListBoxItem4Click(Sender: TObject);
var
  SyncService : IFMXDialogServiceSync;
  caption, inData : array[0..1] of string;
begin
  caption[0]   := 'ID :';
  caption[1] := #1 + 'Pass :';  // #1 앞에 붙이면 마스킹 기능

  inData[0] := 'admin';  // 초기값
  inData[1] := '1234';

  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceSync, IInterface(SyncService)) then
  begin
    if SyncService.InputQuerySync( 'Input String', caption, inData ) then
       ( Sender as TListBoxItem ).Text := inData[0] + '/' + inData[1];
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'InputQuerySync Displayed' );
end;


//**************************************************************************************************
procedure TForm1.ListBoxItem5Click(Sender: TObject);
var
  ASyncService : IFMXDialogServiceASync;
begin
  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceAsync, IInterface(ASyncService)) then
  begin
    ASyncService.MessageDialogAsync( 'Question ?', TMsgDlgType.mtConfirmation,
                                                   [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbNo, 0,
     procedure(const AResult: TModalResult)
     begin
       case AResult of
         mrYES : ( Sender as TListBoxItem ).Text := 'YES';
       end;
     end);
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'MessageDialogAsync Displayed' );
end;


procedure TForm1.ListBoxItem6Click(Sender: TObject);
var
  SyncService : IFMXDialogServiceSync;
  rValue, i : integer;
begin
  if TPlatformServices.Current.SupportsPlatformService (IFMXDialogServiceSync, IInterface(SyncService)) then
  begin
    rValue :=  SyncService.MessageDialogSync( 'Question ?', TMsgDlgType.mtConfirmation,
                                             [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbNo, 0 );

    ( Sender as TListBoxItem ).Text := rValue.ToString;
  end;

  Memo1.Lines.Clear;
  Memo1.Lines.Add( 'MessageDialogSync Displayed' );
end;

end.


FireMonkey SQLite DBExpress vs FireDAC

FireMonkey 에서 SQLite 사용시 DBExpress의 TSQLConnection을 사용하면
다음과 같이 SQL 문 안에 as 항목을 사용하면 실행시 필드없음 에러가 발생한다.

    QueryI.Close;
    QueryI.SQL.Clear;
    QueryI.Sql.Add( 'SELECT count(*) as cnt from PackingMaster ' );
    QueryI.Open;
    result := QueryI.FieldByName('cnt').AsInteger;

이때는 DBExpress의 TSQLConnection 대신 FireDAC의 TFDConnection을 사용하면 에러 없이 잘 실행된다.

참고로 Data Module Unit안에 FireDAC 컴포넌트를 사용하면 컴파일시 FireDAC.VCLUI.Wait 가 자동추가 되어 타겟을 안드로이드나 iOS로 지정시 에러가 발생하는데 이때는 Data Module의 ClassGroup의 속성값을 FMX.Controls.TControl 로 바꿔주면 된다.


Interaction & Motion Design Implementation Using Spline Interpolation with DX10 Seattle (1)

Interaction & Motion Design Implementation Using Spline Interpolation

스플라인 보간법을 활용한 자연스런 Interaction & Motion Design 구현 방안


최근 UX/UI 에서 중요시되고 있는 Interaction & Motion Design의 핵심은 각각의 화면객체들이 물 흐르듯이 상호 작용하며 자연스럽게 표현 되는 것이다.
구글의 Material Design 철학 역시 단어 뜻대로 실제 사물의 움직임을 느끼도록 표현한것이기에 자연스러움이 가장 중요한 포인트라 할 수 있을것이다.

개발자와 디자이너가 이를 구현하기 위해서는 객체들의 애니메이션 작동시간을 유효 적절하게 설정해 주어야 하는데 이러한 작업은 간단한 작업이 아니며 반복적인 시행착오를 겪어야만 원하는 결과에 근접할 수 있어 많은 시간과 노력이 소모된다.

자연스러움이란것은 주관적인 관점이지만 실제생활에서 일어나는 물리 법칙을 적용한다면 인간이 느끼는 자연스러움에 근접하게 표현이 가능할 것이다.
가령 화면스크린이 바닥으로 이동하는것을 애니메이션으로 구현할 때 단순 위치이동이 아닌 자유낙하의 중력가속도를 적용하거나 또는 농구공 처럼 바닥에 몇번 튕겨지는 효과를 내기위해 탄성함수를 적용하면 자연스러운 효과를 낼 수있을 것이다.

델파이 FireMonkey의 FloatAnimation은 튕겨지는 효과를 내는 Bounce 옵션등 몇가지 Interpolation 속성을 제공하고 있다. 하지만 이러한 기본속성만으로 여러 객체들간의 상호 작용을 구현하는것은 어려움과 한계가 있을수 밖에 없다.

단일객체의 경우만 보더라도 화면스크린의 위치이동을 애니메이션으로 구현하였을때 시간과 거리가 일정한 선형함수로 위치이동을 하게 되면 부자연스러워 보이는 이유가 실제생활에서는 시간과 거리가 정확히 비례하는 등속운동은 거의 존재하지 않기 때문이다.
가령 창문을 여닫을때도 속도는 일정하지 않으며 이를 시간과 위치의 함수로 표현하면 직선이 아닌 어떠한 곡선으로 표현 될 것이다.
즉, 애니메이션이란것은 결국 시간과 위치(또는 어떠한 다른 속성)의 변화를 직선이 아닌 곡선으로 표현해주는것이 자연스러움에 근접한다고 할 수 있겠다.

곡선함수를 수식으로 표현하는 방식은 여러가지가 있지만 위의 예를든 자유낙하와 같이 단일 함수로 표현되는 경우와 임의의 곡선으로 표현되는 경우가 있을것이다.
디자이너가 애니메이션의 시간비율을 원하는 임의의 곡선으로 표현하고 이를 수치화 하여 그대로 애니메이션 타임에 적용할 수 있다면 작업의 생산성은 매우 높을것임은 자명한 일이다.
포토샵에서도 곡선의 표현을 이용하여 색상정보를 변형하는데 사용되고 있으며 작업자는 몇개의 포인트를 설정하고 이 포인트를 지나는 곡선을 원하는대로 그려 낼수 있다.



바로 이 몇개의 포인트를 지나는 곡선을 그리는 방법중의 하나가 수치해석에서 많이 활용 되는 스플라인 보간법(Spline Interpolation) 이다.
스플라인 보간법은 공학을 비롯한 여러가지 분야에서 다양한 해석을 하는데 많이 사용 되고 있다. (이동경로 예측, 빅데이터 분석, 통계 씨뮬레이션, 기상예보, 금융, 영상복원 등 )
작업자가 조건에 맞게 특정 포인트들을 지정하면 스플라인 보간법으로 그 포인트들을 지나는 곡선을 그려낼 수 있고 그 곡선을 따르는 나머지 결과값들을 모두 알아 낼 수 있다.

실제 구현해 본 결과 포토샵의 이미지 설정 곡선과 거의 일치하게 나타났으며 이를 통해 포토샵 역식 스플라인 보간법으로 곡선을 표현한것으로 유추된다.
참고로 보간법으로 계산된 결과값을 화면에 곡선으로 표현하기 위해 Delphi Firemonkey에서 제공하는 TPath를 사용하면 아주 빠른 속도로 부드러운 곡선을 그려 낼 수 있다.




이제 다음단계는 곡선으로 얻어진 순차적인 데이터를 애니메이션에 타임에 적용시키면 된다. 복수 객체의 Interaction을 위해서는 복수의 곡선으로 나타내면 되며 이럴때 곡선의 교차점이 정확하게 표현되므로 복수객체의 전환(화면전환등)점이 아주 쉽게 나타내 질 수 있다.







Android Service App with DX10 Seattle

Android Service 란 ?


• 윈도우 환경의 서비스 어플리케이션과 비슷한 개념으로 백그라운 작업이 가능한
[윈도우 서비스와의 차이점]
• 서비스의 주 역활 : 감시, 통보등에 한정 -> Main Activity(Process)의 역할 보조
• 서비스 독자적인 역활은 제한 됨
• 서비스  최초 시작은 Main Activity 가 담당
• 활동하지 않는 서비스는 안드로이드 O/S 자체적으로 종료 시킬수 있음.
        -> 따라서 서비스의 계속 유지를 위해서는 별도의 장치가 필요함
        Ex) Alarm Manager를 통해 주기적으로 활동, 두개의 서비스가 번갈아 가면서 재 시작 등.
[대표적인 서비스]
• 채팅  : 제작 배포자의 자체 Push Message를 받기 위해 리시버 대기
• 장치 연결 : 지정된 장비 연결시 접속 알림 -> 이어폰 연결시 MP3 Play, 비콘, 블루투스
• 클라우드 : 파일 업로드/다운로드 작업시 관련된 클라우드 실행
• 보안관련  바이러스 감시


Android Service 앱 구축 방법

1.위저드 실행
2.서비스 종류 선택
3.별도 프로젝트(별도폴더)에 서비스 앱 작성
4.빌드   
        주의1 : 서비스명(프로젝트명)“Service” 단어 사용 불가함
        주의2 : 메인앱 보다 반드시 먼저 빌드가 되어 있어야 함
5.메인 생성
6.Project Manager > Android Platform > 우클릭 : 서비스 폴더 지정
        주의: 절대경로로 지정이 되므로 서비스앱의 프로젝트 폴더 이동시 재 지정 필요함
7.TLocalServiceConnection.StartService(‘서비스 프로젝트 명');   //  System.Android.Service
  주의 : “lib” 글자 제외 및 대소문자 구분
8.빌드 및 실행

Android Service 앱 확인 사항


 서비스 프로젝트 빌드후  jar파일 라이브러리 추가 확인

Deployment 

AndroidManifest.template.xml



Sample Demo

1. 비콘 인식 서비스 앱 실행.
2. 앱이 종료된 상태에서도 서비스는 가동됨
3. 비콘 접근시 알람
4. 알람 터치시 앱 실행하여 쿠폰 수신