Android Question Bluetooth Reconnection while in Activity

Michael Mc

Member
Licensed User
Longtime User
Hello,

I needs some help from the Android Wizards.

I'm using a Bluetooth barcode scanner in SPP Mode. If the scanner is ready and I start the Activity everything works fine. But when the scanner timeouts (because of battery saving), I cannot get it to reconnect. I have tried so many different methods to get this to work but still no go.

I thought I would post my last version of code here and hope that someone can give my their experience to resolve this issue.

Also, maybe I just missing something here but how do you destroy objects? Example the serial object. I think if you could do this and start over all would be fine.

Right now where it stands is, if the barcode scanner disconnects, it will try to reconnect and will hit the
Sub ScanDevice_Connected (Success As Boolean)
but Success is always False.

Anyway here is the code. Thank you for your help!

PS Some old variables may exist in this code that is not used. Please just focus on the primary objects and methods.


B4X:
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

    Dim ScanDevice As Serial
    Dim Timer1 As Timer

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Private CloseAppTimer As Int
    Private Connected As Boolean
    Private WaitingToConnect As Boolean
    Private BTNScanQuery As Button
    Private ScanIDQuery As EditText
    Private WebViewQuery As WebView
    Private MyScan As ABZxing
    Private StatusPanel As Panel
    Private ItemHTMLString As String
    Dim ast As AsyncStreamsText
    Private WaitingConnectCounter As Int
    Dim Toggla As Toggle
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    Log("Activity_Create")
    If FirstTime Then
        ScanDevice.Initialize("ScanDevice")
        Timer1.Initialize("Timer1", 1000)
    End If
    WaitingToConnect=False

Activity.LoadLayout("queryscreen")
StartScanner(Main.connectedDevice.Name,Main.connectedDevice.mac)  


WebViewQuery.Color = Colors.Transparent

If Main.AlphaSKUKeyboard Then
ScanIDQuery.InputType = ScanIDQuery.INPUT_TYPE_TEXT
Else
ScanIDQuery.InputType = ScanIDQuery.INPUT_TYPE_NUMBERS
End If
Activity.AddMenuItem("Connect Scanner", "mnuConnect")
Activity.AddMenuItem("Disconnect Scanner", "mnuDisconnect")  
ScanIDQuery.RequestFocus

  
  
End Sub

Sub Activity_Resume

    Log("Activity_Resume")

     If ScanDevice.IsEnabled = False Then
        Msgbox("Please enable Bluetooth.", "")
        Else
        If ScanDevice.IsInitialized Then
        ScanDevice.Listen
        End If
      
       End If
  

End Sub

Sub Activity_Pause (UserClosed As Boolean)
    Log("Activity_Pause")
    End Sub

Sub StartScanner(Name As String,Mac As String)
Log("StartScanner " & Name & "  " & Mac)
    If Name<>"" Then

    ScanDevice.Connect(Mac)
    ScanDevice.Listen
    End If
End Sub



Sub ScanDevice_Connected (Success As Boolean)
Log("ScanDevice_Connected" )
    If Success Then
        ProgressDialogHide
        ToastMessageShow("Scanner Connected successfully", False)
        ast.Initialize(Me,"ast",  ScanDevice.InputStream, ScanDevice.OutputStream) 'initialize AsyncStreamsText with the socket streams.
        Connected=True
        Else
        Connected=False
    End If
    If Timer1.Enabled = False Then     Timer1.Enabled=True  
  
End Sub
Sub Timer1_Tick

    If Main.BatterySaver =True Then
        CloseAppTimer = CloseAppTimer+1
        If CloseAppTimer> 600 Then
        ' Will enable once everything works.
        '    Activity.Finish
        End If
    End If

If Connected=False  Then
    StartScanner(Main.connectedDevice.Name,Main.connectedDevice.Mac)
End If

End Sub


Sub ast_NewText(Text As String)
  ScanIDQuery.Text =  Text
    ProcessScan
End Sub


Sub ast_Terminated
ScanDevice.Disconnect
  ToastMessageShow("Scanner Timeout/Disconnected.",True)
  Connected=False
End Sub
  
Sub ast_Error
    ToastMessageShow(LastException.Message, True)
End Sub
 
Last edited:

Michael Mc

Member
Licensed User
Longtime User
Hello @Michael Mc,
Please let me know if my app works correctly for you, If it does I'll check my code and explain what I did.

Link to app :https://www.dropbox.com/s/sgaabx6qhlbh9bm/BarcodeScanner.apk?dl=0

Thanks, but that does not reconnect.

If you start your program it comes up with a blank white screen. Then has connect message try 1 of 5, 2 of 5 and then it connects and I can scans codes.

But if you turn off the scanner or the scanner timeouts then you turn it back on, it does not attempt to reconnect. The scanner is ready and waiting for a connect from your program.

I'm not sure if you have any type of disconnect message, I never see anything. If you have programmed any reconnect code it would be great to see what you may have done. Between what you know and I know maybe there is a way to figure this all out. You would think this is a simple issue, because we know when the scanner gets disconnected. Somehow the Serial Object is not happy reconnecting and I have not figured out how to destroy it and create a new one.

Thanks!!!
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hmm, what you explained appears to me to be impossible as you must at least tap your screen for the message try 1 of 5, 2 of 5 would even start, it can't start by itself.

Anyway my app reads from your android device any previously connected Bluetooth devices then shows them to you, you then select your barcode scanner and it should connect. I've just re-uploaded the app just in case it was a previous version, so please try it again.

Anyway to fix your issue @Michael Mc you should have ScanDevice.Disconnect in Activity_Pause, and ScanDevice.Connect in both Activity_Resume and
ScanDevice_Connected. The very first time that you connect to the scanner in your app (verify in ScanDevice_Connected), make sure that you store the scanners MAC address in a variable(string) stored in Global, that way when you reconnect in Activity_Resume, you already have the MAC address to hand.

BTW what barcode scanner are you using?

That's it...
 
Upvote 0

Michael Mc

Member
Licensed User
Longtime User
Hmm, what you explained appears to me to be impossible as you must at least tap your screen for the message try 1 of 5, 2 of 5 would even start, it can't start by itself.

Anyway my app reads from your android device any previously connected Bluetooth devices then shows them to you, you then select your barcode scanner and it should connect. I've just re-uploaded the app just in case it was a previous version, so please try it again.

Anyway to fix your issue @Michael Mc you should have ScanDevice.Disconnect in Activity_Pause, and ScanDevice.Connect in both Activity_Resume and
ScanDevice_Connected. The very first time that you connect to the scanner in your app (verify in ScanDevice_Connected), make sure that you store the scanners MAC address in a variable(string) stored in Global, that way when you reconnect in Activity_Resume, you already have the MAC address to hand.

BTW what barcode scanner are you using?

That's it...


Thanks again but no go.

I do have the MAC address stored in a Global Variable, its Main.connectedDevice.mac.

I believe the problem is with timing. If I slow my timer down say 1000 instead of 200 I think it is not overloading the message queue and giving the adapter sometime to react. I'm getting better results now, able to connect even from a scanner power off state. I really would want this bullet proof so I guess I'll keep plugging away and see if others have ran into this issue and found a complete solution. I don't want the users to wait to long for the scanner to reconnect.

Really wish to could just Destroy these objects like other languages and start fresh with new ones when needed.

I appreciate your help, if you have any discoveries with your project it would be great to share your knowledge to others, including myself :)


As for the Scanners, I'm testing 2 different ones. Symbol CS3070 and Inateck BCST-10. They both work well but the Symbol is a great pocket size, the Inateck has some nice configuration features.

Thanks
 
Last edited:
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Okay @Michael Mc first off all you do not need a timer, just testing Success in Sub Scanner_Connected(Success As Boolean) is enough for you to retry connecting if the scanner does not connect first time out. I've noticed that in your code that you are testing if the connection is True, but you are doing nothing when the connection is False.

Please post a quick example of your project, thank you.

I take it that you've been to this post https://www.b4x.com/android/forum/threads/barcode-scanning-and-keyboard-input.42000/
 
Upvote 0

Michael Mc

Member
Licensed User
Longtime User
Okay @Michael Mc first off all you do not need a timer, just testing Success in Sub Scanner_Connected(Success As Boolean) is enough for you to retry connecting if the scanner does not connect first time out. I've noticed that in your code that you are testing if the connection is True, but you are doing nothing when the connection is False.

Please post a quick example of your project, thank you.

I take it that you've been to this post https://www.b4x.com/android/forum/threads/barcode-scanning-and-keyboard-input.42000/


Yes some of those Variables where used when I was playing around, so they are just left over or not really used.

I need to have the timer event because to auto reconnect there needs to be way to check for a disconnected device and reconnect it when it is back online. I'm not selecting the scanner within the activity, it is established within a different configuration activity.

Yes I did look at that post, it prompts for you to select a scanner if disconnected. I just need to reconnect the assigned scanner when it becomes online again, don't want to prompt the user because the device may not be within hands reach.

Thanks again!
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
But that's my whole point, you do not need a timer to auto reconnect. All my barcode scanners and my clients barcode scanners reconnect automatically without a timers. Using Activity_Pause and Activity_Resume is enough for the scanner to disconnect and reconnect to the app automatically once you have stored the barcode scanners MAC address on the original connection, even if the phone/tablet is then used for something else, once the user goes back to the app it WILL auto reconnect. You can even scan 100+ barcodes and then go back to the your app afterwards, once auto reconnected the 100+ barcodes will then automatically transfer over one at a time to your app as if you were doing manual scans.

You do not need a timer, just by adding a
ScanDevice_Connected into Activity_Resume is enough to reconnect automatically once you have the original MAC address. The prompt is just because there might be more than one scanner used on the device, so prompting is used to interact with the user. Adding the device name programmatically will connect automatically without a prompt.

Anyway, as I stated in my second post on here to you, you should use Activity_Resume to auto reconnect (check global variable for MAC address) and you should also be using Scanner_Connected(Success As Boolean) and doing something if the scanner is not connected, that's where I put my retry 5 time code. If the scanner turns itself off, then the app will keep trying every few seconds to connect until the scanner is turned back on again. Once again no timer is needed for this to happen if Success = False.

As I asked previously, please create and post a simple project with your code, just the barcode section and we can then look closer at your issue, but you do not need a timer.
 
Last edited:
Upvote 0

Michael Mc

Member
Licensed User
Longtime User
Yes I tried what you suggested but it does not reconnect. There is no event being created to have it check to see if the device is online again. So I need something to check it every 10 secs or so. I can Serial.Listen for weeks and nothing gets fired.

After some trial and error I have my scanners working the way I need them to.

I think each barcode reader has it's own personality. My Symbol device connects fast the Inateck takes 20 secs or so.


I do get an error once in awhile after connection has been successful on the ast.Initialize(... line but I think it is timing issue. The ScanDevice (serial stream) must not be completely established prior to assigning the InputStream to the AsyncStreamsText. I'm testing it on a Note 4

B4X:
Sub ScanDevice_Connected (Success As Boolean)
    If Success Then
        ProgressDialogHide
        ToastMessageShow("Scanner Connected successfully", False)
        Try
        ast.Initialize(Me,"ast",  ScanDevice.InputStream, ScanDevice.OutputStream)
        Catch
          End Try
        Connected=True
        Else
        ScanDevice.Listen
        Connected=False
    End If
  
End Sub

It cannot be a Null Object Reference if it just connected.


---------- ERROR -----------------------
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.InputStream android.bluetooth.BluetoothSocket.getInputStream()' on a null object reference
at anywheresoftware.b4a.objects.Serial.getInputStream(Serial.java:254)
at com.dscorp.InScan50Standard.queryscreen._scandevice_connected(queryscreen.java:813)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at anywheresoftware.b4a.BA$3.run(BA.java:332)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5972)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
Hmm interesting, I've not come across the same issues as you, All the Barcode scanners I've connected to (bar one) have worked.
You should not leave Catch empty, You should use LastException.Message as follows. I use RandomAccessFile for BarcodeData_NewData(Buffer() As Byte) where you're using AsyncStreamText for BarcodeData_NewText(Buffer As String), which really does not matter at all. I've been thinking about your issue but I just cant think of any reason why you would be having issues. Let me drink on it and I'll have a think about your issues @Michael Mc.

B4X:
Try
     ast.Initialize(Me,"ast", ScanDevice.InputStream, ScanDevice.OutputStream)
Catch
     Log(LastException.Message)
End Try

I've just changed my code again in my app, it still works for me, if you want to try it out the link is the one in previous posts.
 
Upvote 0
Top