Reputation: 77
Using Delphi 10.4.2 FireMonkey, targeting Android 10 x64.
I'm trying to take a photo and save it for later processing.
First I've tried to use the built-in TTakePhotoFromCameraAction
, but the OnDidFinishTaking
event doesn't work (the camera screen is visible, I can take the photo and press "ok"), my program shows up, but my TakePhotoFinishTaking()
method is not called.
procedure TMainForm.TakePhotoFinishTaking(Image: TBitmap);
begin
DebugEnter(0, self, 'TakePhotoFinishTaking', [Image]);
HidePopup;
SetBilderActions(false);
try
PicGrid.RowCount := PicGrid.RowCount+1;
InsertImageItem('', Image, PicGrid.RowCount-1);
finally
SetBilderActions(true);
end;
DebugLeave(0, self, 'TakePhotoFinishTaking');
end;
Next I tried to use IFMXCameraService
directly:
procedure TMainForm.btKameraClick(Sender: TObject);
var
Service: IFMXCameraService;
Params : TParamsPhotoQuery;
begin
DebugEnter(0, self, 'btKameraClick', [Sender]);
if PermissionsService.IsEveryPermissionGranted([cPermissionCamera, cPermissionReadExternalStorage, cPermissionWriteExternalStorage]) then begin
if TPlatformServices.Current.SupportsPlatformService(IFMXCameraService, Service) then begin
Params.RequiredResolution := TSize.Create(640, 640);
Params.Editable := false;
Params.NeedSaveToAlbum := true;
Params.OnDidFinishTaking := TakePhotoFinishTaking;
Params.OnDidCancelTaking := NIL;
Service.TakePhoto(NIL, Params);
end else begin
FMX.DialogService.ASync.TDialogServiceAsync.MessageDialog('Kamerafunktion wird auf diesem Gerät nicht unterstützt!', TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], TMsgDlgBtn.mbOK, 0)
end;
end else begin
FMX.DialogService.ASync.TDialogServiceAsync.MessageDialog('Keine Kamera oder externer Speicher Rechte!', TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], TMsgDlgBtn.mbOK, 0)
end;
DebugLeave(0, self, 'btKameraClick');
end;
Same result: I see the camera screen, take a photo, press Ok, my program comes back, but no OnDidFinishTaking
event.
Then I've tried to intercept the messages from the Photo app:
FFinishTakingCamPhotoId := TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromCamera, HandleMessage);
FFinishTakingLibPhotoId := TMessageManager.DefaultManager.SubscribeToMessage(TMessageDidFinishTakingImageFromLibrary, HandleMessage);
FMessageReceivedImagePath := TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedImagePath, HandleMessage);
All of the subcribeToMessage()
calls are returning an ID, but HandleMessage()
is NEVER being called for these Types.
This Message (for example) is working very well!
FOrientationChangedId := TMessageManager.DefaultManager.SubscribeToMessage(TOrientationChangedMessage, HandleMessage);
procedure TMainForm.HandleMessage(const Sender: TObject; const Msg: TMessage);
var
ImgPath : String;
begin
DebugEnter(0, self, 'HandleMessage', [Sender, Msg]);
{$IFDEF Android}
if Msg is TMessageResultNotification then begin
DebugMsg(0, 'TMessageResultNotification');
OnActivityResult(TMessageResultNotification(Msg).RequestCode, TMessageResultNotification(Msg).ResultCode, TMessageResultNotification(Msg).Value);
end;
if Msg is TMessageDidFinishTakingImageFromCamera then begin
DebugMsg(0, 'TMessageDidFinishTakingImageFromCamera');
TakePhotoFinishTaking(TMessageDidFinishTakingImageFromCamera(Msg).Value);
end;
if Msg is TMessageReceivedImagePath then begin
DebugMsg(0, 'TMessageReceivedImagePath');
ImgPath := TMessageReceivedImagePath(Msg).Value;
end;
if Msg is TMessageDidFinishTakingImageFromLibrary then begin
DebugMsg(0, 'TMessageDidFinishTakingImageFromLibrary');
TakePhotoFinishTaking(TMessageDidFinishTakingImageFromLibrary(Msg).Value);
end;
{$ENDIF}
What am I doing wrong?
Upvotes: 2
Views: 1353
Reputation: 77
Ok - Problem solved. It was an old Projekt and that was missing the option android:requestLegacyExternalStorage="true" in the application node of Androidmanifest-template.xml.
After fixing this all works fine, even the TakePhotoFromCameraAction with ObDidFinishTaking Event.
Unfortunately there is no Error or Exception where executed...
Thanks @Dave for pointing me in the right direction!
Upvotes: 1
Reputation: 3612
The reason why your app is not receiving the TMessageDidFinishTakingImageFromCamera
message is that the message is not sent if OnDidFinishTaking
is assigned to the Params
, as per the code in FMX.MediaLibrary.Android
:
procedure TImageManagerAndroid.DidReceiveBitmap(const Sender: TObject; const M: TMessage);
var
ImagePath: string;
Photo: TBitmap;
RequestCode: Integer;
begin
if M is TMessageReceivedImagePath then
begin
ImagePath := TMessageReceivedImagePath(M).Value;
RequestCode := TMessageReceivedImagePath(M).RequestCode;
Photo := TBitmap.CreateFromFile(ImagePath);
try
if Assigned(FParams.OnDidFinishTaking) then
FParams.OnDidFinishTaking(Photo)
else
begin
if RequestCode = TJFMXMediaLibrary.JavaClass.ACTION_TAKE_IMAGE_FROM_CAMERA then
TMessageManager.DefaultManager.SendMessage(Self, TMessageDidFinishTakingImageFromCamera.Create(Photo));
if RequestCode = TJFMXMediaLibrary.JavaClass.ACTION_TAKE_IMAGE_FROM_LIBRARY then
TMessageManager.DefaultManager.SendMessage(Self, TMessageDidFinishTakingImageFromLibrary.Create(Photo));
end;
finally
Photo.Free;
end;
end;
end;
The following code, which is essentially the equivalent as yours, works fine for me using Delphi 10.4.2:
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.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.Objects;
type
TForm1 = class(TForm)
Layout1: TLayout;
Button1: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
private
FCameraPermissions: TArray<string>;
procedure CameraDidFinishTakingHandler(Image: TBitmap);
procedure TakePhoto;
public
constructor Create(AOwner: TComponent); override;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses
System.Permissions,
FMX.Platform.Android,
FMX.MediaLibrary, FMX.Platform;
const
cPermissionCamera = 'android.permission.CAMERA';
cPermissionReadExternalStorage = 'android.permission.READ_EXTERNAL_STORAGE';
cPermissionWriteExternalStorage = 'android.permission.WRITE_EXTERNAL_STORAGE';
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
FCameraPermissions := [cPermissionReadExternalStorage, cPermissionWriteExternalStorage, cPermissionCamera];
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
PermissionsService.RequestPermissions(FCameraPermissions,
procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
begin
if PermissionsService.IsEveryPermissionGranted(FCameraPermissions) then
TakePhoto;
end
);
end;
procedure TForm1.TakePhoto;
var
LCameraService: IFMXCameraService;
LParams: TParamsPhotoQuery;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXCameraService, LCameraService) then
begin
LParams.RequiredResolution := TSize.Create(640, 640);
LParams.Editable := False;
LParams.NeedSaveToAlbum := True;
LParams.OnDidFinishTaking := CameraDidFinishTakingHandler;
LParams.OnDidCancelTaking := nil;
LCameraService.TakePhoto(nil, LParams);
end;
end;
procedure TForm1.CameraDidFinishTakingHandler(Image: TBitmap);
begin
Image1.Bitmap.Assign(Image);
end;
end.
Upvotes: 2