summaryrefslogtreecommitdiffstats
path: root/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java
blob: ef4463015e10010dd6450de0046abdfb65242732 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:COMM$
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** $QT_END_LICENSE$
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
****************************************************************************/

package org.qtproject.qt5.android.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import java.io.IOException;
import java.util.UUID;

@SuppressWarnings("WeakerAccess")
public class QtBluetoothSocketServer extends Thread
{

    /* Pointer to the Qt object that "owns" the Java object */
    @SuppressWarnings({"WeakerAccess", "CanBeFinal"})
    long qtObject = 0;
    @SuppressWarnings({"WeakerAccess", "CanBeFinal"})
    public boolean logEnabled = false;

    private static final String TAG = "QtBluetooth";
    private boolean m_isSecure = false;
    private UUID m_uuid;
    private String m_serviceName;
    private BluetoothServerSocket m_serverSocket = null;

    //error codes
    private static final int QT_NO_BLUETOOTH_SUPPORTED = 0;
    private static final int QT_LISTEN_FAILED = 1;
    private static final int QT_ACCEPT_FAILED = 2;

    public QtBluetoothSocketServer()
    {
        setName("QtSocketServerThread");
    }

    public void setServiceDetails(String uuid, String serviceName, boolean isSecure)
    {
        m_uuid = UUID.fromString(uuid);
        m_serviceName = serviceName;
        m_isSecure = isSecure;

    }

    public void run()
    {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter == null) {
            errorOccurred(qtObject, QT_NO_BLUETOOTH_SUPPORTED);
            return;
        }

        try {
            if (m_isSecure) {
                m_serverSocket = adapter.listenUsingRfcommWithServiceRecord(m_serviceName, m_uuid);
                if (logEnabled)
                    Log.d(TAG, "Using secure socket listener");
            } else {
                m_serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(m_serviceName, m_uuid);
                if (logEnabled)
                    Log.d(TAG, "Using insecure socket listener");
            }
        } catch (IOException ex) {
            if (logEnabled)
                Log.d(TAG, "Server socket listen() failed:" + ex.toString());
            ex.printStackTrace();
            errorOccurred(qtObject, QT_LISTEN_FAILED);
            return;
        }

        if (isInterrupted()) // close() may have been called
            return;

        BluetoothSocket s;
        if (m_serverSocket != null) {
            try {
                while (!isInterrupted()) {
                    //this blocks until we see incoming connection
                    //or close() is called
                    if (logEnabled)
                        Log.d(TAG, "Waiting for new incoming socket");
                    s = m_serverSocket.accept();

                    if (logEnabled)
                        Log.d(TAG, "New socket accepted");
                    newSocket(qtObject, s);
                }
            } catch (IOException ex) {
                if (logEnabled)
                    Log.d(TAG, "Server socket accept() failed:" + ex.toString());
                ex.printStackTrace();
                errorOccurred(qtObject, QT_ACCEPT_FAILED);
            }
        }

        Log.d(TAG, "Leaving server socket thread.");
    }

    // This function closes the socket server
    //
    // A note on threading behavior
    // 1. This function is called from Qt thread which is different from the Java thread (run())
    // 2. The caller of this function expects the Java thread to be finished upon return
    //
    // First we mark the Java thread as interrupted, then call close() on the
    // listening socket if it had been created, and lastly wait for the thread to finish.
    // The close() method of the socket is intended to be used to abort the accept() from
    // another thread, as per the accept() documentation.
    //
    // If the Java thread was in the middle of creating a socket with the non-blocking
    // listen* call, the run() will notice after the returning from the listen* that it has
    // been interrupted and returns early from the run().
    //
    // If the Java thread was in the middle of the blocking accept() call, it will get
    // interrupated by the close() call on the socket. After returning the run() will
    // notice it has been interrupted and return from the run()
    public void close()
    {
        if (!isAlive())
            return;

        try {
            //ensure closing of thread if we are not currently blocking on accept()
            interrupt();

            //interrupts accept() call above
            if (m_serverSocket != null)
                m_serverSocket.close();
            // Wait for the thread to finish
            join(20); // Maximum wait in ms, typically takes < 1ms
        } catch (Exception ex) {
            Log.d(TAG, "Closing server socket close() failed:" + ex.toString());
            ex.printStackTrace();
        }
    }

    public static native void errorOccurred(long qtObject, int errorCode);
    public static native void newSocket(long qtObject, BluetoothSocket socket);
}