summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/android/localdevicebroadcastreceiver.cpp
blob: b1b78377b910107d0a5e60fc55630ea9395177f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include <QtCore/QLoggingCategory>
#include <QtCore/qrandom.h>
#include "localdevicebroadcastreceiver_p.h"
#include "android/jni_android_p.h"

QT_BEGIN_NAMESPACE

Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)

const char *scanModes[] = {"SCAN_MODE_NONE", "SCAN_MODE_CONNECTABLE", "SCAN_MODE_CONNECTABLE_DISCOVERABLE"};
const char *bondModes[] = {"BOND_NONE", "BOND_BONDING", "BOND_BONDED"};

LocalDeviceBroadcastReceiver::LocalDeviceBroadcastReceiver(QObject *parent) :
    AndroidBroadcastReceiver(parent), previousScanMode(0)
{
    addAction(QJniObject::fromString(
        valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionBondStateChanged>()));
    addAction(QJniObject::fromString(
        valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionScanModeChanged>()));
    addAction(QJniObject::fromString(
        valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionAclConnected>()));
    addAction(QJniObject::fromString(
        valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionAclDisconnected>()));

    //cache integer values for host & bonding mode
    //don't use the java fields directly but refer to them by name
    for (uint i = 0; i < (sizeof(hostModePreset)/sizeof(hostModePreset[0])); i++) {
        hostModePreset[i] = QJniObject::getStaticField<jint>(
                                    QtJniTypes::Traits<QtJniTypes::BluetoothAdapter>::className(),
                                    scanModes[i]);
    }

    for (uint i = 0; i < (sizeof(bondingModePreset)/sizeof(bondingModePreset[0])); i++) {
        bondingModePreset[i] = QJniObject::getStaticField<jint>(
                                    QtJniTypes::Traits<QtJniTypes::BluetoothDevice>::className(),
                                    bondModes[i]);
    }
}

void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
{
    Q_UNUSED(context);
    Q_UNUSED(env);

    QJniObject intentObject(intent);
    const QString action = intentObject.callMethod<jstring>("getAction").toString();
    qCDebug(QT_BT_ANDROID) << QStringLiteral("LocalDeviceBroadcastReceiver::onReceive() - event: %1").arg(action);

    if (action == valueForStaticField<QtJniTypes::BluetoothAdapter,
                                      JavaNames::ActionScanModeChanged>()) {

        const QJniObject extrasBundle =
                intentObject.callMethod<QtJniTypes::Bundle>("getExtras");
        const QJniObject keyExtra =
            QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothAdapter,
                                                       JavaNames::ExtraScanMode>());

        int extra = extrasBundle.callMethod<jint>("getInt", keyExtra.object<jstring>());

        if (previousScanMode != extra) {
            previousScanMode = extra;

            if (extra == hostModePreset[0])
                emit hostModeStateChanged(QBluetoothLocalDevice::HostPoweredOff);
            else if (extra == hostModePreset[1])
                emit hostModeStateChanged(QBluetoothLocalDevice::HostConnectable);
            else if (extra == hostModePreset[2])
                emit hostModeStateChanged(QBluetoothLocalDevice::HostDiscoverable);
            else
                qCWarning(QT_BT_ANDROID) << "Unknown Host State";
        }
    } else if (action == valueForStaticField<QtJniTypes::BluetoothDevice,
                                                        JavaNames::ActionBondStateChanged>()) {
        //get BluetoothDevice
        QJniObject keyExtra = QJniObject::fromString(
                                        valueForStaticField<QtJniTypes::BluetoothDevice,
                                        JavaNames::ExtraDevice>());
        const QJniObject bluetoothDevice =
                intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
                                                                keyExtra.object<jstring>());

        //get new bond state
        keyExtra = QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
                                                              JavaNames::ExtraBondState>());
        const QJniObject extrasBundle =
                intentObject.callMethod<QtJniTypes::Bundle>("getExtras");
        int bondState = extrasBundle.callMethod<jint>("getInt", keyExtra.object<jstring>());

        QBluetoothAddress address(bluetoothDevice.callMethod<jstring>("getAddress").toString());
        if (address.isNull())
                return;

        if (bondState == bondingModePreset[0])
            emit pairingStateChanged(address, QBluetoothLocalDevice::Unpaired);
        else if (bondState == bondingModePreset[1])
            ; //we ignore this as Qt doesn't have equivalent API value
        else if (bondState == bondingModePreset[2])
            emit pairingStateChanged(address, QBluetoothLocalDevice::Paired);
        else
            qCWarning(QT_BT_ANDROID) << "Unknown BOND_STATE_CHANGED value:" << bondState;

    } else if (action == valueForStaticField<QtJniTypes::BluetoothDevice,
                                             JavaNames::ActionAclConnected>() ||
               action == valueForStaticField<QtJniTypes::BluetoothDevice,
                                             JavaNames::ActionAclDisconnected>()) {

        const QString connectEvent = valueForStaticField<QtJniTypes::BluetoothDevice,
                                                         JavaNames::ActionAclConnected>();
        const bool isConnectEvent =
                action == connectEvent ? true : false;

        //get BluetoothDevice
        const QJniObject keyExtra =
            QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
                                                       JavaNames::ExtraDevice>());
        QJniObject bluetoothDevice =
                intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
                                                                keyExtra.object<jstring>());

        QBluetoothAddress address(bluetoothDevice.callMethod<jstring>("getAddress").toString());
        if (address.isNull())
            return;

        emit connectDeviceChanges(address, isConnectEvent);
    }
}

QT_END_NAMESPACE