Bluetooth with Qt on Android. Calling java classes through jni on abstract class

2k views Asked by At

Possible duplicate here, but the accepted answer is very short and not of much help.

I am using Qt 5.2 for Android. I want to use my android device Bluetooth functionality which is currently not directly supported by the Qt framework. Therefore I have started using JNI to access Android Java classes and methods.

I am able to create an object of the AudioTimestamp class by doing so:

QAndroidJniObject audioTimestamp2("android/media/AudioTimestamp");

if(!audioTimestamp2.isValid())
{
    qDebug() << "audioTimestamp2 is not a valid object";
    return false;
}

The first line calls the default constructor so this works fine. This was just a test to see if I were able to create a valid object.

When starting with the Bluetooth implementation I read from developer.android.com that I need to get the bluetooth adapter of the device by:

BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();

so I tried doing it like this:

//Create Java string used to obtain bluetooth adapter.
QAndroidJniObject systemService = QAndroidJniObject::fromString("BLUETOOTH_SERVICE");

//Create Context Object.
QAndroidJniObject context("android/content/Context");

if(!context.isValid())
{
    qDebug() << "context is not a valid object";
    return false;
}

//Call getSystemService method on context object and return manager object.
QAndroidJniObject bluetoothManager = context.callObjectMethod("getSystemService", "(Ljava/lang/String;)Landroid/bluetooth/BluetoothManager;", systemService.object<jstring>());

if(!bluetoothManager.isValid())
{
    qDebug() << "bluetoothManager is not a valid object";
    return false;
}

//Call getAdapter() on manager.
QAndroidJniObject bluetoothAdapter = bluetoothManager.callObjectMethod("getAdapter", "()Landroid/bluetooth/BluetoothAdapter;");

//More code

if (!bluetoothAdapter.callMethod<jboolean>("isEnabled"))
{
    qDebug() << "Bluetooth is off";

    //Code to ask user to turn bluetooth on here...
}

What I soon figured out is that "getSystemService(Context.BLUETOOTH_SERVICE)" seems to be called out of nowhere. It belongs to the abstract class Context.java. How can I use Qt JNI calls on an abstract class to get the bluetoothManager?

EDIT:

I tried doing this as well:

QAndroidJniObject context("android/app/Service");

but still get:

D/Qt      (22736): ..\AndroidTest\bluetooth.cpp:33 (bool Bluetooth::start()): context is not a valid object 
2

There are 2 answers

1
Over17 On

getSystemService() is a method of android.content.Context. I think you get "context is not a valid object" because it is an abstract class which cannot be instantiated this way. The same for android.app.Service.

"figured out is that "getSystemService(Context.BLUETOOTH_SERVICE)" seems to be called out of nowhere" - in your sample from developer.android.com it is called on this, which is likely a class derived from Activity and, as a result, Context.

You need a context object to call getSystemService().

In addition, you seem to be calling object method with wrong signature: "(Ljava/lang/String;)Ljava/lang/Object;"

0
Petar On

just for others who may end up here, you can get main context using

QtAndroid::androidActivity()

this is how you use it in your case:

// from https://developer.android.com/reference/android/content/Context.html#BLUETOOTH_SERVICE    
// note that the actual string value is "bluetooth" not "BLUETOOTH_SERVICE", Context.BLUETOOTH_SERVICE is a constant that holds "bluetooth" string value
QAndroidJniObject service_name = QAndroidJniObject::fromString("bluetooth");     

// this is your context
QAndroidJniObject activity = QtAndroid::androidActivity(); 

// now you get your bluetooth manager
QAndroidJniObject bluetoothManager = activity.callObjectMethod("getSystemService","(Ljava/lang/String;)Ljava/lang/Object;", service_name.object<jstring>());