Source Code Delphi Samples with Sources

Статус
В этой теме нельзя размещать новые ответы.

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
InLine variable declaration, WORKS, if used correctly
my example in RAD Studio 10.3.1 Arch
[SHOWTOGROUPS=4,19,20]
Код:
unit Unit1;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
      procedure prcPrivateProc(lVarA: Integer);
    public
      procedure prcPublicProc(lVarB: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
//
{
  //****************************************************************
  procedure prcSub_Procedure1;
  begin
  s := s + ', i dont work in prcSub_Procedure1! See my definition is below (later)';
  end;
  //****************************************************************
}
//
var // <---
  // i: Integer;  // if defined here, will conflict with "i" defined in "var inline below"
  //
  s: String; // scope global to your procedure, same if used in sub-procedures defined here!
  lUrl: String;
  //
  //
  // ****************************************************************
  procedure prcSub_Procedure2;
  begin
    s := s + ', im re-writed in prcSub_Procedure2! See my definition is above (before)';
  end;

// ****************************************************************
begin
  //
  // DONT WORRY ABOUT "line red" in your editor screen!
  //
  lUrl := 'http://www.idera.com';
  //
  ComboBox1.Items.Clear;

  begin // ITS NOT NECESSARY, AND DONT HELP YOU AND NOTHING HERE!
    //

    var  ext := LowerCase(ExtractFileExt(lUrl));
    ShowMessage(ext); // works!
    prcPrivateProc(ext.ToInteger()); // works!
    prcPublicProc(ext.ToInteger()); // works!

    for var i := 0 to 10 do { var "inline" only works on the "block" is defined! }
    begin // "BEGIN_NECESSARY" --> if commented, i is "out of scope" too
      //
      ComboBox1.Items.Add(Format('Value to i = %d', [i]));
      //
      ComboBox1.ItemIndex := i; // "BEGIN_NECESSARY" (above) is essential to works! and below definitions
      //
      //
      prcPrivateProc(i); // works! "i" on the scope!
      //
      prcPublicProc(i); // works! "i" on the scope!
      //
      {
       if (i = 4) then // works too, with BEGIN
        break;
       }
      //
      if (i = 10) then
        ShowMessage(Format('Value to i = %d', [i])); // works! "i" on the scope!
      //
    end; // end to "BEGIN_NECESSARY"
    //
    // prcPrivateProc(i); // dont works! "i" out of scope!
    //
    // prcPublicProc(i); //  ont works! "i" out of scope!
    //
    // ShowMessage(Format('Value to i = %d', [i]));  // dont works! "i" out of scope!
    //
  end;
  //
  // prcPrivateProc(i); // dont works! "i" out of scope!
  //
  // prcPublicProc(i);  // dont works! "i" out of scope!
  //
  // ShowMessage(Format('Value to i = %d', [i]));  // dont works! "i" out of scope!
  //
end;

procedure TForm1.Button2Click(Sender: TObject);
//
{
  //****************************************************************
  procedure prcSub_Procedure1;
  begin
  s := s + ', i dont work in prcSub_Procedure1! See my definition is below (later)';
  end;
  //****************************************************************
}
//
var // <---
  // i: Integer;  // if defined here, will conflict with "i" defined in "var inline below"
  //
  s: String; // scope global to your procedure, same if used in sub-procedures defined here!
  lUrl: String;
  //
  //
  // ****************************************************************
  procedure prcSub_Procedure2;
  begin
    s := s + ', im re-writed in prcSub_Procedure2! See my definition is above (before)';
  end;

// ****************************************************************
begin
  //
  // DONT WORRY ABOUT "line red" in your editor screen!  HERE NONE RED-LINE APPEARS!
  //
  lUrl := 'http://www.idera.com';
  //
  ComboBox1.Items.Clear;
  //
  // begin // BEGIN_1     { uncomment here and showmessage and my procedure prcPrivate and prcPublic}
  //
  var   i := Random(20); { var "inline" only works on the "block" is defined! }
  var   ext := LowerCase(ExtractFileExt(lUrl));
  //
  begin // BEGIN_2   // its not necessary to ShowMessage or my procedure prcPrivate and prcPublic works
    //
    ComboBox1.Items.Add(Format('Value to i = %d', [i]));
    //
    ComboBox1.ItemIndex := i; // "BEGIN_NECESSARY" (above) is essential to works! and below definitions
    //
    //
    prcPrivateProc(i); // works! "i" on the scope!
    //
    prcPublicProc(i); // works! "i" on the scope!
    //

    if (i = 10) then
      ShowMessage(Format('Value to i = %d', [i])); // works! "i" on the scope!
    //
  end; // end to BEGIN_2
  //
  prcPrivateProc(i); // works to BEGIN_1 and BEGIN_2 defined
  //
  prcPublicProc(i); // works to BEGIN_1 and BEGIN_2 defined
  //
  ShowMessage(Format('Value to i = %d', [i])); // works to BEGIN_1 and BEGIN_2 defined
  //
  // end; // end to BEGIN_1
  //
  prcPrivateProc(i); // dont works! if BEGIN_1 defined, then "i"/"ext" out of scope!
  //
  prcPublicProc(i); // dont works! if BEGIN_1 defined, then "i"/"ext" out of scope!
  //
  ShowMessage(Format('Value to i = %d', [i])); // dont works! if BEGIN_1 defined, then "i"/"ext" out of scope!
  //
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ShowMessage('destroyng....');
end;

procedure TForm1.prcPrivateProc(lVarA: Integer);
begin
  ShowMessage(Format('lVarA = %d', [lVarA]));
end;

procedure TForm1.prcPublicProc(lVarB: Integer);
begin
  ShowMessage(Format('lVarB = %d', [lVarB]));
end;

end.

Screen0001.png


Screen0002.png

[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Learn How To Deploy Delphi 10.3 Rio Android Apps To Google Play With Android 64-bit Requirements
July 18, 2019 by Admin FmxExpress.com
[SHOWTOGROUPS=4,19,20]
July 18, 2019 by Admin

There are a number of ways to deploy Delphi and C++Builder FireMonkey apps to Android devices which includes sideloading the apps (copying them to the device), through an enterprise MDM like AirWatch or MaaS260 (mobile device manager), and through Google Play. In addition to Android, FireMonkey apps run on Windows, MacOS, IOS, Linux, and HTML5. Google Play has a restriction that will be in effect on August 1st 2019 which will restrict adding new app (or updating existing apps) which target Android 28+ and contain native libraries as the main app unless they include Android 64-bit binaries in addition to Android 32-bit binaries. You can read a blog post from Google about these changes where they outline exactly what the requirements are and what the exceptions are. RAD Studio 10.3.x Rio (and previous versions) which consists of Delphi 10.3.x Rio and C++Builder 10.3.x Rio currently creates 32-bit binaries for Android.

According to the blog post three third party native files have an exception which allows them to continue to support 32-bit apps which target Android 28+ to Google Play. These three third party developer tools are:

Corona Labs SDK – until August 2020
Adobe Air software and the AIR SDK – until August 2020
Unity 5.6.7 or older – until August 2021
For Delphi 10.3.x and C++Builder 10.3.x and earlier apps the important line in the blog post is this “The requirement does not apply to: APKs or app bundles that are not distributed to devices running Android 9 Pie or later.” What this means is that for Delphi 10.3.x and C++Builder 10.3.x apps (and all previous FireMonkey versions) you will need to add android:maxSdkVersion=”27″ to your AndroidManifest.template.xml file in the uses-sdk section. For example:

<uses-sdk android:minSdkVersion="%minSdkVersion%"
android:targetSdkVersion="%targetSdkVersion%"
android:maxSdkVersion="27" />

What this line does is restrict your app from running on Android 9 Pie (Android 28+) devices which at the time of this writing is only ~10% of Android devices. I tested this solution and Google Play does not display a warning when you upload your Android 32bit app with the maxSdkVersion set. You can still continue to add new FireMonkey apps and update existing apps through Google Play with the maxSdkVersion set. Additionally, you can continue to sideload and deploy your current FireMonkey apps via MDM solutions to Android devices. According to the blog post “Google Play will continue to deliver apps to 32-bit devices. This requirement means that apps with 32-bit native code will need to have an additional 64-bit version as well.” [to be able to target devices running Android 28+]

Developers and third party developer tools like RAD Studio Delphi and C++Builder, Unity, and Adobe AIR are at the mercy of requirements handed down by Apple and Google in order be listed on the major app stores. These requirements constantly change and require updates which is why building apps for Android and Google is a commitment to updating your app frequently and staying up to date with the latest developer tools. Within the Delphi ecosystem this means being on the Update Subscription. Companies that make developer tools for Android and IOS are also committing for a price to keeping their tooling up to date in partnership with their customers.

A more experimental view of Android 64-bit app requirement is that all that Google Play seems to currently check for is that a library (or just a file) exists at lib/arm64-v8a/libMyapp.so in addition to the 32-bit version of your app located at lib/armeabi-v7a/libMyapp.so. I uploaded an Android APK to Google Play with a 32-bit FireMonkey library generated with Delphi 10.3.x Rio in both the armeabi-v7a and arm64-v8a directories and Google Play displayed no warning about missing Android 64-bit support. According to this StackOverflow answer “64-bit Android can use 32-bit native libraries as a fallback, only if System.loadlLibrary() can’t find anything better in the default search path.”. What this means is that it may be possible create a 64-bit Android binary shim in the arm64-v8a directory using a different tool (the Android NDK?) that loads your FireMonkey 32-bit binary from the armeabi-v7a directory if you need to target Android 9 Pie (Android 28+) devices with RAD Studio 10.3.x apps through Google Play.

Embarcadero has a blog post titled “May 2019 RAD Studio Roadmap Commentary from Product Management” where they outline their plan for Android 64-bit support for Android 9 Pie (Android 28+) devices. It states:

“As of August 2019, Google will require that all Google Play Store applications are 64-bit enabled. Android 64-bit support is actively in the works for Delphi as we speak. In time for this new Google requirement, we plan to kick off our 10.4 beta this summer with support for building Delphi Android 64-bit applications. While the usual beta restrictions do not allow for building and deploying production apps, we intend to include a special beta EULA provision that allows 10.4 beta testers to deploy (production) Android apps to the Google Play Store. We followed the same approach for 10.3 and Google’s API level 26 requirement last summer and that process worked well for our customers. InterBase support for Android 64-bit is also in the works.”

Bottom line is that Delphi 10.3.x Rio and C++Builder 10.3.x Rio 32-bit apps can continue to be deployed via Google Play using android:maxSdkVersion=”27″ to 90% of Android devices and Embarcadero has Android 64-bit support for Android 9 Pie (Android 28+) devices on their roadmap.

Head over and check out the full blog post about the Embarcader RAD Studio Roadmap and future Android 64-bit support.

SOURCES:
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
When a Exception is raised on Constructor or Destructor from a Class
thanks to Alister Christie
Testing-Raise-Exceptions-in-Constructor-and-Destructor-from-Objects.png


[SHOWTOGROUPS=4,19,20]Для просмотра ссылки Войди или Зарегистрируйся[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
my sample using: FireMonkey TScaleLayout, TGridPanelLayout, TLayout and GetScreenOrientation to rotate components using screen orientation from Android
here my sample to show how to rotate components in Firemonkey project accourding with screen orientation
Scenary:
  • RAD Studio 10.3.2 Arch
  • FireMonkey project
  • Smartphone Moto G4 with Android 7.0 Nougat
FMX-Layout-Landscape-Portrait-screenshot.png

Screenshot-20191011-021033.png

Screenshot-20191011-021048.png
[SHOWTOGROUPS=4,19,20]
Code source:
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
my sample about: Reading JSON File using TJSONIterator, TJSONTokens and TJSONTextReader classes - Easy mode!

My-Conan-Exiles-Screen0001.png
[SHOWTOGROUPS=4,19,20]
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
My sample based on "FireDAC using connections type", webinar showed by Jens Fudge
FireDAC for Windows 10 Database Access by Jens Fudge MVP Embarcadero - webinar

[SHOWTOGROUPS=4,19,20]Для просмотра ссылки Войди или Зарегистрируйся[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Here my example how to use TVirtualImageList and TImageCollection to store and show images in TImage or similar controls!
prjVCL_Read_Icons_On_Executable_or_Anothers.png
[SHOWTOGROUPS=4,19,20]
Код:
unit uFormMain2;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  System.ImageList,
  Vcl.ImgList,
  Vcl.VirtualImageList,
  Vcl.BaseImageCollection,
  Vcl.ImageCollection,
  Vcl.StdCtrls,
  Vcl.ExtCtrls;

type
  TForm2 = class(TForm)
    ImageCollection1: TImageCollection;
    VirtualImageList1: TVirtualImageList;
    btnCountingItems: TButton;
    Memo1: TMemo;
    btnAddImageOnImageCollection: TButton;
    Panel1: TPanel;
    Panel2: TPanel;
    img_My_VirtualImage_ICON: TImage;
    imgBMP_FULL_IMAGE: TImage;
    btnAddImageOnVirtualImageList: TButton;
    Panel3: TPanel;
    img_My_VirtualImage_BITMAP: TImage;
    btnCleaningVirtualImageList_ImageCollection: TButton;
    procedure btnCountingItemsClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnAddImageOnImageCollectionClick(Sender: TObject);
    procedure btnAddImageOnVirtualImageListClick(Sender: TObject);
    procedure btnCleaningVirtualImageList_ImageCollectionClick(Sender: TObject);
  private
    procedure prcLOG(lText: string);
  public
    //
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.prcLOG(lText: string);
begin
  Memo1.Lines.Add(lText);
end;

procedure TForm2.btnAddImageOnVirtualImageListClick(Sender: TObject);
var
  lVILItem:            TVirtualImageListItem;
  lImageIndexOnVIList: Integer;
  //
  lMyImageName: string;
begin
  if not(ImageCollection1.Count > 0) then
  begin
    ShowMessage('There is not image on ImageCollection1');
    exit;
  end;
  //
  if (VirtualImageList1.Count = 1) then
  begin
    ShowMessage('Already there is 1 image on VirtualImageList1 for test!');
    exit;
  end;
  //
  lMyImageName := '2_without_logo';
  //
  lVILItem                := VirtualImageList1.Images.Add;
  lVILItem.CollectionName := lMyImageName;
  //
  lVILItem.Name := lMyImageName;
  //
  btnCountingItems.Click;
  //
  lImageIndexOnVIList := VirtualImageList1.GetIndexByName(lVILItem.Name); // searching by image names...
  //
  if (lImageIndexOnVIList > -1) then
  begin
    VirtualImageList1.GetIcon(lImageIndexOnVIList, img_My_VirtualImage_ICON.Picture.Icon); // myICON_Temp);
    //
    VirtualImageList1.GetBitmap(lImageIndexOnVIList, img_My_VirtualImage_BITMAP.Picture.Bitmap); // myBITMAP_Temp);
    //
    prcLOG('TImage''s resulted!');
  end
  else
    ShowMessage('lImageIndexOnVIList = -1'); // not founded!
  //
  if (VirtualImageList1.Count = 0) then
    ShowMessage('There is not images on VirtualImageList1');
  //
  prcLOG(StringOfChar('-', 80));
end;

procedure TForm2.btnCleaningVirtualImageList_ImageCollectionClick(Sender: TObject);
begin
  VirtualImageList1.Clear;
  ImageCollection1.Images.Clear;
  //
  imgBMP_FULL_IMAGE.Picture          := nil;
  img_My_VirtualImage_ICON.Picture   := nil;
  img_My_VirtualImage_BITMAP.Picture := nil;
  //
  prcLOG('VirtualImageList and ImageCollection was cleaned!');
  prcLOG(StringOfChar('-', 80));
end;

procedure TForm2.btnCountingItemsClick(Sender: TObject);
begin
  prcLOG(Format('ImageCollection1.Count = %d, VirtualImageList1.Count = %d', [ { }
    ImageCollection1.Count,                                                    { }
    VirtualImageList1.Count                                                    { }
    ]));
  prcLOG(StringOfChar('-', 80));
end;

procedure TForm2.btnAddImageOnImageCollectionClick(Sender: TObject);
var
  lICItem:  TImageCollectionItem;
  lICSItem: TImageCollectionSourceItem;
  lVILItem: TVirtualImageListItem;
  //
  lMyImageName:       string;
  lMyPathAndFileName: string;
begin
  //
  lMyPathAndFileName := '..\..\2_without_logo.bmp';
  lMyImageName       := '2_without_logo';
  //
  imgBMP_FULL_IMAGE.Picture.Bitmap.LoadFromFile(lMyPathAndFileName);
  //
  lICItem      := ImageCollection1.Images.Add;
  lICItem.Name := lMyImageName;
  lICSItem     := lICItem.SourceImages.Add;
  lICSItem.Image.LoadFromFile(lMyPathAndFileName);
  //
  prcLOG('lICItem.Name = ' + lICItem.Name);
  prcLOG('lICItem.Index = ' + lICItem.Index.ToString);
  prcLOG('lICItem.ID = ' + lICItem.ID.ToString);
  prcLOG('lICItem.DisplayName = ' + lICItem.DisplayName);
  prcLOG('lICItem.GetNamePath = ' + lICItem.GetNamePath);
  prcLOG('lICItem.DisplayName = ' + lICItem.DisplayName);
  prcLOG('lICItem.SourceImages.GetNamePath = ' + lICItem.SourceImages.GetNamePath);
  //
  btnCountingItems.Click;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;
end;

end.
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
my VCL project Creating Forms MDI using FormStyle fsMDIForm and fsMDIChild and ProgressBar control on runtime - my sample for remember good-times
Forms-MDI-and-Child-with-Control-Created-in-Run-Time.png
[SHOWTOGROUPS=4,19,20]
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
TEdit accepting only FLOAT values or NOT and some keys from User (NUMBERs, DOT, COMMA, ENTER, BACKSPACE, ESC, etc..)
NOTE: NOT PERFECT OK! :)

Here my simple TEDIT sample for this, of course, is possible using a code more xpert like create a class to automatize all process, or same, use new functions/procedure on RAD Studio 10.3.3 Rio.
TEdit_Only_Float_Values_Is_Accepted_Screen0001.png
Code:
[SHOWTOGROUPS=4,19,20]
Код:
unit Unit1;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    lbTextTyped: TLabel;
    lbKeyPressed: TLabel;
    Edit2: TEdit;
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// 0,1,2,3,4,5,6,7,8,9,",", "-", ".", "ENTER", "BACKSPACE", "ESC"
// You can use some like: "0".."9", etc... of course!
const
  lMyCharsAllowed = [Char(48), Char(49), Char(50), Char(51), Char(52), Char(53), { }
  { -------------- } Char(54), Char(55), Char(56), Char(57), Char(44), Char(45), { }
  { -------------- } Char(46), Char(13), Char(8), Char(27)                       { }
    ];
  //
  lDontRepeatThis = [Char(44), Char(45), Char(46)]; // Dont repeat ",-."

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
var
  lText: string;
begin
  //
  lbKeyPressed.Caption := 'Key pressed: ' + Ord(Key).ToString;
  //
  lText := Trim((Sender as TEdit).Text); // only help me on tests!
  //
  if not(Key in lMyCharsAllowed) or                         { Accept only my chars, ok! }
    ((Key in lDontRepeatThis) and (Pos(Key, lText) > 0)) or { Don't repeat this chars! }
    ((Key = Char(45)) and (Length(lText) > 0)) or           { Minus, only on first char }
    ((Key = Char(44)) and (Pos(Char(46), lText) > 0)) or    { If it have Comma, dont accept Dot }
    ((Key = Char(46)) and (Pos(Char(44), lText) > 0)) then  { If it have Dot, dont accept Comma }
  begin
    Key := #0;
    Exit;
  end;
  //
  if not(Key = Char(8)) then // BACKSPACE dont appears on my resulted!
    lbTextTyped.Caption := lText + Key;
  //
  if (Key = Chr(13)) then // ENTER... What's happens?
    perform(WM_NEXTDLGCTL, 0, 0);
end;

end.
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
My sample to create your "re-TRY" another or same command line: like "try reconnect again my login"
[SHOWTOGROUPS=4,19,20]
Код:
procedure TForm2.Button1Click(Sender: TObject);
var
  lMyCounter: integer;
begin
  lMyCounter := 0;
  //
  while (lMyCounter <= 3) do // or "While True do ...." for exit, use "break" for example!
  begin
    // Here, you can use another value than "WSDL_a" if not needs test 1, 2, and 3 way! Like your "Case test"!
    Inc(lMyCounter); // start in 1... because your Array of options!
    //
    if (lMyCounter <= 3) then // avoid any call unnecessary
    begin
      try
        Label3.Caption := Format('My contador: %d', [lMyCounter]);
        //
        ShowMessage(Format('Counter %d', [lMyCounter])); // for test on screen!
        //
        StrToInt('22a'); // simulating errors and call "except section"!
        //
      except
        // raise; // re-raise the exception if necessary!
        continue;
        {
          Note: "Continue" does not violate the flow of control dictated by a try..finally construct.
          If a call to "Continue" causes the control to leave the try clause, the finally clause is entered.
        }
      end;
      //
      // Inc(wsdl_a); // never... infinite looping!
      //
    end;
  end;
  //
  ShowMessage(Format('End procedure! No more try!'#13#10'Counter: %d', [lMyCounter]));
end;

Meu_Contador_de_Exceptions.png
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Here my sample to works with Class Helper to Strings to divide it in "before" and "after" Delimiter char! - very easy!

Screen04.png

Screen05.png
Код:
unit uMainForm;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    btnUsinSPLIT_function: TButton;
    ListBox1: TListBox;
    btnUsingListBox: TButton;
    ListBox2: TListBox;
    Memo1: TMemo;
    btnMyNewSplitStrings: TButton;
    procedure btnUsinSPLIT_functionClick(Sender: TObject);
    procedure btnUsingListBoxClick(Sender: TObject);
    procedure btnMyNewSplitStringsClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnUsinSPLIT_functionClick(Sender: TObject);
var
  lMyArraySpplited: TArray<string>;
  lMyRegKey       : string;
  lNewRegKey      : string;
  i               : Integer;
  lLastDelimiter  : integer;
begin
  memo1.Lines.Clear;
  //
  // if lMyRegKey = ''  or '\'  -> it's necessary verify too!
  // But DONT problem if lLastDelimiter <= 0
  // on the end, your "string" resulted can be EMPTY!
  // None exception will be raised!
  //
  lMyRegKey := 'part1\part2\part3\value';
  //
  lMyArraySpplited := lMyRegKey.Split(['\']);
  //
  lLastDelimiter := lMyRegKey.LastDelimiter('\') + 1; // +1 here or below (Rigth substring)
  //
  memo1.Lines.Add('SubString Left  = ' + lMyRegKey.Substring(-lLastDelimiter, lLastDelimiter));
  memo1.Lines.Add('SubString Right = ' + lMyRegKey.Substring(lLastDelimiter));
  //
  memo1.Lines.Add('LastDelimiter = ' + lMyRegKey.LastDelimiter('\').ToString);
  //
  memo1.Lines.Add('');
  //
  lNewRegKey := lMyRegKey.Join('\', lMyArraySpplited, 0, 2); // "part1\part2"
  //
  memo1.Lines.Add('Join 0 to 2 = ' + lNewRegKey);
  //
  lNewRegKey := lMyRegKey.Join('\', lMyArraySpplited, 3, 4); // "value"
  //
  memo1.Lines.Add('Join 3 to 4 = ' + lNewRegKey);
  //
  memo1.Lines.Add('');
  //
  for i := 0 to high(lMyArraySpplited) do
  begin
    if lMyArraySpplited[i] <> '' then
      memo1.Lines.Add(lMyArraySpplited[i]);
  end;
end;

procedure TForm1.btnMyNewSplitStringsClick(Sender: TObject);
var
  lMyRegKey       : string;
  lMyArraySpplited: TArray<string>;
begin
  Memo1.Lines.Clear;
  //
  lMyRegKey := 'part1\part2\part3\value';
  //
  // start from "1" and ending on "3" chars!
  // using "\" like my "Delimiter" to split my string!
  //
  lMyArraySpplited := lMyRegKey.Split(['\'], '1', '3', Length(lMyRegKey));
  //
  Memo1.Lines.Add('How many items SPLITTED = ' + Length(lMyArraySpplited).ToString);
  Memo1.Lines.Add('');
  Memo1.Lines.Add('my items:');
  //
  Memo1.Lines.AddStrings(lMyArraySpplited); // working with my items splitted (my array)
end;

procedure TForm1.btnUsingListBoxClick(Sender: TObject);
var
  lMyRegKey: string;
begin
  lMyRegKey := 'part1\part2\part3\value';
  //
  ListBox1.Items.Delimiter     := '\';
  ListBox1.Items.DelimitedText := lMyRegKey;
  //
  ListBox2.Items.Clear;
  ListBox2.Items.Add(ListBox1.Items[3]);
  //
  // another ways can help too, when using a "List"
  //
  // ListBox1.Items.IndexOf('first position to start')
  // ListBox1.Items.IndexOf('last position to end')
  // ShowMessage(ListBox1.Items.KeyNames[2]);
end;

end.
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Creating a "counter" to close your "Active window", like MessageDLG using SetTimer() and PostMessage() from API Windows
Code by Žarko Gajić (MVP Embarcadero)

[SHOWTOGROUPS=4,19,20]
VCL_MessageDLG_with_Auto_Close_CallBack_function.png
Код:
unit uMainForm;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.Menus,
  Vcl.Buttons,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Arquivo1: TMenuItem;
    Opc11: TMenuItem;
    Opc21: TMenuItem;
    Opc31: TMenuItem;
    N1: TMenuItem;
    Opc41: TMenuItem;
    Help1: TMenuItem;
    Opc12: TMenuItem;
    Opc22: TMenuItem;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  System.UITypes, // msg buttons
  Vcl.Consts;     // SMsgDlgInformation

//********************************************************************
// Code by Žarko Gajić  (MVP Embarcadero)
//********************************************************************

function MessageDlgTimed(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint; const closePeriod: integer = 2000): Integer;
var
  timerCloseId: UINT_PTR;

  procedure CloseMessageDlgCallback(AWnd: HWND; AMsg: UINT; AIDEvent: UINT_PTR; ATicks: DWORD); stdcall;
  var
    activeWnd: HWND;
  begin
    KillTimer(AWnd, AIDEvent);

    activeWnd := GetActiveWindow;

    if IsWindow(activeWnd) and IsWindowEnabled(activeWnd) then
      PostMessage(activeWnd, WM_CLOSE, 0, 0);
  end; (* CloseMessageDlgCallback *)

begin
  timerCloseId := SetTimer(0, 0, closePeriod, @CloseMessageDlgCallback);
  //
  result := MessageDlg(Msg + ', ' + closePeriod.ToString + 'ms to destroy itself', DlgType, Buttons, HelpCtx);
  //
  if timerCloseId <> 0 then
    KillTimer(0, timerCloseId);
end;

//********************************************************************
function HookResourceString(ResStringRec: pResStringRec; NewStr: pChar): integer;
var
  OldProtect: DWORD;
begin
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^), PAGE_EXECUTE_READWRITE, @OldProtect);
  result                   := ResStringRec^.Identifier;
  ResStringRec^.Identifier := Integer(NewStr);
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^), OldProtect, @OldProtect);
end;

procedure UnHookResourceString(ResStringRec: pResStringRec; oldData: integer);
var
  OldProtect: DWORD;
begin
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^), PAGE_EXECUTE_READWRITE, @OldProtect);
  ResStringRec^.Identifier := oldData;
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^), OldProtect, @OldProtect);
end;

function MessageDlgTimedAdvanced(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint; const closePeriod: integer = 5000): Integer;
const
  tickPeriod = 250;
var
  timerCloseId, timerTickId: UINT_PTR;
  r                        : integer;
  peekMsg                  : TMsg;

  procedure CloseMessageDlgCallback(AWnd: HWND; AMsg: UINT; AIDEvent: UINT_PTR; ATicks: DWORD); stdcall;
  var
    activeWnd: HWND;
  begin
    KillTimer(AWnd, AIDEvent);

    activeWnd := GetActiveWindow;

    if IsWindow(activeWnd) and IsWindowEnabled(activeWnd) then
      PostMessage(activeWnd, WM_CLOSE, 0, 0);
  end; (* CloseMessageDlgCallback *)

  procedure PingMessageDlgCallback(AWnd: HWND; AMsg: UINT; AIDEvent: UINT_PTR; ATicks: DWORD); stdcall;
  var
    activeWnd     : HWND;
    wCaption      : string;
    wCaptionLength: integer;
  begin
    activeWnd := GetActiveWindow;
    if IsWindow(activeWnd) and IsWindowEnabled(activeWnd) and IsWindowVisible(activeWnd) then
    begin
      wCaptionLength := GetWindowTextLength(activeWnd);
      SetLength(wCaption, wCaptionLength);
      GetWindowText(activeWnd, PChar(wCaption), 1 + wCaptionLength);
      SetWindowText(activeWnd, Copy(wCaption, 1, -1 + Length(wCaption)));
    end
    else
      KillTimer(AWnd, AIDEvent);
  end; (* PingMessageDlgCallback *)

//
begin
  if (DlgType = mtInformation) and ([mbOK] = Buttons) then
  begin
    timerCloseId := SetTimer(0, 0, closePeriod, @CloseMessageDlgCallback);

    if timerCloseId <> 0 then
    begin
      timerTickId := SetTimer(0, 0, tickPeriod, @PingMessageDlgCallback);

      if timerTickId <> 0 then
        r := HookResourceString(@SMsgDlgInformation, PChar(SMsgDlgInformation + ' ' + StringOfChar('.', closePeriod div tickPeriod)));
    end;

    result := MessageDlg(Msg, DlgType, Buttons, HelpCtx);

    if timerTickId <> 0 then
    begin
      KillTimer(0, timerTickId);
      UnHookResourceString(@SMsgDlgInformation, r);
    end;

    if timerCloseId <> 0 then
      KillTimer(0, timerCloseId);
  end
  else
    result := MessageDlg(Msg, DlgType, Buttons, HelpCtx);
end;

//********************************************************************
procedure TForm1.Button2Click(Sender: TObject);
begin
  MessageDlgTimedAdvanced('string', mtInformation, [mbOK], 0, 5000); // ok
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MessageDlgTimed('string', mtInformation, [mbYes], 0, 4000); // ok
end;

end.
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Memory 3D – Full Source Code Delphi Game
by Žarko Gajić (MVP Embarcadero)
[SHOWTOGROUPS=4,19,20]
1585520479779.png
“If you want it to be playable and more interesting you need to jazz it up a bit!”
That’s what’s been cooking in my head from the time I’ve finished implementing the Для просмотра ссылки Войди или Зарегистрируйся (Match Up, Concentration, or whatever you are used to call it). As a proof of concept, I’ve coded a very simple application, aka the front end for the game – juts to have a Для просмотра ссылки Войди или Зарегистрируйся.

Now, the time has come to finish the series and introduce a more eye candy version of the game, one that’s not using dull buttons with numbers for field display values but that actually looks like card game type of Memory, with nice fancy images/icons for game fields. Why stop there? Why not go a step forward and introduce a new dimension for the game: make it 3D having fields appear on planes/layers, so players need to switch between planes to match a pair.

Memory 3D

Here’s the idea: in the standard Memory game, all fields containing game pairs, would be presented to the player at once. Meaning that if the game has 12 fields, that is 6 pairs, all 12 playable fields are visible and the player can pick from to find a match – so basically 2 dimensions: a number of rows and columns where fields are presented in a grid like fashion (say 4×3 for 12 fields).

What if I would to introduce one more, 3rd, dimension: a plane (a layer). So if the game has 8 pairs (16 fields) and 2 planes – only 8 fields are visible/presented to the player at one time. 8 fields on first plane, 8 more on the second plane. So one field of a pair can be on the first plane and the second field can be on the second plane. Player needs to switch between planes to find a match – remember the row and column but also the plane.

Sounds interesting, so let’s see the UI and some code …
For those living by the TL;DR: mantra: Для просмотра ссылки Войди или Зарегистрируйся.

As stated I want to have some graphics displayed on each game field. For this purpose I’ve went to browse the Для просмотра ссылки Войди или Зарегистрируйся web site hosting some free to use icons and graphics. I was looking for some handy set of icons and have found one from Для просмотра ссылки Войди или Зарегистрируйся:

1585520506334.png

There are 10×10 icons/glyphs here – quite enough as that would result in game of Memory of maximum 200 fields (100 pairs). I’ll store the entire image in a hidden “ClipImage” TImage control and will cut out the piece I need for a game field. Since field values would go from 0 to 99 the icon/glyph in second row, third column would have the index of 12. Here’s a function to get the image graphics for a field with the value of “fieldIndex”:

Код:
function TMainForm.GetFieldGraphics(const fieldIndex: integer): TPicture;
var
  clipWidth, clipHeight: Integer;
  srcRect, destRect: TRect;
begin
  clipWidth := ClipImage.Picture.Width div ClipColumns;
  clipHeight := ClipImage.Picture.Height div ClipRows;
  destRect := Rect(0, 0, clipWidth, clipHeight);
  srcRect.Left := (fieldIndex mod ClipColumns) * clipWidth;
  srcRect.Top := (fieldIndex div ClipRows) * clipHeight;
  srcRect.Right := srcRect.Left + clipWidth;
  srcRect.Bottom := srcRect.Top + clipHeight;
  PictureClip.Bitmap.Width := clipWidth;
  PictureClip.Bitmap.Height := clipHeight;
  PictureClip.Bitmap.Canvas.CopyRect(destRect, ClipImage.Canvas, srcRect);
  result := PictureClip;
end;

The UI
The user interface looks pretty much the same as in the 2D version of the game. We need to have a way to switch between planes so 2 more buttons added to the UI. Also, I’ve added some Display options: to display (or not) some field info like what plane are we one, what player has claimed the pair and alike.

1585520521437.png

The New Game
Here’s how the game is created and started:

Код:
procedure TMainForm.btnNewGameClick(Sender: TObject);
var
  newGamePairs, newGamePlayers, newGamePlanes: integer;
  newGameFieldValueShift                     : integer;
begin
  Randomize;
  newGamePairs   := StrToInt(ledPairs.Text);
  newGamePlayers := StrToInt(ledPlayers.Text);;
  newGamePlanes  := StrToInt(ledPlanes.Text);;
  fClipImage     := imgImagesGrid100;
  fClipColumns   := 10;
  fClipRows      := 10;
  fMaxPairs      := fClipColumns * fClipRows;
  //
  if newGamePairs > MaxPairs then
  begin
    newGamePairs  := MaxPairs;
    ledPairs.Text := newGamePairs.ToString;
  end;
  //
  newGameFieldValueShift := Random(MaxPairs - newGamePairs + 1);
  //
  try
    MGame.NewGame(newGamePairs, newGamePlayers, newGamePlanes, newGameFieldValueShift);
  except
    on E: Exception do
    begin
      MessageDlg(E.Message, mtError, [mbOk], -1);
      Exit;
    end;
  end;
end;

Set the wanted number of fields, planes and players. The “newGameFieldValueShift” ensures we always pick random range of icons from the available set – so not to always use the same ones.
The MGame.NewGame would raise the OnGameCreate and OnGameStart events I’m using to setup the user interface. If the total number of fields (2 x number of pairs) is not dividable by the number of planes – the game would raise an exception and would not start.
The OnPlaneChaned even handler is the most interesting one as this is where the icons would be extracted:

Код:
procedure TMainForm.PlaneChanged(Sender: TObject);
var
  i     : integer;
  mField: TMField;
  pnl   : TPanel;
  img   : TImage;
  lbl   : TLabel;
begin
  lblCurrentPlane.Caption := Format('Current plane: %d of %d planes.', [MGame.CurrentPlane, MGame.PlanesCount]);
  // set field hosts for current plane
  for i := 0 to -1 + gameGrid.ControlCount do
  begin
    mField := MGame.Fields[i + MGame.FirstFieldIndexOnCurrentPlane];
    pnl    := TPanel(gameGrid.Controls[i]);
    img    := TImage(pnl.Controls[0]);
    lbl    := TLabel(pnl.Controls[1]);
    if chkShowPlaneInfo.Checked then
    begin
      lbl.Caption := Format('%d / %d / %d', [i + 1, MGame.CurrentPlane, MGame.PlanesCount]);
      lbl.Visible := MGame.PlanesCount > 1;
    end
    else
      lbl.Visible := false;
    //
    mField.Host := img;
    //
    if mField = MGame.OpenedField then
    begin
      pnl.BevelKind := bkTile;
      TImage(mField.Host).Picture.Assign(GetFieldGraphics(mField.Value))
    end
    else
      if mField.Player <> nil then
      begin
        pnl.BevelKind := bkNone;
        TImage(mField.Host).Picture.Assign(GetFieldGraphics(mField.Value));
        if chkShowClaimedInfo.Checked then
        begin
          lbl.Caption := Format('%s', [mField.Player.Name]);
          lbl.Visible := true;
        end;
      end
      else
      begin
        pnl.BevelKind := bkTile;
        TImage(mField.Host).Picture.Assign(imgQuestionField.Picture);
        // TImage(mField.Host).Picture.Assign(GetFieldGraphics(mField.Value))
      end;
  end;
  //
  pnlGameGrid.Refresh;
  //
end;

The rest of the code is more or less the same as in the 2D version of the game.
Hope you like it and if you do a FireMonkey version for mobiles – do share :)
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
My sample to simple way to verify some info about your Wifi connection using new way to ask permissions on Android (7.0 - Nougat)
thanks to FMX Express forum!!!

Dont forget mark your permissions used on Project - Option in your project.

1585529338453.png

[SHOWTOGROUPS=4,19,20]
Код:
unit uMainForm;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  System.Variants,
  System.Permissions, {permissions to app}
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.Controls.Presentation,
  FMX.StdCtrls,
  FMX.ScrollBox,
  FMX.Memo;

type
  TFormMain = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    // FPermissionCamera              : string;
    // FPermissionReadExternalStorage : string;
    // FPermissionWriteExternalStorage: string;
    //
    FPermissionWifiState: string;
    //
    procedure DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
    procedure MyPermissionsRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
    //
{$IFDEF ANDROID}
    procedure prcWifiInfo;
{$ENDIF}
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;

implementation

{$R *.fmx}

uses
  FMX.DialogService
{$IFDEF ANDROID},
  FMX.Helpers.Android,
  Androidapi.JNI.JavaTypes,
  AndroidApi.Helpers,
  AndroidApi.JNI.OS,
  AndroidApi.JNI.net,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNIBridge
{$ENDIF}
    ;

{ How to working with new way when asking permission in Android:
  0 - Always inform to the user that permissions your app needs. When it needs it!
  1 - Define what permissions your app needs!
  2 - Ask the permissions when needs! // Android can help here asking only 1x to user!
  3 - Test if your permissions is allowed!
}

procedure TFormMain.Button1Click(Sender: TObject);
begin
  // ...testing only in Android
{$IFDEF ANDROID}
  // Asking permission to access "YOUR NECESSITY" in your Android...
  PermissionsService.RequestPermissions( { }
    [FPermissionWifiState],              { <--- ... I need this permission [ a, b, c, d, ...] }
    MyPermissionsRequestResult,          { <-- callback function to each permission }
    DisplayRationale                     { <-- to show the message for each permission - Always Non-Modal!!! }
    );
{$ENDIF}
end;

procedure TFormMain.DisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
var
  I           : Integer;
  RationaleMsg: string;
begin
  for I := 0 to high(APermissions) do
  begin
    if APermissions[I] = FPermissionWifiState then
      RationaleMsg := RationaleMsg + 'The app needs to access your "<<YOUR NECESSITY HERE>>"' + SLineBreak + SLineBreak;
  end;
  //
  // Show an explanation to the user *asynchronously* - don't block this thread waiting for the user's response!
  // After the user sees the explanation, invoke the post-rationale routine to request the permissions
  //
  TDialogService.ShowMessage(RationaleMsg,
    procedure(const AResult: TModalResult)
    begin
      // TProc is defined in System.SysUtils
      //
      APostRationaleProc; // used by System to go-back in before function...
    end)
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
  // FPermissionCamera               := JStringToString(TJManifest_permission.JavaClass.CAMERA);
  // FPermissionReadExternalStorage  := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
  // FPermissionWriteExternalStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
  //
  FPermissionWifiState := JStringToString(TJManifest_permission.JavaClass.ACCESS_WIFI_STATE); // dont need ask permission!
{$ENDIF}
end;

procedure TFormMain.MyPermissionsRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
  // 1 permission = ACCESS_WIFI_STATE
  if (Length(AGrantResults) = 1) and               { }
    (AGrantResults[0] = TPermissionStatus.Granted) { }
  then
{$IFDEF ANDROID}
    prcWifiInfo { execute your procedure here if all it's ok }
{$ENDIF}
  else
    TDialogService.ShowMessage('The permission <<YOUR NECESSITY HERE>>  not allowed by user'); // msg to ACCESS_WIFI_STATE, for example
end;

{$IFDEF ANDROID}

procedure TFormMain.prcWifiInfo;
var
  WifiManagerObj: JObject;
  WifiManager   : JWifiManager;
  WifiInfo      : JWifiInfo;
begin
  WifiManagerObj := SharedActivityContext.getSystemService(TJContext.JavaClass.WIFI_SERVICE);
  //
  WifiManager := TJWifiManager.Wrap((WifiManagerObj as ILocalObject).GetObjectID);
  //
  WifiInfo := WifiManager.getConnectionInfo();
  //
  Memo1.Lines.Clear;
  Memo1.Lines.Add('FPermissionWifiState = ' + FPermissionWifiState);
  Memo1.Lines.Add('Wifi Enabled: ' + WifiManager.isWifiEnabled.ToString);
  Memo1.Lines.Add('Wifi State: ' + WifiManager.getWifiState.ToString);
  Memo1.Lines.Add('Ping Supplicant: ' + WifiManager.pingSupplicant.ToString);
  Memo1.Lines.Add('BSSID: ' + JStringToString(WifiInfo.getBSSID));
  Memo1.Lines.Add('HiddenSSID: ' + WifiInfo.getHiddenSSID.ToString);
  Memo1.Lines.Add('IpAddress: ' + WifiInfo.getIpAddress.ToString);
  Memo1.Lines.Add('LinkSpeed: ' + WifiInfo.getLinkSpeed.ToString + 'Mbps');
  Memo1.Lines.Add('MacAddress: ' + JStringToString(WifiInfo.getMacAddress));
  Memo1.Lines.Add('NetworkId: ' + WifiInfo.getNetworkId.ToString);
  Memo1.Lines.Add('Rssi: ' + WifiInfo.getRssi.ToString + 'dBm');
  Memo1.Lines.Add('SSID: ' + JStringToString(WifiInfo.getSSID));
  Memo1.Lines.Add('SupplicantState: ' + JStringToString(WifiInfo.getSupplicantState.toString));
end;
{$ENDIF}

end.
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Auto-start custom Android applications
- Not necessary any change on sources Android!

[SHOWTOGROUPS=4,19,20]
thanks to Digi International Inc. (2019)

Auto-start custom Android applications

When creating customized Android firmware, you must typically launch a specific Android application after system boots. Android has two mechanisms for this:

Start an application after Android boot:
Valid for a standard Android system with multiple applications.
No need to modify and compile Android sources.
Replace the default Android Home application:
Recommended if your system consists only of this application.
May require you to modify and compile Android sources.
Start an application after Android boot

When an Android system boots, it sends out a boot complete event. Android applications can listen and capture this event to take specific actions, such as automatically starting an activity or service.

You can use this mechanism to create an application with the required permissions to listen for the boot complete event and automatically start an activity or service every time Android starts up. To do so, follow these steps:

Declare the permission in AndroidManifest.xml. Add the android.permission.RECEIVE_BOOT_COMPLETED permission to your application's manifest file just before the application declaration node:
AndroidManifest.xml
Код:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Define the Activity that will be auto-started in the AndroidManifest.xml. Place this declaration inside the application node:
AndroidManifest.xml
Код:
<activity
    android:name=".MyActivity"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Register the Receiver listening for the boot complete event in the AndroidManifest.xml. Place this declaration inside the application node:
AndroidManifest.xml
Код:
<receiver
    android:name=".StartMyActivityAtBootReceiver"
    android:label="StartMyServiceAtBootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Create the receiver class to listen for the boot complete event. This class must extend BroadcastReceiver abstract class. Its onReceive() method is called when the device boot is complete. For example, create a Java class called StartMyActivityAtBootReceiver.java and place it in the same package as the activity class to auto-start:
Код:
StartMyActivityAtBootReceiver
public class StartMyActivityAtBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            Intent activityIntent = new Intent(context, MyActivity.class);
            activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(activityIntent);
        }
    }
}

When this class receives an intent, it checks if it is the ACTION_BOOT_COMPLETE. If so, it creates a new activity intent and fills it with the activity class to be started. Finally, it executes the startActivity() method using the Android context and the activity intent.

Note Due to security reasons, Android does not auto-start any application until you manually launch it at least once. After that, the applications will automatically start on each Android boot.

Replace the default Android Home application
The home screen you see on your Android device after boot is a standard application that reacts to a home event. When Android finishes booting and is ready to start the home activity, the home event is sent and qualifying applications identify themselves as bootable candidates.

The system sends out the android.intent.category.HOME and android.intent.category.DEFAULT intents when it is done initializing.

Android looks for application manifests with these intent filters when it starts up. If there is more than one, Android lists all of them and allows you to select the one to launch.

In order to designate your application as a home application, follow these steps:

Add the intent filters to AndroidManifest.xml. Copy these two lines into the intent filter of your application main activity:
Код:
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />

Your main activity definition should look similar to the following:
AndroidManifest.xml
Код:
<activity
    android:name=".MyActivity"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.HOME" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Install your application in the device. On the next startup, Android displays a dialog box that allows you to choose between the default Android launcher and the application you just modified:

1585704026825.png

Note You can set your selection as the default home application for the future.

Replace default Home application with a custom application in sources
The Replacing the default Android Home procedure is only valid for already-deployed Android systems. If you want to deploy an Android system with a custom home application already designated, you must make additional changes to the Android BSP sources:

Create a custom home application and include it in the Android BSP sources. You can directly include the application source code or a pre-compiled version of it.
Note Verify that your custom Android home application includes the android.intent.category.HOME and android.intent.category.DEFAULT intent filters in the application manifest file.

Force your application to override the default launcher applications. Add the following entry in your application's Android.mk file just before the include $(BUILD_PACKAGE) line:
Код:
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3

Your application's Android.mk file should look similar to the following:

Android.mk
Код:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := android-common android-support-v13
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := MyApplication
LOCAL_CERTIFICATE := shared
LOCAL_PRIVILEGED_MODULE := true
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
include $(BUILD_PACKAGE)

Include your application in the Android firmware build. Add your application's module name "MyApplication" (as defined in the LOCAL_PACKAGE_NAME of your Application's Android.mk file) to the list of packages of the firmware at device/digi/imx6_ccimx6_sbc/imx6_ccimx6_sbc.mk:
imx6_ccimx6_sbc.mk
Код:
[...]
PRODUCT_PACKAGES += MyApplication
[...]

Build the Android firmware. Issue this command sequence in the root folder of the Android sources.
Clean the artifacts from the previous build:
Код:
$ make installclean
Build the Android firmware:$ make -j<Number_Of_Jobs>

<Number_Of_Jobs> is the number of cores you want to use for the build process.

The resulting firmware will boot your custom Android home application by default.

[/SHOWTOGROUPS]
 
Статус
В этой теме нельзя размещать новые ответы.