10b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/*
20b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Copyright (C) 2009 The Android Open Source Project
30b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
40b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
50b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * you may not use this file except in compliance with the License.
60b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * You may obtain a copy of the License at
70b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
80b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
90b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Unless required by applicable law or agreed to in writing, software
110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
120b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * See the License for the specific language governing permissions and
140b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * limitations under the License.
150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypackage android.bluetooth;
180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
2016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.ParcelUuid;
2116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.RemoteException;
2216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.util.Log;
2316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
240b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.Closeable;
250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.IOException;
260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.InputStream;
270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.OutputStream;
2871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pellyimport java.util.concurrent.locks.ReentrantReadWriteLock;
2971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/**
3145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * A connected or connecting Bluetooth socket.
320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
3345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
3445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
3545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * side, use a {@link BluetoothServerSocket} to create a listening server
369fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * socket. When a connection is accepted by the {@link BluetoothServerSocket},
379fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * it will return a new {@link BluetoothSocket} to manage the connection.
38f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * On the client side, use a single {@link BluetoothSocket} to both initiate
399fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * an outgoing connection and to manage the connection.
400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
419fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
429fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
439fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly *
459fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
469fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothDevice#createRfcommSocketToServiceRecord
479fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * BluetoothDevice.createRfcommSocketToServiceRecord()}.
489fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Then call {@link #connect()} to attempt a connection to the remote device.
499fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * This call will block until a connection is established or the connection
509fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * fails.
5145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
529fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
539fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothServerSocket} documentation.
5445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly *
559fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>Once the socket is connected, whether initiated as a client or accepted
569fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * as a server, open the IO streams by calling {@link #getInputStream} and
579fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
589fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * and {@link java.io.OutputStream} objects, respectively, which are
599fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * automatically connected to the socket.
609fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
619fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>{@link BluetoothSocket} is thread
6245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * safe. In particular, {@link #close} will always immediately abort ongoing
6345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * operations and close the socket.
64cf44059813539bf7f36dabd278cef93ba3122c56Nick Pelly *
659fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p class="note"><strong>Note:</strong>
669fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
679fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main *
689fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket}
699fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream}
709fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream}
710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable {
7316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final String TAG = "BluetoothSocket";
7416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
7524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /** @hide */
7624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public static final int MAX_RFCOMM_CHANNEL = 30;
7724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
7845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
796a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_RFCOMM = 1;
806a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_SCO = 2;
816a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_L2CAP = 3;
826a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly
8324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EBADFD = 77;
8424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EADDRINUSE = 98;
8524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
866a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private final int mType;  /* one of TYPE_RFCOMM etc */
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final BluetoothDevice mDevice;    /* remote device */
880b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final String mAddress;    /* remote address */
890b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mAuth;
900b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mEncrypt;
910b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothInputStream mInputStream;
920b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothOutputStream mOutputStream;
9316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final SdpHelper mSdp;
9416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
9516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private int mPort;  /* RFCOMM channel or L2CAP psm */
960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
97ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    private enum SocketState {
98ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        INIT,
99ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        CONNECTED,
100ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        CLOSED
101ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
102ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
10371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** prevents all native calls after destroyNative() */
104ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    private SocketState mSocketState;
10571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
106ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /** protects mSocketState */
10771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private final ReentrantReadWriteLock mLock;
10871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
10971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** used by native code only */
11071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private int mSocketData;
1110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1120b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
113bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * Construct a BluetoothSocket.
1146a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly     * @param type    type of socket
1150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
1160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param auth    require the remote device to be authenticated
1170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param encrypt require the connection to be encrypted
118bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param device  remote device that this socket can connect to
1190b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param port    remote port
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * @param uuid    SDP uuid
1210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @throws IOException On error, for example Bluetooth not available, or
122f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
1230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
124bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
12724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
12824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                throw new IOException("Invalid RFCOMM channel: " + port);
12924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
13024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid == null) {
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = port;
13316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = null;
13416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        } else {
13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = new SdpHelper(device, uuid);
13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = -1;
13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1386a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly        mType = type;
1390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mAuth = auth;
1400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mEncrypt = encrypt;
141bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDevice = device;
142bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (device == null) {
143bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = null;
144bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        } else {
145bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = device.getAddress();
146bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        }
1470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        if (fd == -1) {
1480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketNative();
1490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } else {
1500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketFromFdNative(fd);
1510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mInputStream = new BluetoothInputStream(this);
1530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mOutputStream = new BluetoothOutputStream(this);
154ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        mSocketState = SocketState.INIT;
15571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock = new ReentrantReadWriteLock();
1560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /**
15916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Construct a BluetoothSocket from address. Used by native code.
160bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param type    type of socket
161bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param auth    require the remote device to be authenticated
163bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param encrypt require the connection to be encrypted
164bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param address remote device that this socket can connect to
165bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param port    remote port
166bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @throws IOException On error, for example Bluetooth not available, or
167f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
168bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     */
169bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
170bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int port) throws IOException {
17116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null);
172bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
173bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
17445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** @hide */
1750b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    @Override
1760b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    protected void finalize() throws Throwable {
1770b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        try {
1780b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            close();
1790b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } finally {
1800b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            super.finalize();
1810b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1820b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1830b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1840b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
1850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Attempt to connect to a remote device.
18645e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>This method will block until a connection is made or the connection
1870b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * fails. If this method returns without an exception then this socket
18845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * is now connected.
1896d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * <p>Creating new connections to
1906d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * remote Bluetooth devices should not be attempted while device discovery
1916d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * is in progress. Device discovery is a heavyweight procedure on the
1926d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Bluetooth adapter and will significantly slow a device connection.
1936d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
1946d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * discovery. Discovery is not managed by the Activity,
1956d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * but is run as a system service, so an application should always call
1966d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * {@link BluetoothAdapter#cancelDiscovery()} even if it
1976d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * did not directly request a discovery, just to be sure.
19845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>{@link #close} can be used to abort this call from another thread.
19945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @throws IOException on error, for example connection failure
2000b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2010b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void connect() throws IOException {
20271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
20371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
204ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
20516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
20616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
20716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mPort = mSdp.doSdp();  // blocks
20816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
20916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
21016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            connectNative();  // blocks
211ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CONNECTED;
21271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
21371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
21471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
21845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Immediately close this socket, and release all associated resources.
21945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>Causes blocked calls on this socket in other threads to immediately
2200b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * throw an IOException.
2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void close() throws IOException {
22371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abort blocking operations on the socket
22471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
22571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
226ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) return;
22716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
22816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mSdp.cancel();
22916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
23071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            abortNative();
23171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
23271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
23371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
23471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
23516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // all native calls are guaranteed to immediately return after
236f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby        // abortNative(), so this lock should immediately acquire
23771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.writeLock().lock();
23871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
239ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CLOSED;
24071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            destroyNative();
24171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
24271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.writeLock().unlock();
24371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
24745e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Get the remote device this socket is connecting, or connected, to.
24845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @return remote device
2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
250bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothDevice getRemoteDevice() {
251bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mDevice;
2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the input stream associated with this socket.
25645e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The input stream will be returned even if the socket is not yet
2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return InputStream
2600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public InputStream getInputStream() throws IOException {
2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mInputStream;
2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the output stream associated with this socket.
26745e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The output stream will be returned even if the socket is not yet
2680b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2690b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2700b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return OutputStream
2710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public OutputStream getOutputStream() throws IOException {
2730b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mOutputStream;
2740b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2750b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
27624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
277ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * Get the connection status of this socket, ie, whether there is an active connection with
278ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * remote device.
279ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * @return true if connected
280ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     *         false if not connected
281ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     */
282ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    public boolean isConnected() {
283ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        return (mSocketState == SocketState.CONNECTED);
284ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
285ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
286ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /**
28724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Currently returns unix errno instead of throwing IOException,
28824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * so that BluetoothAdapter can check the error code for EADDRINUSE
28924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
29024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ int bindListen() {
29171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
29271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
293ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) return EBADFD;
29424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return bindListenNative();
29571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
29671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
29771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
29871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
29971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
30071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
30171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
30271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
303ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
304ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
305ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            BluetoothSocket acceptedSocket = acceptNative(timeout);
306ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CONNECTED;
307ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            return acceptedSocket;
30871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
30971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
31071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
31171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
31271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
31371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int available() throws IOException {
31471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
31571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
316ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
31771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return availableNative();
31871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
31971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
32071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
32171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
32271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
32371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
32471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
32571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
326ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
32771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return readNative(b, offset, length);
32871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
32971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
33071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
33171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
33271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
33371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
33471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
33571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
336ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
33771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return writeNative(b, offset, length);
33871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
33971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
34071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
34171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
34271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
3436a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketNative() throws IOException;
3446a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketFromFdNative(int fd) throws IOException;
3456a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void connectNative() throws IOException;
34624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int bindListenNative();
34771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native BluetoothSocket acceptNative(int timeout) throws IOException;
34871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int availableNative() throws IOException;
34971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int readNative(byte[] b, int offset, int length) throws IOException;
35071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int writeNative(byte[] b, int offset, int length) throws IOException;
35171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native void abortNative() throws IOException;
3526a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void destroyNative() throws IOException;
35324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
35424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Throws an IOException for given posix errno. Done natively so we can
35524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * use strerr to convert to string error.
35624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
35724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ native void throwErrnoNative(int errno) throws IOException;
35816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
35916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
36016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Helper to perform blocking SDP lookup.
36116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
36216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class SdpHelper extends IBluetoothCallback.Stub {
36316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final IBluetooth service;
36416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final ParcelUuid uuid;
36516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final BluetoothDevice device;
36616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private int channel;
36716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private boolean canceled;
36816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public SdpHelper(BluetoothDevice device, ParcelUuid uuid) {
36916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            service = BluetoothDevice.getService();
37016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.device = device;
37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
37216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            canceled = false;
37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /**
37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * Returns the RFCOMM channel for the UUID, or throws IOException
37616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * on failure.
37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         */
37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized int doSdp() throws IOException {
37916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
38016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            channel = -1;
38116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
38216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            boolean inProgress = false;
38316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
38416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this);
38516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (RemoteException e) {Log.e(TAG, "", e);}
38616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
38716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!inProgress) throw new IOException("Unable to start Service Discovery");
38816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
38916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
39016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                /* 12 second timeout as a precaution - onRfcommChannelFound
39116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                 * should always occur before the timeout */
39216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                wait(12000);   // block
39316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
39416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (InterruptedException e) {}
39516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
39616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
39716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (channel < 1) throw new IOException("Service discovery failed");
39816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
39916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return channel;
40016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
40116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /** Object cannot be re-used after calling cancel() */
40216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void cancel() {
40316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
40416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                canceled = true;
40516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = -1;
40616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
40716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
40816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
40916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void onRfcommChannelFound(int channel) {
41016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
41116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                this.channel = channel;
41216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
41316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
41416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
41516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
4160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly}
417