Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e691f6d
Small changes for Android
lmbelo May 31, 2021
1a79b32
Small changes for android
lmbelo May 31, 2021
d5ad2e6
Python distribution finder app - used on pre-build event of sample apps
lmbelo Jun 1, 2021
b5bdddd
Python distributions
lmbelo Jun 1, 2021
87b6729
Base Android sample project
lmbelo Jun 1, 2021
c9ef931
Android conditionals
lmbelo Jun 3, 2021
317cce4
Android test cases project
lmbelo Jun 3, 2021
66ed9d9
Helper class for loading Python lib
lmbelo Jun 3, 2021
da03d4c
Test case - Check up Python environment on Android
lmbelo Jun 3, 2021
8078105
Test case - Check up functionality for Python types on a custom varia…
lmbelo Jun 3, 2021
73a388c
Test case - Check up numeric operations
lmbelo Jun 3, 2021
87352ac
Renamed PyEnv test case unit to the desired patter name
lmbelo Jun 3, 2021
9ec1662
Test case - Check up method callback
lmbelo Jun 3, 2021
34fea3d
MethodCallBack for ARM processor
lmbelo Jun 22, 2021
a40b688
Patching bugs on Android
lmbelo Jul 20, 2021
f520794
Wrap Delphi unit test
lmbelo Jul 20, 2021
aafb166
MethodCallback unit test adjustments
lmbelo Jul 20, 2021
69dcde0
NumberServices unit test adjustments
lmbelo Jul 20, 2021
92d87d2
PyEnv unit test adjustments
lmbelo Jul 20, 2021
ec0411b
PythonLoad unit adjustments
lmbelo Jul 20, 2021
aceeb95
VarPyth unit test adjustments
lmbelo Jul 20, 2021
2c4bed6
Including WrapDelphiTest unit to project
lmbelo Jul 20, 2021
04e9151
x64 method callback version
lmbelo Aug 1, 2021
5dd8a38
Small adjustments
lmbelo Aug 1, 2021
f40f3f0
Fixing 'GetDispatchInvokeArgs' for x64
lmbelo Aug 1, 2021
0caf39e
Adjustments for x64
lmbelo Aug 1, 2021
794f020
Removing the Android conditional. CPUX64 is not present under DCCAARM…
lmbelo Aug 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Demos/FMX/Android/Demo00/AndroidManifest.template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="%package%"
android:versionCode="%versionCode%"
android:versionName="%versionName%"
android:installLocation="%installLocation%">

<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
<%uses-permission%>
<uses-feature android:glEsVersion="0x00020000" android:required="True"/>
<application android:persistent="%persistent%"
android:restoreAnyVersion="%restoreAnyVersion%"
android:label="%label%"
android:debuggable="%debuggable%"
android:largeHeap="%largeHeap%"
android:icon="%icon%"
android:theme="%theme%"
android:hardwareAccelerated="%hardwareAccelerated%"
android:resizeableActivity="false"
android:requestLegacyExternalStorage="true">

<%provider%>
<%application-meta-data%>
<%uses-libraries%>
<%services%>
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:label="%activityLabel%"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:launchMode="singleTask">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="%libNameValue%" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<%activity%>
<%receivers%>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
165 changes: 165 additions & 0 deletions Demos/FMX/Android/Demo00/AppEnvironment.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
(**************************************************************************)
(* *)
(* Module: Unit 'AppEnvironment' Copyright (c) 2021 *)
(* *)
(* Lucas Moura Belo - lmbelo *)
(* lucas.belo@live.com *)
(* Brazil *)
(* *)
(* PyScripter *)
(* e-mail: pyscripter@gmail.com *)
(* *)
(* Project pages: https://github.com/Embarcadero/python4delphi *)
(* https://github.com/pyscripter/python4delphi *)
(**************************************************************************)
(* Functionality: App environment set up *)
(* *)
(* *)
(**************************************************************************)
(* This source code is distributed with no WARRANTY, for no reason or use.*)
(* Everyone is allowed to use and change this code free for his own tasks *)
(* and projects, as long as this header and its copyright text is intact. *)
(* For changed versions of this code, which are public distributed the *)
(* following additional conditions have to be fullfilled: *)
(* 1) The header has to contain a comment on the change and the author of *)
(* it. *)
(* 2) A copy of the changed source has to be sent to the above E-Mail *)
(* address or my then valid address, if this is possible to the *)
(* author. *)
(* The second condition has the target to maintain an up to date central *)
(* version of the component. If this condition is not acceptable for *)
(* confidential or legal reasons, everyone is free to derive a component *)
(* or to generate a diff file to my or other original sources. *)
(**************************************************************************)
unit AppEnvironment;

interface

uses
System.Classes, System.SysUtils, System.Threading, System.Zip, PythonEngine;

type
IProgressNotifier = interface
['{7A2D1743-D4D8-4093-B372-04D814536708}']
procedure Start(const ADescription, AFirstAction: string; const ATotal: Int64);
procedure Update(const ACurrentAction: string; const AProgress: Int64);
procedure Stop();
end;

TAppEnvInit = reference to procedure(const AInitialized: boolean; const ALastErrorMsg: string);

TAppEnvironment = class
private
FInitialized: boolean;
FProgressNotifier: IProgressNotifier;
procedure OnZipProgressEvent(Sender: TObject; FileName: string; Header: TZipHeader; Position: Int64);
procedure DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
const ACheckPyLib: boolean = true);
public
constructor Create(const AProgressNotifier: IProgressNotifier);

procedure InitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
const ACheckPyLib: boolean; const AAppEnvInit: TAppEnvInit);

property Initialized: boolean read FInitialized;
end;

implementation

uses
System.IOUtils, FMX.Dialogs, PythonLoad;

{ TAppEnvironment }

constructor TAppEnvironment.Create(const AProgressNotifier: IProgressNotifier);
begin
Assert(Assigned(AProgressNotifier), '"AProgressNotifier" undefined');
FInitialized := false;
FProgressNotifier := AProgressNotifier;
end;

procedure TAppEnvironment.DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
const ACheckPyLib: boolean = true);
begin
try
//Lock user iteractions
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Start('Searching for Python installation', String.Empty, 0);
end);

Sleep(200);

//Python distibution unzip
TPythonLoad.Extract(
procedure(const AFolderExists: boolean; var AReplaceFiles: boolean) begin
if not AFolderExists then begin
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Start('Installing Python', String.Empty, 0);
end);
end;
AReplaceFiles := false;
end, OnZipProgressEvent);

//Configure Python for Android
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Start('Configuring Python for Android', String.Empty, 3);
FProgressNotifier.Update('Check for files', 1)
end);

TPythonLoad.Configure(APythonEngine);
Sleep(1000);

//Load python library
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Start('Loading Python', String.Empty, 3);
FProgressNotifier.Update('Loading and mapping library', 2)
end);

TThread.Synchronize(nil, procedure() begin
APythonEngine.LoadDll();
end);
Sleep(1000);

//All done notification
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Start('Loading environment', String.Empty, 3);
FProgressNotifier.Update('All ready', 3)
end);
Sleep(1000);
finally
TThread.Synchronize(nil, procedure() begin
FProgressNotifier.Stop();
end);
end;
end;

procedure TAppEnvironment.InitializeEnvironmentAsync(
const APythonEngine: TPythonEngine; const ACheckPyLib: boolean;
const AAppEnvInit: TAppEnvInit);
begin
TTask.Run(
procedure() begin
try
DoInitializeEnvironmentAsync(APythonEngine, ACheckPyLib);
FInitialized := true;
if Assigned(AAppEnvInit) then
AAppEnvInit(true, String.Empty);
except
on E: Exception do begin
if Assigned(AAppEnvInit) then
AAppEnvInit(false, E.Message);
end;
end;
end);
end;

procedure TAppEnvironment.OnZipProgressEvent(Sender: TObject; FileName: string;
Header: TZipHeader; Position: Int64);
begin
TThread.Queue(nil, procedure() begin
FProgressNotifier.Start('Extracting files', String.Empty, Header.UncompressedSize);
FProgressNotifier.Update(TPath.GetFileName(FileName), Position);
end);
end;

end.
180 changes: 180 additions & 0 deletions Demos/FMX/Android/Demo00/MainForm.fmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
object PyMainForm: TPyMainForm
Left = 0
Top = 0
Caption = 'MainForm'
ClientHeight = 743
ClientWidth = 349
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnCreate = FormCreate
OnDestroy = FormDestroy
DesignerMasterStyle = 3
object spInputOutput: TSplitter
Align = Top
Cursor = crVSplit
MinSize = 20.000000000000000000
Position.Y = 265.000000000000000000
Size.Width = 349.000000000000000000
Size.Height = 8.000000000000000000
Size.PlatformDefault = False
end
object tbTop: TToolBar
Size.Width = 349.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
object Label1: TLabel
Align = Client
Size.Width = 349.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
StyleLookup = 'toollabel'
TextSettings.HorzAlign = Center
Text = 'Python4Delphi - PyLoad'
TabOrder = 1
end
end
object tbBottom: TToolBar
Align = Bottom
Position.Y = 695.000000000000000000
Size.Width = 349.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
TabOrder = 1
object btnRun: TButton
Action = actRun
Align = Center
Enabled = True
ImageIndex = -1
Size.Width = 48.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
StyleLookup = 'playtoolbutton'
TabOrder = 0
end
end
object Layout1: TLayout
Align = Top
Position.Y = 48.000000000000000000
Size.Width = 349.000000000000000000
Size.Height = 217.000000000000000000
Size.PlatformDefault = False
TabOrder = 5
object mmOutput: TMemo
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
DataDetectorTypes = []
ReadOnly = True
Align = Client
Margins.Left = 10.000000000000000000
Margins.Top = 10.000000000000000000
Margins.Right = 10.000000000000000000
Size.Width = 329.000000000000000000
Size.Height = 207.000000000000000000
Size.PlatformDefault = False
TabOrder = 1
Viewport.Width = 321.000000000000000000
Viewport.Height = 199.000000000000000000
end
object Layout2: TLayout
Anchors = [akRight, akBottom]
Position.X = 284.000000000000000000
Position.Y = 163.000000000000000000
TabOrder = 6
object Circle1: TCircle
Align = Contents
Fill.Color = claGainsboro
Size.Width = 50.000000000000000000
Size.Height = 50.000000000000000000
Size.PlatformDefault = False
Stroke.Thickness = 0.000000000000000000
end
object btnClearOutput: TButton
Action = actClearOutput
Align = Client
Enabled = True
ImageIndex = -1
Size.Width = 48.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
StyleLookup = 'trashtoolbutton'
TabOrder = 3
end
end
end
object Layout3: TLayout
Align = Client
Size.Width = 349.000000000000000000
Size.Height = 422.000000000000000000
Size.PlatformDefault = False
TabOrder = 6
object mmInput: TMemo
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
DataDetectorTypes = []
Align = Client
Margins.Left = 10.000000000000000000
Margins.Right = 10.000000000000000000
Margins.Bottom = 10.000000000000000000
Size.Width = 329.000000000000000000
Size.Height = 412.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
Viewport.Width = 321.000000000000000000
Viewport.Height = 404.000000000000000000
end
object Layout4: TLayout
Anchors = [akRight, akBottom]
Position.X = 284.000000000000000000
Position.Y = 358.000000000000000000
TabOrder = 6
object Circle2: TCircle
Align = Contents
Fill.Color = claGainsboro
Size.Width = 50.000000000000000000
Size.Height = 50.000000000000000000
Size.PlatformDefault = False
Stroke.Thickness = 0.000000000000000000
end
object btnClearInput: TButton
Action = actClearInput
Align = Client
Enabled = True
ImageIndex = -1
Size.Width = 48.000000000000000000
Size.Height = 48.000000000000000000
Size.PlatformDefault = False
StyleLookup = 'trashtoolbutton'
TabOrder = 3
end
end
end
object PythonEngine1: TPythonEngine
AutoLoad = False
IO = PythonGUIInputOutput1
Left = 258
Top = 56
end
object PythonGUIInputOutput1: TPythonGUIInputOutput
UnicodeIO = True
RawOutput = False
Output = mmOutput
Left = 259
Top = 112
end
object ActionList1: TActionList
Left = 288
Top = 320
object actRun: TAction
Text = 'Run'
OnExecute = actRunExecute
end
object actClearOutput: TAction
Text = 'actClearOutput'
OnExecute = actClearOutputExecute
end
object actClearInput: TAction
Text = 'actClearInput'
OnExecute = actClearInputExecute
end
end
end
Loading