summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java49
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.cpp10
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_android.cpp101
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h2
4 files changed, 125 insertions, 37 deletions
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
index c91cda5c..cfc8b914 100644
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
+++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
@@ -61,8 +61,15 @@ public class QtBluetoothBroadcastReceiver extends BroadcastReceiver
@SuppressWarnings("WeakerAccess")
static Context qtContext = null;
- private static final int TURN_BT_ON = 3330;
+ // These are opaque tokens that could be used to match the completed action
+ private static final int TURN_BT_ENABLED = 3330;
private static final int TURN_BT_DISCOVERABLE = 3331;
+ private static final int TURN_BT_DISABLED = 3332;
+
+ // The 'Disable' action identifier is hidden in the public APIs so we define it here
+ public static final String ACTION_REQUEST_DISABLE =
+ "android.bluetooth.adapter.action.REQUEST_DISABLE";
+
private static final String TAG = "QtBluetoothBroadcastReceiver";
public void onReceive(Context context, Intent intent)
@@ -90,35 +97,61 @@ public class QtBluetoothBroadcastReceiver extends BroadcastReceiver
qtContext = context;
}
- static public void setDiscoverable()
+ static public boolean setDisabled()
+ {
+ if (!(qtContext instanceof android.app.Activity)) {
+ Log.w(TAG, "Bluetooth cannot be disabled from a service.");
+ return false;
+ }
+ // The 'disable' is hidden in the public API and as such
+ // there are no availability guarantees; may throw an "ActivityNotFoundException"
+ Intent intent = new Intent(ACTION_REQUEST_DISABLE);
+
+ try {
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISABLED);
+ } catch (Exception ex) {
+ Log.w(TAG, "setDisabled() failed to initiate Bluetooth disablement");
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ static public boolean setDiscoverable()
{
if (!(qtContext instanceof android.app.Activity)) {
Log.w(TAG, "Discovery mode cannot be enabled from a service.");
- return;
+ return false;
}
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
try {
- ((Activity)qtContext).startActivityForResult(intent, TURN_BT_ON);
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISCOVERABLE);
} catch (Exception ex) {
+ Log.w(TAG, "setDisabled() failed to initiate Bluetooth discoverability change");
ex.printStackTrace();
+ return false;
}
+ return true;
}
- static public void setConnectable()
+ static public boolean setEnabled()
{
if (!(qtContext instanceof android.app.Activity)) {
- Log.w(TAG, "Connectable mode cannot be enabled from a service.");
- return;
+ Log.w(TAG, "Bluetooth cannot be enabled from a service.");
+ return false;
}
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
try {
- ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISCOVERABLE);
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_ENABLED);
} catch (Exception ex) {
+ Log.w(TAG, "setEnabled() failed to initiate Bluetooth enablement");
ex.printStackTrace();
+ return false;
}
+ return true;
}
static public boolean setPairingMode(String address, boolean isPairing)
diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp
index 7f4de876..7e17433e 100644
--- a/src/bluetooth/qbluetoothlocaldevice.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice.cpp
@@ -104,6 +104,16 @@ QT_BEGIN_NAMESPACE
be connectable and powered on, if required. This mode is is not supported on Android.
On \macos, it is not possible to set the \l hostMode() to HostConnectable or HostPoweredOff.
+ \note Starting from Android 13 (API level 33) the HostPoweredOff state relies on
+ non-public Android API as the public one has been deprecated, see
+ (\l {https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#disable()}
+ {disable()}). This may change in a future version of Android.
+
+ \note At least on Android 12 the device's Bluetooth visibility setting may dictate the result
+ of setting either HostDiscoverable or HostConnectable. For example if the visibility is set
+ \e off, it may not be possible to enter the HostDiscoverable mode, but HostConnectable will be
+ used instead. This may change in future version of Android.
+
*/
void registerQBluetoothLocalDeviceMetaType()
diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp
index fce88838..b7a3a874 100644
--- a/src/bluetooth/qbluetoothlocaldevice_android.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp
@@ -135,19 +135,26 @@ bool QBluetoothLocalDevicePrivate::isValid() const
void QBluetoothLocalDevicePrivate::processHostModeChange(QBluetoothLocalDevice::HostMode newMode)
{
- if (!pendingHostModeTransition) {
- // if not in transition -> pass data on
+ qCDebug(QT_BT_ANDROID) << "Processing host mode change:" << newMode
+ << ", pending transition:" << pendingConnectableHostModeTransition;
+ if (!pendingConnectableHostModeTransition) {
+ // If host mode is not in transition -> pass data on
emit q_ptr->hostModeStateChanged(newMode);
return;
}
+ // Host mode is in transition: check if the new mode is 'off' in which state
+ // we can enter the targeted 'Connectable' state
if (isValid() && newMode == QBluetoothLocalDevice::HostPoweredOff) {
- bool success = (bool)obj->callMethod<jboolean>("enable", "()Z");
- if (!success)
+ const bool success = (bool)QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setEnabled");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Transitioning Bluetooth from OFF to ON failed";
emit q_ptr->error(QBluetoothLocalDevice::UnknownError);
+ }
}
-
- pendingHostModeTransition = false;
+ pendingConnectableHostModeTransition = false;
}
// Return -1 if address is not part of a pending pairing request
@@ -251,49 +258,87 @@ void QBluetoothLocalDevice::powerOn()
return;
if (d_ptr->adapter()) {
- bool ret = (bool)d_ptr->adapter()->callMethod<jboolean>("enable", "()Z");
- if (!ret)
+ bool success(false);
+ if (QtAndroidPrivate::androidSdkVersion() >= 31) {
+ success = (bool)QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setEnabled");
+ } else {
+ success = (bool)d_ptr->adapter()->callMethod<jboolean>("enable", "()Z");
+ }
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Enabling bluetooth failed";
emit error(QBluetoothLocalDevice::UnknownError);
+ }
}
}
void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode requestedMode)
{
- QBluetoothLocalDevice::HostMode mode = requestedMode;
+ QBluetoothLocalDevice::HostMode nextMode = requestedMode;
if (requestedMode == HostDiscoverableLimitedInquiry)
- mode = HostDiscoverable;
+ nextMode = HostDiscoverable;
- if (mode == hostMode())
+ if (nextMode == hostMode())
return;
- if (mode == QBluetoothLocalDevice::HostPoweredOff) {
- bool success = false;
- if (d_ptr->adapter())
- success = (bool)d_ptr->adapter()->callMethod<jboolean>("disable", "()Z");
+ switch (nextMode) {
- if (!success)
+ case QBluetoothLocalDevice::HostPoweredOff: {
+ bool success = false;
+ if (d_ptr->adapter()) {
+ if (QtAndroidPrivate::androidSdkVersion() >= 31) {
+ success = (bool)QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setDisabled");
+ } else {
+ success = (bool)d_ptr->adapter()->callMethod<jboolean>("disable", "()Z");
+ }
+ }
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to power off the adapter";
emit error(QBluetoothLocalDevice::UnknownError);
- } else if (mode == QBluetoothLocalDevice::HostConnectable) {
- if (hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
- // cannot directly go from Discoverable to Connectable
- // we need to go to disabled mode and enable once disabling came through
+ }
+ break;
+ }
+ case QBluetoothLocalDevice::HostConnectable: {
+ if (hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
+ // On Android 'Discoverable' is actually 'CONNECTABLE_DISCOVERABLE', and
+ // it seems we cannot go directly from "Discoverable" to "Connectable". Instead
+ // we need to go to disabled mode first and then to the 'Connectable' mode
setHostMode(QBluetoothLocalDevice::HostPoweredOff);
- d_ptr->pendingHostModeTransition = true;
+ d_ptr->pendingConnectableHostModeTransition = true;
} else {
- QAndroidJniObject::callStaticMethod<void>(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
- "setConnectable");
+ const bool success = (bool)QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setEnabled");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to enable the Bluetooth";
+ emit error(QBluetoothLocalDevice::UnknownError);
+ }
}
- } else if (mode == QBluetoothLocalDevice::HostDiscoverable
- || mode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) {
+ break;
+ }
+
+ case QBluetoothLocalDevice::HostDiscoverable: {
if (!ensureAndroidPermission(BluetoothPermission::Advertise)) {
qCWarning(QT_BT_ANDROID) << "Local device setHostMode() failed due to"
"missing permissions";
return;
}
- QAndroidJniObject::callStaticMethod<void>(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver", "setDiscoverable");
+ const bool success = (bool)QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setDiscoverable");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to set Bluetooth as discoverable";
+ emit error(QBluetoothLocalDevice::UnknownError);
+ }
+ break;
+ }
+ default:
+ qCWarning(QT_BT_ANDROID) << "setHostMode() unsupported host mode:" << nextMode;
+ break;
}
}
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index 198d1d1f..71e75a7d 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -138,7 +138,7 @@ private:
public:
LocalDeviceBroadcastReceiver *receiver;
- bool pendingHostModeTransition = false;
+ bool pendingConnectableHostModeTransition = false;
QList<QPair<QBluetoothAddress, bool> > pendingPairings;
QList<QBluetoothAddress> connectedDevices;