Android Question Android Rugged Phone and CameraEx class

QtechLab

Active Member
Licensed User
Longtime User
Hello guys,

Currently i'm writing an App that will gonna be used locally in a warehouse to move boxes and misc. products with QR Code.
So i bought 2 different android rugged phone.

Model1
r1.PNG


Model2
r2.PNG



The QRCode scanner put simply the data read in keyboard buffer. That's wonderful because you don't have to write anything strange in order to read data.

My question is this:
I have a view that, after scan a product, allow the device to take a photo and save to the warehouse database.
Now here's the problem.
With Rugged Model 2 i can scan, take photo, scan another time, take photo and go on.
With Rugged Model 1 i can scan, take photo and then i can't get the scan object another time (it doesn't work).

I read the unfiltered logs and i notice some big differences between the two devices.
It seems that the camera in the rugged model 1 can't be handled properly

Logs Rugged model 1
RUGGED 1:
Flushing all pending requests.
Repeating capture request cancelled.
Capture failed for request: 0
Legacy camera service transitioning to state IDLE
convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
Only received metering rectangles with weight 0.
Only received metering rectangles with weight 0.
Legacy camera service transitioning to state CAPTURING
Received jpeg.
Producing jpeg buffer...
Legacy camera service transitioning to state IDLE
Repeating capture request set.
convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
Only received metering rectangles with weight 0.
Only received metering rectangles with weight 0.
Picture taken: (Bitmap): 1080 x 1920, scale = 1,00
Skip the tag entry since tag number is not defined: 2
Stop reading file since a wrong offset may cause an infinite loop: 0
Stop reading file since a wrong offset may cause an infinite loop: 0
Stop reading file since a wrong offset may cause an infinite loop: 0
Flushing all pending requests.
Repeating capture request cancelled.
Capture failed for request: 2
Legacy camera service transitioning to state CAPTURING
Legacy camera service transitioning to state IDLE
[SurfaceTexture-1-3851-3] cancelBuffer: BufferQueue has been abandoned
uid=10102(com.mq.moli*******) Binder:3851_4 identical 1 line
[SurfaceTexture-1-3851-3] cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3851-3] connect: BufferQueue has been abandoned
[SurfaceTexture-1-3851-3] setMaxDequeuedBufferCount: BufferQueue has been abandoned
Access denied finding property "vendor.camera.aux.packagelist"
Jpeg surface is invalid, skipping...
Access denied finding property "vendor.camera.aux.packagelist"
type=1400 audit(0.0:76): avc: denied { read } for name="u:object_r:vendor_camera_prop:s0" dev="tmpfs" ino=15079 scontext=u:r:untrusted_app:s0:c102,c256,c512,c768 tcontext=u:object_r:vendor_camera_prop:s0 tclass=file permissive=0

Logs Rugged model 2
RUGGED 2:
[sendCameraState]flashlightState=0,j=0
[sendCameraState]scannerState=1,j=0
[sendCameraState]scannerState=0,j=1
sendCameraState PackageName=com.mq.moli******
connectCameraServiceLocked,com.mq.moli*******
[sendCameraState]flashlightState=0,j=0
[sendCameraState]scannerState=0,j=0
sendCameraState PackageName=com.mq.moli******
type=1400 audit(0.0:13): avc: denied { search } for name="255" dev="proc" ino=224 scontext=u:r:untrusted_app:s0 tcontext=u:r:mediaserver:s0 tclass=dir permissive=0
jpeg_decoder mode 1, colorType 4, w 1008, h 1792, sample 1, bsLength 0!!
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned
[SurfaceTexture-1-3446-1](this:0x7f84df6c00,id:2,api:4,p:255,c:-1) cancelBuffer: BufferQueue has been abandoned

I repeat: the app and the code is the same for both devices.

Does anyone had the same issue in the past?

Thanks in advance,
Marcello
 
Last edited:

QtechLab

Active Member
Licensed User
Longtime User
This is the activity code:

B4X:
Sub btNewPicture_Click
    If cam.IsInitialized = False Then
        initCamera
    End If
    OpenCamera(frontCamera)
    ImgStatic.Visible = False
    btNewPicture.Visible = False
    BtSend.Visible = False
    BtSnap.Visible = True
End Sub

Sub BtSnap_Click
    'MyCam.TakePicture
    ImgStatic.Visible = False
    TakePicture
End Sub

Sub initCamera
    VideoFileDir = rp.GetSafeDirDefaultExternal("")
    VideoFileName = "1.mp4"
    cam.Initialize(PnlCamera)
    
    Log(cam.SupportedHardwareLevel)
End Sub

Sub OpenCamera (front As Boolean)
    rp.CheckAndRequest(rp.PERMISSION_CAMERA)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result = False Then
        ToastMessageShow("Permessi camera richiesti", True)
        Return
    End If

    Wait For (cam.OpenCamera(front)) Complete (TaskIndex As Int)
    If TaskIndex > 0 Then
        MyTaskIndex = TaskIndex 'hold this index. It will be required in later calls.
        Wait For(PrepareSurface) Complete (Success As Boolean)
    End If
    Log("Start success: " & Success)

    If Success = False Then
        ToastMessageShow("Errore apertura camera", True)
    End If
End Sub

Sub PrepareSurface As ResumableSub
    'sizes can be modified here
    If VideoMode Then
        cam.PreviewSize.Initialize(640, 480)
        ResizePreviewPanelBasedPreviewSize
        'Using a temporary file to store the video.
        Wait For (cam.PrepareSurfaceForVideo(MyTaskIndex, VideoFileDir, "temp-" & VideoFileName)) Complete (Success As Boolean)
    Else
        cam.PreviewSize.Initialize(1920, 1080)
        ResizePreviewPanelBasedPreviewSize
        Wait For (cam.PrepareSurface(MyTaskIndex)) Complete (Success As Boolean)
    End If
    
    If Success Then cam.StartPreview(MyTaskIndex, VideoMode)
    Return Success
End Sub

Private Sub ResizePreviewPanelBasedPreviewSize
    Dim pw = cam.PreviewSize.Height, ph = cam.PreviewSize.Width As Int
    Dim r As Float = Max(Activity.Width / pw, Activity.Height / ph)  'FILL_NO_DISTORTIONS (change to Min for FIT)
    Dim w As Int = pw * r
    Dim h As Int = ph * r
    PnlCamera.SetLayoutAnimated(0, Round(Activity.Width / 2 - w / 2), Round(Activity.Height / 2 - h / 2), Round(w), Round(h))
End Sub

Sub HandleError (Error As Exception)
    Log("Error: " & Error)
    OpenCamera(frontCamera)
End Sub

Sub TakePicture
    Try
        Wait For(cam.FocusAndTakePicture(MyTaskIndex)) Complete (Data() As Byte)
        '
        cam.DataToFile(Data, VideoFileDir, "1.jpg")
        Dim bmp As Bitmap = cam.DataToBitmap(Data)
        Log("Picture taken: " & bmp) 'ignore
        imgTaken = RotateJpegIfNeeded(bmp, Data)

        cam.Stop
        
        'Layout settings'
        btNewPicture.Visible = True
        BtSend.Visible = True
        BtSnap.Visible = False
        PnlCamera.SetLayoutAnimated(0, sdLeft, sdTop, sdW, sdH)
        ImgStatic.Visible = True
        ImgStatic.Bitmap = imgTaken

    Catch
        HandleError(LastException)
    End Try
    
    'reset focus for QRCode scanner'
    txtScan.Text = ""
    txtScan.RequestFocus
    
End Sub


Private Sub RotateJpegIfNeeded (bmp As B4XBitmap, Data() As Byte) As B4XBitmap
    Dim p As Phone
    If p.SdkVersion >= 24 Then
        Dim ExifInterface As JavaObject
        Dim in As InputStream
        in.InitializeFromBytesArray(Data, 0, Data.Length)
        ExifInterface.InitializeNewInstance("android.media.ExifInterface", Array(in))
        Dim orientation As Int = ExifInterface.RunMethod("getAttribute", Array("Orientation"))
        Select orientation
            Case 3  '180
                bmp = bmp.Rotate(180)
            Case 6 '90
                bmp = bmp.Rotate(90)
            Case 8 '270
                bmp = bmp.Rotate(270)
        End Select
        in.Close
    End If
    Return bmp
End Sub
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
Are you using Camera2? Test it with CameraEx (1).

Update: The service that read the QRCode seems to use the camera (don't know why because it has its own module).

Then i did some test:
If i use the default device camera, the service is stopped and i can take photo; after closing the default camera the QR service restart work properly.
If i use B4X Pages Camera Intent, the QR service won't restart to work.
If i use B4A Camera intent, the QR service won't restart to work.
If i user Camera2 on B4A, the service won't restart to work.

For some Reason CameraEx class allow the service to restart work properly

Is it possible that the Camera wrappers or Camera2 don't free some objects?

https://www.b4x.com/android/forum/threads/b4x-b4xpages-intent-based-camera.120721/
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
Camera2 API is based on a newer API. Your device supports it in "legacy mode". This means that it doesn't properly support it and it is better to use the older Camera API.
Thank you. I may ask to the device manufacturer. They may have some usefull information.
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hello @MarcelloCSI
I've developed a few bespoke warehouse solutions using Android powered 1D/2D laser barcode scanners pictured below, using lasers make for an excellent solution.

I had the exact same problem as you, but the issue was fixed with a library wrap
I personally use the BroadCastReceiver to capture the Intent scanned barcodes (yes the scanned code can also be captured in the keyboard buffer, but I didn't find that an efficient way to code), but to help matter I personally use a wrapped library to initialise the device and the enable/disable the scanner.

If I remember correctly, the laser in these devices are also classed as a camera, so when any of my clients wants to take a photo of items/boxes (before of after scanning barcodes) in their warehouses, I use the library to call a method called StopScan, this disabled the laser and the cameras are then guaranteed to work for me 100% of the time. The wrapped library that I have has a few methods, but I only use three of them if my memory serves correctly, Initialize, StartScan and StopScan. I personally found that using StopScan in the library to disable the laser scanner fixed all my camera issues, after taking the photo with the device, I use the StartScan method to enable the laser scanner again.

I hope that help you out a bit. As I said, I had the exact same issue, by using StopScan and StartScan in the wrapped library before an and after taking photos, that fixed my issue and all my clients are happy.

ABS.jpg

Enjoy...
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
Hello @MarcelloCSI
I've developed a few bespoke warehouse solutions using Android powered 1D/2D laser barcode scanners pictured below, using lasers make for an excellent solution.

I had the exact same problem as you, but the issue was fixed with a library wrap
I personally use the BroadCastReceiver to capture the Intent scanned barcodes (yes the scanned code can also be captured in the keyboard buffer, but I didn't find that an efficient way to code), but to help matter I personally use a wrapped library to initialise the device and the enable/disable the scanner.

Hello Peter,

Thans for your reply. You just gave me the hope to continue using those terminals. :)
The issue happens only with the "model 1" that i posted. I don't know why but the "model 2" recongize the camera open and stop and restart the lasers properly.
The nice thing of avoiding the wrapper is that ideally the app could run on every device.
So, i'm gonna ask the manufacturer for SDK. They just gave me the service apps.

Best regards,
Marcello
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hello Peter,

Thans for your reply. You just gave me the hope to continue using those terminals. :)
The issue happens only with the "model 1" that i posted. I don't know why but the "model 2" recongize the camera open and stop and restart the lasers properly.
The nice thing of avoiding the wrapper is that ideally the app could run on every device.
So, i'm gonna ask the manufacturer for SDK. They just gave me the service apps.

Best regards,
Marcello

Are you sure that you have the cameras the correct way around in your code for each device. You should change the camera code to try to see if the laser is camera 0 on one device but camera 1 on the other device.
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
The camera code is correct.
Are you sure that you have the cameras the correct way around in your code for each device. You should change the camera code to try to see if the laser is camera 0 on one device but camera 1 on the other device.

The camera code is correct.
Manufacturer development team tell me that i have to kill completely the camera service in order to let the qrcode laser restart properly. Is there a javaObject Call that i can use to kill the camera for real?
 
Upvote 0

MikeSW17

Active Member
Licensed User
Longtime User
Manufacturer development team tell me that i have to kill completely the camera service in order to let the qrcode laser restart properly. Is there a javaObject Call that i can use to kill the camera for real?

Surely, if the Manufacturer says you must kill the camera service, they can tell you how they do it?
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Surely, if the Manufacturer says you must kill the camera service, they can tell you how they do it?

Mike the procedure is supposed to be as follows, but as @MarcelloCSI has not interest in what I say I gave up. Before starting CameraEx or Camera2 you are supposed to do the following
  1. Stop the laser (via library or inline java)
  2. Close the laser (via library or inline java)
  3. Now you can work with CameraEx or Camera2
  4. Once you have finished using CameraEx or Camera2, open the laser again (via library or inline java) (open not initialize)
I've had multiple Android powered 1D/2D laser barcode scanners, they basically all work the exact same way, you do not need to stop the camera service at all. The laser is classed as a camera, by closing off the laser you can then utilise the device camera (safely) to your hearts content until you open the laser again via code. Wrapping the library would help him out a treat. Using inline java also worked for me when I was testing lots of manufacturers devices, but doing it that was was a complete pain and for each device it took me ages. Once I found a device that I liked I just got the library wrapped and I stuck to that device.

But all the devices that I've got used the same 1 - 4 order process above to allow the developer to use the device cameras and the laser scanner without any conflict.
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
Mike the procedure is supposed to be as follows, but as @MarcelloCSI has not interest in what I say I gave up. Before starting CameraEx or Camera2 you are supposed to do the following
  1. Stop the laser (via library or inline java)
  2. Close the laser (via library or inline java)
  3. Now you can work with CameraEx or Camera2
  4. Once you have finished using CameraEx or Camera2, open the laser again (via library or inline java) (open not initialize)
Goodmorning Peter, Mike

I asked for an SDK to Wrap. That maybe take some time but seems to be the only way to do an App that work always.
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
@Peter Simpson, to ask the obvious: is the library wrapper available to upload for @MarcelloCSI ? Or is it confidential/licensed?
Hello Mike,

I'm waiting a response from the producer. Is there is one, they'll give me the java library to handle the scanner (i hope).
For now i haven't signed any NDA contract. I'll update the post soon.

Thanks for interest and sharing your ideas. :)

Ciao
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
@Peter Simpson , @MikeSW17
-
Here's an Update:
I got a java library with some intents and actions declared inside.

Java:
public static final String BARCODEPORT_RECEIVEDDATA_ACTION = "com.android.serial.BARCODEPORT_RECEIVEDDATA_ACTION";
public static final String BARCODEPORT_RECEIVEDDATA_EXTRA_DATA = "DATA";

// Simulate scanning keys
static public final String ACTION_KEYEVENT_KEYCODE_SCAN_L_DOWN = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_L_DOWN";
static public final String ACTION_KEYEVENT_KEYCODE_SCAN_L_UP = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_L_UP";
static public final String ACTION_KEYEVENT_KEYCODE_SCAN_R_DOWN = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_R_DOWN";
static public final String ACTION_KEYEVENT_KEYCODE_SCAN_R_UP = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_R_UP";
static public final String ACTION_KEYEVENT_SCAN_F_UP = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_F_UP";
static public final String ACTION_KEYEVENT_SCAN_F_DOWN = "com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_F_DOWN";

// service for 4710
static final String PACKAGE_NAME = "com.zebra.scanner";
static final String SERVICE_NAME = "com.zebra.scanner.ScannerJsbService";

// switch scanner enable state
static final String ACTION_CHANGE_STATE_ENABLE = "com.zebra.action.CHANGE_STATE_ENABLE";
static final String ACTION_CHANGE_STATE_DISABLE = "com.zebra.action.CHANGE_STATE_DISABLE";

Now i have successfully received data with BroadCastReceiver b4a library (awesome).

B4X:
Dim ScannerAction As String = "com.android.serial.BARCODEPORT_RECEIVEDDATA_ACTION"
Dim ScannerData As String = "DATA"

public Sub RegisterScannerReceiver()
    BroadCast.addAction(ScannerAction)
    BroadCast.SetPriority(999)
    BroadCast.registerReceiver("")
End Sub

Sub BroadcastReceiver_OnReceive (Action As String, i As Object)
    Dim i2 As Intent = i
    If Action = ScannerAction Then
        If i2.HasExtra(ScannerData) Then
            Log(i2.GetExtra(ScannerData))
        End If
    End If
End Sub

How do you suggest to call the ENABLE and DISABLE actions?
What can i do for call the Scanner service?

Thank you vey much for the support.
 
Upvote 0

QtechLab

Active Member
Licensed User
Longtime User
Hello @Peter Simpson , @MikeSW17

Got code working by using B4X Class only.
(Example)
B4X:
intent.Initialize(laserService, "")
intent.SetPackage(laserPackage)
StartService(i)

broadcast.sendBroadcast(broadcastScannerOn)
Using Intents i got the laser scanner service and Started/Stopped with Broadcast Receiver.
Broadcast receiver also working for parse read data, so i'll remove the keyboard buffer function from my app (that needed a textfield in the UI).

Thanks a lot for your support :)

Have a nice day.
Marcello
 
Upvote 0
Top