Jump to content
Chester Wilson

android camera problem

Recommended Posts

I am having great difficulty getting a firemonkey programme to take piccies on an android device.

 

This is the simplest programme I have managed to put together for this.  It keeps blowing up no matter what I try!

(I have put 3 full days work into it, with no success, and now seek help!)


I am using Delphi in Embarcadero® RAD Studio 10.4 Version 27.0.37889.9797
(it will be a month before I can get home to download Sydney).

The phone I am working on is a Huawei P20 Pro with android 10 (can I have
android 7 back please?????)

 

I got Marco's GitHub main form for a camera, and got the same error from it.

I wondered if it were a Delphi bug, and sent it off to Quality.Embarcadero.
Dave Nottage kindly replied, telling me to set the permissions.  However,
if the permissions are not set, the error message is different, and setting
the permissions did not help.  I sent back that Dave's considered response did
not help any, but have heard nothing since.

 

It is necessary to run it once, then go and set up the android settings permissions
since android have become cripplingly paranoid from V10.

 

The error message is:
Project TryCamera1.spk raised exception class EJNIException with message
'java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData
(android.content.pm.PackageManager, java.lang.String)' on a null object reference'.

 

The crash comes on ExecuteTarget in FMX.MediaLibrary.Action
where it is called with FCameraService.TakePhoto

TryCamera1.dpr

TryCamera1.dproj

TryCamera1.dproj.local

TryCamera1.identcache

TryCamera1.res

TryCameraMainUnit.fmx

TryCameraMainUnit.pas

TryCameraMainUnit1.fmx

TryCameraMainUnit1.pas

Share this post


Link to post
Guest

hi @Chester Wilson 

 

try my CAM for Android test based on Fernando Rizzato (MVP leader Embarcadero on South America)

 

 

hug

Edited by Guest

Share this post


Link to post

Thanks, hug!  I will tackle it over the next few days.

Even if the permissions for a programme have been set in "Settings" on an android device, and set up in the programme (project/options etc), is it still necessary to go through all the code for the permissions in the programme as well?  Or is that so that the user can get an error message telling him which permissions have not been set?

Share this post


Link to post
Guest
6 hours ago, Chester Wilson said:

...Or is that so that the user can get an error message telling him which permissions have not been set?

your software, SHOULD verify if the permissions was or not conceded by Android (OS) - ALWAYS!

the Android, as know, store this info for each app, but, the app should verify if the permissions still granted!

 

hug

Share this post


Link to post

Have you any idea how to get location permission not only for when the programme is the primary one on the screen, but always?  In earlier androids I could continue tracking, go off an do something else briefly, then return to the tracking programme.  In recent androids this turns off the location to the tracking programme, really messing up the data collection!  (Why they think location is a dangerous privilege I do not know.  The only time I can see it being dangerous is if I am going somewhere where my wife does not want me to go, and she finds out about it!)

Share this post


Link to post
Guest

in app, one time conceded the permition by user, it stay until he remove the app or the permitions.

now, about Android O.S., you can go in SETUP-APPLICATION find you app and change or see its permitions. or click on app-icon and hold until appears some menu.

 

https://developer.android.com/guide/topics/permissions/overview

 

note: my nickname is EMAILX45  not HUG  😂

 

hug

Edited by Guest

Share this post


Link to post

Hello Hug emailx54 and Chester,

isnt it that nowadays the Android system uses stronger battery saving features?

To always be able to run tasks in background is what a User tells his Android -> allow/set background-tasks manually.

Am i wrong?

 

I just found this info about how to create background tasks, there is nothing about Android setting explained... mhhhhh strange world.

 

noHug, Corona forbid it :-]

Share this post


Link to post

Sorry, EmailX45!  I will accept the "hug" at the bottom of your email as a friendly "man hug" and call you by your preferred name!

 

The problem is that the later versions of android will only allow you in the "Settings" for a programme to have location as  either deniet or "Only while app is in use"!

It seems to be part of their idea that some permissions are regarded as "dangerous", and therefore are limited in their availability.  Unfortunately I need to be able

to continue tracking (small furry animals in remote areas of Australia) without interruption - and I cannot find out how to get android to cooperate!!!!

i go to another app briefly, and the GPS gets turned off my tracking programme!  This is a real problem, and I would like to get a useful answer to it.

Any idea whom I should ask?

 

Share this post


Link to post
Guest

hi @Chester Wilson

 

in Android 9/10 you need to say that you "need that your app dont use POWER MANAGEMENT...", or be, you need exclude your app this behavior.

Manually, you need find your app, and, in Battery options, say that your app dont "SLEEP" in background.

Then, here, you need access the permitions more restrictive on system.

 

Many app, should use a certificate for that, for security, as say the Android rules in link above. You see?

Unfortunatelly, I dont have a sample for this in my tests for Android.

 

But, basically, you needs ask the permittions for access this area on Android for you app. For that, the restriction for security area on Android, else, any app would can access this area and access the user-datas.

and, location is a basic area to find a user in a city for example... now, imagine you been followed by a "psico-killer"  hmmmmmmmm :classic_cheerleader:

 

hug

Share this post


Link to post
Guest
14 hours ago, KodeZwerg said:

To always be able to run tasks in background is what a User tells his Android -> allow/set background-tasks manually.

yes and not.

Yes, for that user know this necessity.

No, because, in programming you can do it.

please, read the Android permitions (link above), and the secction about "use of certifacates" for OEM Android.

As in another area, web for example, and today in many others "local" places, the certificate use, do more simple truth a app/user as secure or same give-a-pass as right.

 

hug

Share this post


Link to post
1 hour ago, emailx45 said:

yes and not.

Yes, for that user know this necessity.

No, because, in programming you can do it.

please, read the Android permitions (link above), and the secction about "use of certifacates" for OEM Android.

As in another area, web for example, and today in many others "local" places, the certificate use, do more simple truth a app/user as secure or same give-a-pass as right.

 

hug

With my current little level of knowledge about Android internals, I can only say that you can't force it on the program level.
But what you can do is to use the release authorizations (permissions) to oblige the user to enter into a contract with you.
So the user is the decisive factor. (As always hehehe)

Since my knowledge is poor I will do follow your advice with glance and put my head into documention.

 

Hugging thanks back.

Share this post


Link to post
Guest

remember, some "techs" is not allowed, but, it's possible... else, we would have no problems with adware, spyware, and other virus-family ...

now, with a 'truth certificate' you can do it. 

 

hug

Edited by Guest

Share this post


Link to post

Well, fellas, thanks for your ideas.  I can request required permissions now, and get some of them! (Why it won't give me WAKE_LOCK I know not.  Reasonable not to give me ELEPHANT though!)

The location one still comes up with the annoyance of "only while active".  I am not sure that the argument about a tracking predator is good enough to bugger it up for everyone, especially as a tracking predator would have to get hold of the victim's phone and set it all up.  However, it really buggers up my job of tracking small furry mammals in the middle of Australia!  I could not find anything explanatory in the suggested reading on certificates, how to use them, where to get them, and what they may be capable of doing for this problem.

 

Unfortunately, I have had no luck with the camera stuff.  I have taken your ideas, and other ideas from the net, and put together two means of accessing the camera.  Neither of them works, and they still prang with the extremely unhelpful message of :

 

"java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager,java.lang.String)' on a null object reference."

 

The sample files are attached in a single .zip.

 

I would greatly appreciate any ideas, as the various delphi help facilities and the net have been no help at all!

 

Permissions.zip

Share this post


Link to post
Guest

hi @Chester Wilson

 

try review your code!!! really it is not good at all... if it should works... really, I dont know! Your environment, your problems.

 

try this changes and other if necessar

... when clicking in button to take a picture or choice the CAM
	
  PermissionsService.RequestPermissions( { }
  [lMyCAMPermission],                    { }
  prcPermissionsResulted,                { }
  prcDisplayRationale                    { = nil, if you DONT WANT show any message! }
  );
  
  
//******************************************
{$IF DEFINED(ANDROID)}  // DisplayRationale and PermissionsResulted is used only mobile!

procedure TfrmFormMain.prcDisplayRationale(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
var
  lRationaleMsg: string;
  i            : integer;
begin
  for i := 0 to high(APermissions) do
  begin
    if APermissions[i] = lMyCAMPermission then
      lRationaleMsg := lRationaleMsg + 'This app needs access your CAM to works' + 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(lRationaleMsg,
      procedure(const AResult: TModalResult)
    begin
      // TProc is defined in System.SysUtils
      //
      APostRationaleProc; // used by System to go-back in before function...
    end)
end;

procedure TfrmFormMain.prcPermissionsResulted(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
  // verifying if the permissions was granted! - Here, testing only 1 permission = CAM
  if (Length(AGrantResults) = 1) {my CAM permission} and (AGrantResults[0] = TPermissionStatus.Granted) {was granted or not?} then
    //
	// here it's where your CAM should have the permission confirmed or not by System!!!
    prcCAMStartCapture { execute your procedure here if all it's ok }
	///
  else
    TDialogService.ShowMessage('The permission <<CAMERA access>> not allowed by user');
end;
{$ENDIF}


//*****************************************************
// same unit than your procedure to CAM use, or in any other levelup
// the "initialization section" is called on "order than unit-use", or be, in "uses clauses" order
//
initialization

// prefere use here!!!
aPermissions[0] := JStringToString(TJManifest_permission.JavaClass.CAMERA);
aPermissions[1] := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
aPermissions[2] := JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION);
aPermissions[3] := JStringToString(TJManifest_permission.JavaClass.ACCESS_COARSE_LOCATION);
aPermissions[4] := JStringToString(TJManifest_permission.JavaClass.CALL_PHONE);
aPermissions[5] := JStringToString(TJManifest_permission.JavaClass.WAKE_LOCK);
// aPermissions[6] := JStringToString(TJManifest_permission.JavaClass.ELEPHANT);  ???

finalization

end.

 

hug

Share this post


Link to post

Thanks for your response, emailx45!

I was trying to simplify it down to a minimalist programme to hone in on where the error may be coming from.

I do not need to send any rationale to the user. The system box requesting permission is quite, quite enough!

The RequestPermissions is sending me the correct information - ie that the programme has been granted CAMERA permission, and it works without any problems.

 

The problem is in the next bit, where I try to access the camera.

The error message comes after either the TakePhoto() or the TakePhotoFromCameraAction1.Execute

Dave Nottage suggested that I had to get camera permissions first.  I have done that successfully

(well, the RequestPermissions returned .Granted, so I assume that means all is well), but the same

error message persists, and I would love to be able to get rid of it.

 

My apologies if my pascal reads like programming by a Fortran programmer!  As I have nobody else for 1000km whom I know of to interact Delphi programming with, I am stuck with my background.

Share this post


Link to post
Guest

as I said in my sample post... ALWAYS IS NECESSARY VERIFY THE PERMISSIOBS BEFORE ANY ITERATION WITH CAM OR OTHERS.

Then, if you SDK is right with your IDE and project, it should works.... except uf exist any bug on parts (you, IDE or Android). but if works in another device, then, you can compare with Huawey P20...

Now, RAD10.4.x is bugged in many areas, mainly in another platforms.

 

My tip: try compile in RAD10.3.3 and see if same error happens. Try my sample in my post link (it was tested in Androud 7.0 Nougat and works. 

Later, try in your Huawaey P20.

 

hug

Share this post


Link to post
Guest

now about have your Android 7.0 back... no way without hack your device. Or be, you need install  the Android 7.0 image (as a ISO in MSWindows) using a tool for that. But can be a risk do it, you see?

on Internet you found many tools for that, mainly in forums about Android not official. But warning about download Android images from unknow sources.

 

Google Android Developers site:

https://developer.android.com/topic/generic-system-image

 

 

Here, a project to emulate Android system on VirtualBox or VMWare for tests using your pc.

https://www.linuxvmimages.com/images/android-x86/

 

hug

Edited by Guest

Share this post


Link to post

Thanks for your warnings, emaiilx45!  No, I am not going to take my phone back to a7 - and nor would the other users of the programme.

It is interesting that Dave Nottage, to whom I sent the latest version of the programme, had no trouble running it under 10.3.3.

I tried it with 10.3.3 on m computer and still got the same error message.

My android seems to be 25.2.5.  Could that be a problem?

 

Otherwise my option seems to be getting / writing a java wrapper for camera2 - which looks pretty daunting!

Share this post


Link to post

Hi Dave,

 

thanks for that, always one step ahead 👍

 

I just briefly looked into it, I wonder if it would be possible to intercept the texture stream, and if so where its best to do that ?

 

Beside facedetetion, I find it much more interesting to implement own filters in the image stream on the fly, and to put features and drawings on top of the preview video.

I'm not sure if any FMX control can be above the Camera preview, but shouldn't that be possible with the updated Z-order in Android ( in iOS too ) ?.

 

So far I'm not sure where the textures can be intercepted.

I find the (for Android)

    FSurfaceTexture: JSurfaceTexture;
    FSurfaceTextureListener: JTextureView_SurfaceTextureListener;


which leads to the assumption that this could be tapped somehow.

Just checked the Andoid part, not sure about iOS, but IOS was more performant anyway.

 

Would be interesting to know if you are also work on such kind of image-processing for video stream from the camera ?

 

Edited by Rollo62

Share this post


Link to post
10 hours ago, Rollo62 said:

I wonder if it would be possible to intercept the texture stream

I have been working on that. I needed to make a substantial change to using an OpenGL surface - a problem I am having is doing a transform when the device is not oriented in the "normal" position. 

10 hours ago, Rollo62 said:

I find the (for Android)

    FSurfaceTexture: JSurfaceTexture;
    FSurfaceTextureListener: JTextureView_SurfaceTextureListener;


which leads to the assumption that this could be tapped somehow.

That already is "tapped", however the SurfaceTextureListener is not the right place. As per my comment above, I've switched to using GLSurfaceView: https://developer.android.com/reference/android/opengl/GLSurfaceView

 

Which uses: https://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer

 

The GLSurfaceView calls onDrawFrame of the Renderer when a new frame is available, so the capture/filtering can be done there. This part is all done in Java, however the Delphi code could "hook" into the filtering, and can already pass a Java bitmap of the resulting frame to Delphi. Again as per above, I want to resolve the transform issue which is currently eluding me.

 

I'm willing to share the work in progress with others if they think they can help. Best to join my Slack workspace to do so: https://slack.delphiworlds.com

  • Like 1

Share this post


Link to post

All I want to do is take a bloody piccie!

 

Here is the next episode - trying to use the definitions in Androidapi.JNI.Hardware.  It crashed most effectively with non-explanatory error messages in both 10.3 and 10.4.

It needs 2 buttons (ButtonPiccie and ButtonExit) and an Image.

(Not sure if this is easier than trying to send the files, or more of a nuisance - please tell me!)

 

unit TryCamera3MainUnit;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Memo.Types, FMX.Objects, FMX.StdCtrls,
  FMX.Controls.Presentation, FMX.ScrollBox, System.Permissions, FMX.Memo,
  Androidapi.JNI.JavaTypes,  Androidapi.JNIBridge,  Androidapi.JNI.Hardware,
  Androidapi.Helpers;

type
  TForm1 = class(TForm)
    ButtonPiccie: TButton;
    Memo1: TMemo;
    ButtonExit: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure ButtonPiccieClick(Sender: TObject);

    procedure RequestPermissionsResultProc(
       const aPermissions : System.TArray<string>;
       const aGrantResults : System.TArray<tPermissionStatus>);
    procedure ButtonExitClick(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

  aPermissions : System.TArray<string>;
  aGrantResults : System.TArray<tPermissionStatus>;

implementation
{$R *.fmx}

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

procedure TForm1.FormActivate(Sender: TObject);
begin
   aPermissions := ['android.permission.CAMERA'];

   PermissionsService.RequestPermissions(
      aPermissions,
      RequestPermissionsResultProc);
end;

procedure TForm1.ButtonExitClick(Sender: TObject);
begin
   Application.Terminate;
end;

procedure tForm1.ButtonPiccieClick(Sender : tObject);
var
  Cam : JCamera;
  h, w : integer;
begin
  Cam := TJCamera.Create; //Crashes here

  Memo1.Lines.Add(JstringToString(Cam.toString));
  Application.ProcessMessages;

  Cam.startPreview; //Originally crashed here

  h := Cam.getParameters.getPictureSize.height;
  w := Cam.getParameters.getPictureSize.width;

  Memo1.Lines.Clear;
  Memo1.Lines.Add('Height: ' + inttostr(h));
  Memo1.Lines.Add('Width: ' + inttostr(w));
end;

 

procedure tForm1.RequestPermissionsResultProc(
   const aPermissions : System.TArray<string>;
   const aGrantResults : System.TArray<tPermissionStatus>);
var
   s : string;
begin
   s := 'Unknown';
   case aGrantResults[0] of
      tPermissionStatus.Granted: s := 'Granted';
      tPermissionStatus.Denied:  s := 'Denied';
      tPermissionStatus.PermanentlyDenied: s := 'Permanently Denied';
   end;

   Memo1.Lines.Add(aPermissions[0]);
   Memo1.Lines.Add(s);
end;

end.

 

Share this post


Link to post
50 minutes ago, Chester Wilson said:

Cam := TJCamera.Create; //Crashes here

You do not create an instance of JCamera using Create. As per the documentation:

 

Camera  |  Android Developers

 

To take pictures with this class, use the following steps:

  1. Obtain an instance of Camera from open(int).

Share this post


Link to post

Dear Everyone,

                              More from the struggling department!

 

Click on that Camera | Android Developers reference and you get taken to a deprecated page.

 

I have looked at the Java Camera2 page - which is fine if you want to write in Java!  Not so helpful if you can't get the Delphi basics sorted out (but yes, it would be very helpful after that.)

 

I have tried to get the files from Github.  It does not give me an option to download.  I can look at each of the files in turn, select all the text, copy then paste into notepad then save with the correct filename.  Messy - but there must be a better way (which I have not found yet).  Any ideas please?

 

In Androidapi.JNI.Hardware Delphi pseudo-interfaces are created, with what should ideally be class methods, but for syntactic reasons they are just methods.  Unfortunately when you type something to reference one of these methods it will not let you.  (If you write one yourself, does the UUID have to match something deep in the bowels of Java, or can you just generate your own UUID?)

For example, trying to get the number of cameras available to decide which to open:

i := JCameraClass.getNumberOfCameras; - can't find any getNumberOfCameras function.  In fact, typing JCameraClass. gives none of the "Class" functions which should be available.

 

What syntax should be used to get this to work please?

 

 

 

Share this post


Link to post

Found!  On the Kastri page, you have to click on "Code" before you can Download.  (Beats me, but it rhymes.) NOW I can start to get some understanding.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×