Blepdroid Bluetooth BLE and FragmentManager Issue

This question is regarding a fatal exception error message that occurs when using Blepdroid (a Bluetooth low energy library) with later versions of Processing 3. My tests suggest their may be a bug or unlisted change in Processing. I would value an opinion on the source of the problem before submitting it as a bug to the Processing developers. The error message is listed below.

FATAL EXCEPTION: Animation Thread
Process: processing.test.test2, PID: 17735
java.lang.NoSuchMethodError: No virtual method getFragmentManager()Landroid/app/FragmentManager; in class Lprocessing/core/PApplet; or its super classes (declaration of ā€˜processing.core.PAppletā€™ appears in /data/app/processing.test.test2-1/base.apk)
at blepdroid.Blepdroid.<init>(Blepdroid.java:293)
at processing.test.test2.Test2.setup(Test2.java:88)
at processing.core.PApplet.handleDraw(PApplet.java:1801)
at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:471)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:503)

Iā€™ve written many programs using Blepdroid and Processing version 3.2.3. These have worked perfectly for the last 18 months, successfully accessing Blepdroid and presumably the fragment manager method that Blepdroid calls. With Processing versions 3.3.7 and 3.4 my same programs plus Blepdroid still build successfully but when run they give the fatal exception error message shown above:

My programs also continue to run properly with newly installed versions of the SDK for 3.2.3 provided I include my old Processing folder with its SDK folder. If I donā€™t include the folder I get a message saying that Android no longer supports this version of Processing.

Blepdroid hasnā€™t changed in the last year and I have been using the same copy of Bepdroid throughout that time. If Blepdroid has successfully called for FragmentManager in earlier versions then it must have been available in those earlier versions. However, I couldnā€™t find anything in the changes notes for Processing 3 that says access to the FragmentManager method has been changed?

Below is a simplified example of code that uses Blepdroid and works without error on Processing version 3.2.3 but fails with the error message above on Processing versions 3.3.7 and 3.4.

import blepdroid.*;
import blepdroid.BlepdroidDevice;
import android.os.Bundle;
import android.content.Context;
import android.app.Activity;
import java.util.UUID;

Blepdroid blepdroid;
Activity activity;
Context context;

void setup(){
  blepdroid = new Blepdroid(this);
  size(480, 890);
}

void draw(){
  background(255,0,0);
  fill(0);
}

Manifest for Processing 3.2.3

<?xml version="1.0" encoding="UTF-8"?>
-<manifest package="" android:versionName="1.0" android:versionCode="1" 
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:targetSdkVersion="26" android:minSdkVersion="15"/>
-<application android:label="" android:icon="@drawable/icon">
<service android:name="blepdroid.BluetoothLeService"/>
-<activity android:name=".MainActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
-<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

References

Blepdroid source code, downloadable code and a statement of the issue https://github.com/joshuajnoble/blepdroid

Another discussions of this issue

Thanks for any advice, Peter

I donā€™t have Android Mode installed and never did. :robot:
Nonetheless, Iā€™ve decided to do some ā€œinvestigationsā€ on this ā€œmysteryā€. :male_detective:

According to your posted error logs: :warning:

That fatal exception occurs within setup() when you try to instantiate class Blepdroid: :sweat:

Inside Blepdroidā€™s constructor, weā€™ve got this suspicious statement which attempts to invoke method getFragmentManager() over a passed PApplet object: :thinking:
parent.getFragmentManager().beginTransaction().add(android.R.id.content, this).commit();

However, thereā€™s no method getFragmentManager() to be found within class PApplet.
The PApplet there merely implements ActivityAPI: :roll_eyes:
public class PApplet extends Object implements ActivityAPI, PConstants {

And consequently, thatā€™s what actually throws the ā€œFATAL EXCEPTIONā€: :dizzy_face:

In some old Android Mode builds, its PApplet class used to extends Androidā€™s Fragment class: :older_man:
public class PApplet extends Fragment implements PConstants, Runnable {

Which most likely is where PApplet would inherit that method getFragmentManager(); which in turn class Blepdroid would expect to find there. :crazy_face:

Thank you very much for your investigation and that clear explanation.

In trying to resolve the issue would it be reasonable to ask Processing if they would be prepared to continue to set up its PApplet class to extend Androidā€™s Fragment class:or include it in some other way? Or is it better to ask Joshua who wrote Blepdroid if he can use another approach to access this class?

Iā€™m not a Java programmer and am keenly aware that all this work by the Processing team and by Joshua (Blepdroid) is voluntary but not clear which approach would require more work?

It does nothing to do with the Processing version but with the Android mode version. Right now the AM version is 4.x.x. When AM swapped to 4, PApple tstop extending from Activity and instead, it contains an instance of PSurface and it s nature depends on the technology you are targeting. See this.

You should reach Joshua as it is very unlikely Processing will take a lad to fix this.

Kf

1 Like

Thank you, Iā€™ll try to get in touch with Joshua and see if he is able to fix this - are you able to say if its likely to be a major task? Also do you know if the Android mode was devleoped by a subgroup of Processing.org or by Android (Google)?

If Joshua is unavailable to fix this problem I will try to develop a BLE library myself but Iā€™m a complete novice with Java and Android and suspect it will take several months of part time stiudy to learn and to write a library. On looking at the link kfraje provided I could see no reference to Bluetooth - the references are understandably all graphics related - does this mean that its no longer possible/practical/appropriate to develop applications for Processing that use Bluetooth low energy?

Hi
The Android Mode is supported by the Foundation. It is the work done by the lead @Andres and his team. Check this here.

Blepdroid is a library provided by a community member and I do not know if he is related to the Foundation. I do know he is a nice guy.

Is it a major change? I donā€™t think so. I was able to run your sketch after I did some research and some changes (Trivial changes but some deep changes in Androidā€¦ took some time). Anyways, the solution I have is partial and I will message Andres to see if I can generate a final fix.

This is what I am going to do and I would need your help as I am not setup to test the functionality of the library. I have made three changes. I have built a new jar and I was able to run it without having any errors in the console. However, I would like to know if the BLE actually works. It would be a great help if you do this:

  • Use one of your projects and check that the BLE works
  • Please use the latest version of Processing and the latest Android mode. You dont have to use the latest if you think any other configurations of yours will work. Anyhow, tell us what versions did you use (It will help the community)
  • If you use the latest Processing and AM, donā€™t forget to use a brand new manifest. To do so, rename the current manifest in your project folder (add .backup for instance) and then attempt to run the code. This will generate a brand new manifest. THEN, you need to modify the manifest to include the service definition as well as permissions as described here by Jooshua
  • Then run the code again and see if it works for you.

Can you PM you email address so I can send you the jar file? I do not want to make this jar public unless I know the changes were effective. Are you familiar with the Library concept in Processing, related to the library file layout? If you are not, let me know and I can provide instructions. when you get the jar file, just replace the jar file inside blepdroid/library/ folder. Make sure you are not running the PDE when you do this, or just restart it.

By the way, I would like to mention there is another library that offers B2 bot sure if it covers BLE (Not enough experience neither in the field nor with the library) but it could potentially work for your project as wellā€¦ or at least, it could be use as a base. However, letā€™s see if we can make this one work.

Kf

What a fast response many thanks for all of that work! My email address is peter@energysustained.com and I should have no trouble with any of the actions you suggest. Does your Jar file replace Joshuaā€™s Blepdroid Jar or is it additional?

This new jar will be replace the old one. You can always get a copy of this old one from the original github repo. I will send you the file soon.

kf

The file came through fine and should have it set up and tested by tomorrow. Slow internet here, takes a couple of hours to download the new Processing version and SDK

Thanks po

Hello kfrajer

I carried out the test on several of my programs with partial success. The system no longer fails immediately on start up and the Blepdroid scan and device discovered functions are working. The connect function may also work but as soon as a Bluetooth characteristic is changed to indicate new data from a device there is a failure and the data signal is not received. So no error if there is no signal from a Bluetooth device but when the device starts transmitting data the error occurs and the data is not received.

The error seems similar to the first one stating: ā€œCaused by: java.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classesā€

Does this mean I should be importing additional Java utilities?

Iā€™ve copied the error file below with a few of the normal code running messages before and after the error. Also a skeleton version of my code that includes all the Blepdroid functionality Iā€™m using and generates the error signal when run with a Bluetooth device providiing a signal.

I had comms issues downloading the latest SDK files but its all set now so I should be able to respond much faster.

ERROR NOTIFICATION
scanDevices
check functionality
scanLeDevice
running scan
calling startLeScan
device discovered
connectDevice
connectDevice::connected device
BluetoothLEService connectDevice
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at blepdroid.Blepdroid.addDevice(Blepdroid.java:621)
at blepdroid.BlepdroidAdapter$2.onScanResult(BlepdroidAdapter.java:97)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:393)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5912)
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:1405)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)
Caused by: java.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classes (declaration of ā€˜java.util.concurrent.ConcurrentHashMapā€™ appears in /system/framework/core-libart.jar)
at blepdroid.BluetoothLeService.connect(BluetoothLeService.java:150)
at blepdroid.Blepdroid.connectDevice(Blepdroid.java:346)
at processing.test.newjartest1.NewJarTest1.onDeviceDiscovered(NewJarTest1.java:96)
ā€¦ 13 more
device discovered
connectDevice
connectDevice::connected device
BluetoothLEService connectDevice

Skeleton Code including all the Blepdroid functions used

import blepdroid.*;
import blepdroid.BlepdroidDevice;
import android.os.Bundle;
import android.content.Context;
import android.app.Activity;
import java.util.UUID;

// IMU UUIDs      
public static UUID ASTRO_UUID = UUID.fromString("702f0b50-ec84-11e7-8c3f-9a214cf093ae");

Blepdroid blepdroid;
Activity activity;
Context context;

// Display variables
PFont f1, f2;

// Program control variables
boolean allSetUp = false;
int poll = 1;                       // Precaution to avoid Bluetooth data stream conflict, may be superfluous
int stop1 = 0;     

void setup(){
  
  // Set up Bluetooth control
  blepdroid = new Blepdroid(this);
  Activity activity = this.getActivity();
  Context context = activity.getApplicationContext();
  
  // Set up display
  size(480, 890);
  smooth();
  f1 = createFont("Consolas-Bold-35.vlw",35,true);
  f2 = createFont("Consolas-25.vlw",25,true);
  ellipseMode(RADIUS);
}

void draw(){
  background(255,0,0);
  textFont(f1,40); 
  fill(0);
  text("Start",45,475);
  text("Quit",45,775);
  fill(130);
  ellipse(80, 700, 30, 30);  // Start
  ellipse(80, 400, 30, 30);  // Quit
  if(stop1 == 1){
    System.exit(0);
    // exit(); // alternative recommended by Processing.org 
               // but may no longer be available        
  }
}

void mousePressed(){ 
  // Start button
  if ((mouseY < 440) && (mouseY > 380) && (mouseX < 100) && (mouseX > 60)){
    blepdroid.scanDevices();
  }

  // Quit button
  else if ((mouseY < 740) && (mouseY > 680) && (mouseX < 100) && (mouseX > 60)){
    stop1 = 1;
  } 
}

void onDeviceDiscovered(BlepdroidDevice device){
  if (device.name != null && device.name.equals("IMUA")){
    blepdroid.connectDevice(device);
  }
  if (device.name != null && device.name.equals("IMUB")){
    blepdroid.connectDevice(device);
  }
}

void onBluetoothConnection( BlepdroidDevice device, int state){
  blepdroid.discoverServices(device);
}

void onServicesDiscovered(BlepdroidDevice device, int status){
  //  Set for whatever device was just connected
  blepdroid.setCharacteristicToListen(device, ASTRO_UUID);
}

void onCharacteristicChanged(BlepdroidDevice device, String characteristic, byte[] data){
  String dataString = new String(data);
  if(device.name.equals("IMUA") && poll == 1){
    downloadIMUA(dataString);
  }else if(device.name.equals("IMUB") && poll == -1){
    downloadIMUB(dataString);
  }
  poll = -poll;
}

void downloadIMUA(String dataString){
  String[] xyz = split(dataString, ' ');
}

void downloadIMUB(String dataString){
  String[] xyz = split(dataString, ' ');
}

Thxs for checking this. Yes, that was my concern about fixing only certain lines of codeā€¦ to fix this, it could take a greater effort as it will require to:

  1. become familiar with the code
  2. Become familiar with the BLE api
  3. Setup a test environment

I might be wrong, maybe the fixing requires adjusting just a few lines of code. I believe you already issue a ticket in the blepdroid repo. Not sure if he is maintaining this code base. I cannot commit to fixing this bc of time constraints.

I notice this library is taking to a rfduino. I am assuming this is not needed by the blepdroid but it is used to support/test the library or blepdroid was design to interact with that type of electronics in the first place. Could you comment on your setup? Simple hello-world kind of setupā€¦ nothing fancy.

Also, did you check the ketai library? That is another option. I used their B2 a while ago. Ketai was revamped to work with the new AM but I have not used it myself.

Kf

Yes Blepdroid was designed for use with arduino devices. My set up is for remote monitoring of astro telescopes .It uses two arduino 101 clones with BLE incorporated in each. For reasons of power usage Iā€™m constrained to using BLE.

Also thanks for helping me understand this all a bit better, much appreciated and also appreciate your time constraints

Letā€™s decipher what that java.lang.NoSuchMethodError error log means: :male_detective:

Thxs @GoToLoop I can try adding this fix to the library.

@PeterO I will send you another jar when i get the fix done.

For the arduino, what BLE shield are you using in your project?

Kf

Thanks KF for the additional library,and GoToLoop for the analysis

Re Arduino 101 - the BLE is called Curie BLE and is embedded in the Arduino 101 board - see https://www.arduino.cc/en/Reference/CurieBLE

1 Like

Hello kfrajer,

Joshua Noble got in touch and will be looking at the problem. If you do add the fix to the library Iā€™d be keen to try it out but I know you are constrained on time and wanted to let you know.

Thanks po

So the problem is deeper and it is not at the blepdroid level but at the Android API level based on this post in SO. I will let Joshua address the issue. Updating the library require knowledge of the architecture. I could try to solve this issue but a more holistic approach is needed to make this library functional again.

You could always setup your system to run on an older version: Run java 7, Processing 3.4 and Android Mode 3.0.2. To do this way, you will need to change the PATH variable (Windows ?) to point to your java7 JRE. For Processing, you need to define your worksketch directory. Not sure if you can change the preference file location. However, thinking about it, your preference file could be use for different processing versions as usually is not affected by change of versions.

Kf

Many thanks for that link and all the research - it does looks very complex.

Iā€™ll wait and see how Joshua fares and read as much as I can about BLE

Hi everyone,

Seem you are in the process of getting a solution directly from Joshua. With regards to the first error mentioned in this thread (the method getFragmentManager no longer available in PApplet) the reason is that, in order to support different ā€œkindsā€ of apps (live wallpapers, VR, etc) PApplet is no longer a descendant of Androidā€™s Fragment. You can still get a reference to the activity that contains the Processing sketch by calling getActivity(), so one way to solve the initial issue could be to replace the getFragmentManager() call by getActivity().getFragmentManager().

Since this change in PAppletā€™s hierarchy broke other libraries that relied on Fragmentā€™s API, I created an interface where one can add some commonly used methods from Fragment, so they are available again under PApplet, and old libs could function w/out having to rebuild them. So, I could add getFragmentManager() to that interface, however, from reading the latest posts, it sounds like there are other issues with Blepdroid that may require Joshua to update/rebuilt it anyways.

Andres

1 Like

Hi @kfrajer and @Andres,

Iā€™m still trying to get Blepdroid up and running and I have two questions:

  1. Thanks for the advice kfrajer and Iā€™ve tried changing to Android mode 3.0.3 in the android mode folder, but I get a message ā€œThe package Android does not exist. You might be missing a libraryā€. The version Iā€™m using is also called Android Mode 253 and Iā€™m replacing the latest ā€œAndroidā€ folder in the \Processing\modes folder with the older versionā€¦ Is that the right procedure? I havenā€™t yet changed the Java Path back to 7.

  2. Thanks for the update Andres as you suggest the problem was deeper and Iā€™ve copied below a simplest Blepdroid test and the response in case its any use.

TEST AND RESPONSE COPIED BELOW

import blepdroid.*;
import blepdroid.BlepdroidDevice;
import android.os.Bundle;
import android.content.Context;
import java.util.UUID;

// IMU UUIDs      
public static UUID ASTROCAL_UUID = UUID.fromString("702f0a24-ec84-11e7-8c3f-9a214cf093ae");

Blepdroid blepdroid;
BlepdroidDevice IMUB;

boolean allSetUp = false;


void setup()
{
  size(480, 890);
  blepdroid = new Blepdroid(this);

}

void Main()
  {
    println(" scan !");
    blepdroid.scanDevices();
  }


void onDeviceDiscovered(BlepdroidDevice device)
{
  if (device.name != null && device.name.equals("IMUB"))
  {
    println("device address = ", device.address);
  } else {
    println("no device");
  }
}

RESPONSE

Build folder: C:\Users\PeterO\AppData\Local\Temp\android5191259535773247277sketch
:app:preBuild UP-TO-DATE
:app:preDebugBuild
:app:compileDebugAidl
:app:compileDebugRenderscript
:app:checkDebugManifest
:app:generateDebugBuildConfig
:app:prepareLintJar
:app:generateDebugResValues
:app:generateDebugResources
:app:mergeDebugResources
:app:createDebugCompatibleScreenManifests
:app:processDebugManifest
:app:splitsDiscoveryTaskDebug
:app:processDebugResources
:app:generateDebugSources
:app:javaPreCompileDebug
:app:compileDebugJavaWithJavac
:app:compileDebugNdk NO-SOURCE
:app:compileDebugSources
:app:mergeDebugShaders
:app:compileDebugShaders
:app:generateDebugAssets
:app:mergeDebugAssets
:app:extractTryWithResourcesSupportJarDebug
:app:transformClassesWithStackFramesFixerForDebug
:app:transformClassesWithDesugarForDebug
:app:transformClassesWithDexBuilderForDebug
:app:transformDexArchiveWithExternalLibsDexMergerForDebug
:app:transformDexArchiveWithDexMergerForDebug
:app:mergeDebugJniLibFolders
:app:transformNativeLibsWithMergeJniLibsForDebug
:app:processDebugJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForDebug
:app:validateSigningDebug
:app:packageDebug
:app:assembleDebug

BUILD SUCCESSFUL in 1m 49s
28 actionable tasks: 28 executed
FATAL EXCEPTION: main
Process: processing.test.testblepdroid1, PID: 5916
java.lang.RuntimeException: Unable to start activity ComponentInfo{processing.test.testblepdroid1/processing.test.testblepdroid1.MainActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2697)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2771)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1432)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5912)
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:1405)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)
Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at android.support.v7.app.AppCompatDelegateImplV9.createSubDecor(AppCompatDelegateImplV9.java:354)
at android.support.v7.app.AppCompatDelegateImplV9.ensureSubDecor(AppCompatDelegateImplV9.java:323)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:293)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:149)
at processing.test.testblepdroid1.MainActivity.onCreate(MainActivity.java:21)
at android.app.Activity.performCreate(Activity.java:6178)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2650)
ā€¦ 10 more