BluetoothSocket.java revision 3aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45
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 *
683aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference">
693aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3>
703aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about using Bluetooth, read the
713aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
723aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div>
733aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez *
749fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket}
759fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream}
769fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream}
770b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */
780b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable {
7916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final String TAG = "BluetoothSocket";
8016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
8124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /** @hide */
8224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public static final int MAX_RFCOMM_CHANNEL = 30;
8324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
8445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
856a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_RFCOMM = 1;
866a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_SCO = 2;
876a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    /*package*/ static final int TYPE_L2CAP = 3;
886a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly
8924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EBADFD = 77;
9024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ static final int EADDRINUSE = 98;
9124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
926a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private final int mType;  /* one of TYPE_RFCOMM etc */
93bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final BluetoothDevice mDevice;    /* remote device */
940b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final String mAddress;    /* remote address */
950b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mAuth;
960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final boolean mEncrypt;
970b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothInputStream mInputStream;
980b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    private final BluetoothOutputStream mOutputStream;
9916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final SdpHelper mSdp;
10016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
10116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private int mPort;  /* RFCOMM channel or L2CAP psm */
1020b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
103ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    private enum SocketState {
104ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        INIT,
105ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        CONNECTED,
106ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        CLOSED
107ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
108ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
10971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** prevents all native calls after destroyNative() */
110ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    private SocketState mSocketState;
11171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
112ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /** protects mSocketState */
11371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private final ReentrantReadWriteLock mLock;
11471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
11571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** used by native code only */
11671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private int mSocketData;
1170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
119bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * Construct a BluetoothSocket.
1206a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly     * @param type    type of socket
1210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
1220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param auth    require the remote device to be authenticated
1230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param encrypt require the connection to be encrypted
124bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param device  remote device that this socket can connect to
1250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param port    remote port
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * @param uuid    SDP uuid
1270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @throws IOException On error, for example Bluetooth not available, or
128f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
1290b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
130bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
13324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
13424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                throw new IOException("Invalid RFCOMM channel: " + port);
13524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
13624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid == null) {
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = port;
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = null;
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        } else {
14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = new SdpHelper(device, uuid);
14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = -1;
14316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1446a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly        mType = type;
1450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mAuth = auth;
1460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mEncrypt = encrypt;
147bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDevice = device;
148bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (device == null) {
149bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = null;
150bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        } else {
151bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = device.getAddress();
152bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        }
1530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        if (fd == -1) {
1540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketNative();
1550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } else {
1560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketFromFdNative(fd);
1570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mInputStream = new BluetoothInputStream(this);
1590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mOutputStream = new BluetoothOutputStream(this);
160ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        mSocketState = SocketState.INIT;
16171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock = new ReentrantReadWriteLock();
1620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
164bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /**
16516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Construct a BluetoothSocket from address. Used by native code.
166bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param type    type of socket
167bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
168bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param auth    require the remote device to be authenticated
169bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param encrypt require the connection to be encrypted
170bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param address remote device that this socket can connect to
171bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param port    remote port
172bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @throws IOException On error, for example Bluetooth not available, or
173f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     *                     insufficient privileges
174bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     */
175bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
176bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int port) throws IOException {
17716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null);
178bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
179bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
18045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** @hide */
1810b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    @Override
1820b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    protected void finalize() throws Throwable {
1830b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        try {
1840b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            close();
1850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } finally {
1860b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            super.finalize();
1870b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1880b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1890b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1900b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
1910b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Attempt to connect to a remote device.
19245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>This method will block until a connection is made or the connection
1930b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * fails. If this method returns without an exception then this socket
19445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * is now connected.
1956d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * <p>Creating new connections to
1966d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * remote Bluetooth devices should not be attempted while device discovery
1976d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * is in progress. Device discovery is a heavyweight procedure on the
1986d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Bluetooth adapter and will significantly slow a device connection.
1996d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
2006d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * discovery. Discovery is not managed by the Activity,
2016d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * but is run as a system service, so an application should always call
2026d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * {@link BluetoothAdapter#cancelDiscovery()} even if it
2036d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main     * did not directly request a discovery, just to be sure.
20445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>{@link #close} can be used to abort this call from another thread.
20545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @throws IOException on error, for example connection failure
2060b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2070b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void connect() throws IOException {
20871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
20971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
210ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
21116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
21216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
21316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mPort = mSdp.doSdp();  // blocks
21416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
21516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
21616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            connectNative();  // blocks
217ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CONNECTED;
21871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
21971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
22071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
22445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Immediately close this socket, and release all associated resources.
22545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>Causes blocked calls on this socket in other threads to immediately
2260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * throw an IOException.
2270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void close() throws IOException {
22971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abort blocking operations on the socket
23071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
23171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
232ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) return;
23316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
23416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mSdp.cancel();
23516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
23671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            abortNative();
23771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
23871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
23971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
24071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
24116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // all native calls are guaranteed to immediately return after
242f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby        // abortNative(), so this lock should immediately acquire
24371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.writeLock().lock();
24471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
245ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CLOSED;
24671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            destroyNative();
24771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
24871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.writeLock().unlock();
24971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
25345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Get the remote device this socket is connecting, or connected, to.
25445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @return remote device
2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
256bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothDevice getRemoteDevice() {
257bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mDevice;
2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the input stream associated with this socket.
26245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The input stream will be returned even if the socket is not yet
2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return InputStream
2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public InputStream getInputStream() throws IOException {
2680b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mInputStream;
2690b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2700b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the output stream associated with this socket.
27345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The output stream will be returned even if the socket is not yet
2740b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2750b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2760b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return OutputStream
2770b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2780b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public OutputStream getOutputStream() throws IOException {
2790b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mOutputStream;
2800b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2810b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
28224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
283ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * Get the connection status of this socket, ie, whether there is an active connection with
284ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * remote device.
285ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     * @return true if connected
286ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     *         false if not connected
287ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie     */
288ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    public boolean isConnected() {
289ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie        return (mSocketState == SocketState.CONNECTED);
290ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    }
291ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
292ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie    /**
29324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Currently returns unix errno instead of throwing IOException,
29424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * so that BluetoothAdapter can check the error code for EADDRINUSE
29524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
29624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ int bindListen() {
29771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
29871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
299ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) return EBADFD;
30024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return bindListenNative();
30171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
30271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
30371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
30471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
30571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
30671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
30771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
30871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
309ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
310ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie
311ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            BluetoothSocket acceptedSocket = acceptNative(timeout);
312ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            mSocketState = SocketState.CONNECTED;
313ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            return acceptedSocket;
31471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
31571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
31671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
31771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
31871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
31971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int available() throws IOException {
32071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
32171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
322ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
32371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return availableNative();
32471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
32571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
32671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
32771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
32871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
32971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
33071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
33171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
332ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
33371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return readNative(b, offset, length);
33471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
33571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
33671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
33771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
33871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
33971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
34071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
34171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
342ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie            if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
34371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return writeNative(b, offset, length);
34471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
34571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
34671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
34771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
34871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
3496a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketNative() throws IOException;
3506a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketFromFdNative(int fd) throws IOException;
3516a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void connectNative() throws IOException;
35224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int bindListenNative();
35371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native BluetoothSocket acceptNative(int timeout) throws IOException;
35471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int availableNative() throws IOException;
35571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int readNative(byte[] b, int offset, int length) throws IOException;
35671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int writeNative(byte[] b, int offset, int length) throws IOException;
35771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native void abortNative() throws IOException;
3586a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void destroyNative() throws IOException;
35924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
36024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Throws an IOException for given posix errno. Done natively so we can
36124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * use strerr to convert to string error.
36224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
36324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ native void throwErrnoNative(int errno) throws IOException;
36416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
36616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Helper to perform blocking SDP lookup.
36716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
36816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class SdpHelper extends IBluetoothCallback.Stub {
36916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final IBluetooth service;
37016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final ParcelUuid uuid;
37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final BluetoothDevice device;
37216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private int channel;
37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private boolean canceled;
37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public SdpHelper(BluetoothDevice device, ParcelUuid uuid) {
37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            service = BluetoothDevice.getService();
37616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.device = device;
37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            canceled = false;
37916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
38016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /**
38116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * Returns the RFCOMM channel for the UUID, or throws IOException
38216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * on failure.
38316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         */
38416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized int doSdp() throws IOException {
38516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
38616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            channel = -1;
38716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
38816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            boolean inProgress = false;
38916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
39016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this);
39116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (RemoteException e) {Log.e(TAG, "", e);}
39216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
39316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!inProgress) throw new IOException("Unable to start Service Discovery");
39416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
39516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
39616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                /* 12 second timeout as a precaution - onRfcommChannelFound
39716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                 * should always occur before the timeout */
39816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                wait(12000);   // block
39916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
40016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (InterruptedException e) {}
40116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
40216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
40316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (channel < 1) throw new IOException("Service discovery failed");
40416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
40516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return channel;
40616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
40716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /** Object cannot be re-used after calling cancel() */
40816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void cancel() {
40916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
41016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                canceled = true;
41116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = -1;
41216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
41316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
41416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
41516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void onRfcommChannelFound(int channel) {
41616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
41716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                this.channel = channel;
41816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
41916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
42016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
42116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
4220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly}
423