BluetoothSocket.java revision 9fab0aef19a4633d2e4670564e5d7ae9e52fe11f
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.
389fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * On the client side, use a single {@link BluetoothSocket} to both intiate
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
9771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** prevents all native calls after destroyNative() */
9871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private boolean mClosed;
9971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
10071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** protects mClosed */
10171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private final ReentrantReadWriteLock mLock;
10271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
10371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /** used by native code only */
10471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private int mSocketData;
1050b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1060b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
107bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * Construct a BluetoothSocket.
1086a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly     * @param type    type of socket
1090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
1100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param auth    require the remote device to be authenticated
1110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param encrypt require the connection to be encrypted
112bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param device  remote device that this socket can connect to
1130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @param port    remote port
11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * @param uuid    SDP uuid
1150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @throws IOException On error, for example Bluetooth not available, or
1160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     *                     insufficient priveleges
1170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
118bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
12124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
12224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                throw new IOException("Invalid RFCOMM channel: " + port);
12324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
12424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid == null) {
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = port;
12716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = null;
12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        } else {
12916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mSdp = new SdpHelper(device, uuid);
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mPort = -1;
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1326a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly        mType = type;
1330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mAuth = auth;
1340b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mEncrypt = encrypt;
135bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDevice = device;
136bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (device == null) {
137bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = null;
138bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        } else {
139bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAddress = device.getAddress();
140bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        }
1410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        if (fd == -1) {
1420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketNative();
1430b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } else {
1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            initSocketFromFdNative(fd);
1450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mInputStream = new BluetoothInputStream(this);
1470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        mOutputStream = new BluetoothOutputStream(this);
14871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mClosed = false;
14971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock = new ReentrantReadWriteLock();
1500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
152bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    /**
15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Construct a BluetoothSocket from address. Used by native code.
154bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param type    type of socket
155bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param fd      fd to use for connected socket, or -1 for a new socket
156bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param auth    require the remote device to be authenticated
157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param encrypt require the connection to be encrypted
158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param address remote device that this socket can connect to
159bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @param port    remote port
160bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     * @throws IOException On error, for example Bluetooth not available, or
161bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     *                     insufficient priveleges
162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly     */
163bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
164bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            int port) throws IOException {
16516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null);
166bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
167bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
16845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly    /** @hide */
1690b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    @Override
1700b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    protected void finalize() throws Throwable {
1710b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        try {
1720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            close();
1730b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        } finally {
1740b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly            super.finalize();
1750b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        }
1760b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
1770b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
1780b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
1790b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Attempt to connect to a remote device.
18045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>This method will block until a connection is made or the connection
1810b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * fails. If this method returns without an exception then this socket
18245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * is now connected.
18345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>{@link #close} can be used to abort this call from another thread.
18445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @throws IOException on error, for example connection failure
1850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
1860b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void connect() throws IOException {
18771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
18871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
18971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
19016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
19116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
19216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mPort = mSdp.doSdp();  // blocks
19316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
19416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
19516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            connectNative();  // blocks
19671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
19771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
19871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
1990b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2000b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2010b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
20245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Immediately close this socket, and release all associated resources.
20345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>Causes blocked calls on this socket in other threads to immediately
2040b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * throw an IOException.
2050b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2060b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public void close() throws IOException {
20771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abort blocking operations on the socket
20871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
20971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
21071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) return;
21116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (mSdp != null) {
21216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mSdp.cancel();
21316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
21471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            abortNative();
21571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
21671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
21771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
21871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
21916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // all native calls are guaranteed to immediately return after
22071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        // abortNative(), so this lock should immediatley acquire
22171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.writeLock().lock();
22271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
22371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mClosed = true;
22471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            destroyNative();
22571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
22671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.writeLock().unlock();
22771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
2280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2290b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
23145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * Get the remote device this socket is connecting, or connected, to.
23245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * @return remote device
2330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
234bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothDevice getRemoteDevice() {
235bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mDevice;
2360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the input stream associated with this socket.
24045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The input stream will be returned even if the socket is not yet
2410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2430b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return InputStream
2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public InputStream getInputStream() throws IOException {
2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mInputStream;
2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    /**
2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * Get the output stream associated with this socket.
25145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly     * <p>The output stream will be returned even if the socket is not yet
2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * connected, but operations on that stream will throw IOException until
2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * the associated socket is connected.
2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     * @return OutputStream
2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly     */
2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    public OutputStream getOutputStream() throws IOException {
2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly        return mOutputStream;
2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly    }
2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly
26024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
26124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Currently returns unix errno instead of throwing IOException,
26224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * so that BluetoothAdapter can check the error code for EADDRINUSE
26324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
26424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ int bindListen() {
26571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
26671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
26724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (mClosed) return EBADFD;
26824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return bindListenNative();
26971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
27071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
27171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
27271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
27371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
27471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ BluetoothSocket accept(int timeout) throws IOException {
27571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
27671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
27771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
27871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return acceptNative(timeout);
27971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
28071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
28171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
28271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
28371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
28471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int available() throws IOException {
28571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
28671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
28771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
28871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return availableNative();
28971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
29071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
29171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
29271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
29371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
29471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int read(byte[] b, int offset, int length) throws IOException {
29571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
29671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
29771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
29871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return readNative(b, offset, length);
29971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
30071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
30171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
30271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
30371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
30471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    /*package*/ int write(byte[] b, int offset, int length) throws IOException {
30571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        mLock.readLock().lock();
30671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        try {
30771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            if (mClosed) throw new IOException("socket closed");
30871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            return writeNative(b, offset, length);
30971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        } finally {
31071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly            mLock.readLock().unlock();
31171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly        }
31271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    }
31371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly
3146a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketNative() throws IOException;
3156a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void initSocketFromFdNative(int fd) throws IOException;
3166a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void connectNative() throws IOException;
31724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int bindListenNative();
31871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native BluetoothSocket acceptNative(int timeout) throws IOException;
31971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int availableNative() throws IOException;
32071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int readNative(byte[] b, int offset, int length) throws IOException;
32171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native int writeNative(byte[] b, int offset, int length) throws IOException;
32271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly    private native void abortNative() throws IOException;
3236a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly    private native void destroyNative() throws IOException;
32424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
32524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * Throws an IOException for given posix errno. Done natively so we can
32624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * use strerr to convert to string error.
32724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
32824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /*package*/ native void throwErrnoNative(int errno) throws IOException;
32916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
33016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
33116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Helper to perform blocking SDP lookup.
33216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
33316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class SdpHelper extends IBluetoothCallback.Stub {
33416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final IBluetooth service;
33516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final ParcelUuid uuid;
33616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private final BluetoothDevice device;
33716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private int channel;
33816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        private boolean canceled;
33916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public SdpHelper(BluetoothDevice device, ParcelUuid uuid) {
34016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            service = BluetoothDevice.getService();
34116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.device = device;
34216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
34316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            canceled = false;
34416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
34516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /**
34616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * Returns the RFCOMM channel for the UUID, or throws IOException
34716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         * on failure.
34816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly         */
34916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized int doSdp() throws IOException {
35016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
35116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            channel = -1;
35216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
35316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            boolean inProgress = false;
35416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
35516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this);
35616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (RemoteException e) {Log.e(TAG, "", e);}
35716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
35816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!inProgress) throw new IOException("Unable to start Service Discovery");
35916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            try {
36116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                /* 12 second timeout as a precaution - onRfcommChannelFound
36216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                 * should always occur before the timeout */
36316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                wait(12000);   // block
36416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            } catch (InterruptedException e) {}
36616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
36716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (canceled) throw new IOException("Service discovery canceled");
36816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (channel < 1) throw new IOException("Service discovery failed");
36916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
37016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return channel;
37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
37216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        /** Object cannot be re-used after calling cancel() */
37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void cancel() {
37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                canceled = true;
37616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = -1;
37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
37916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
38016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public synchronized void onRfcommChannelFound(int channel) {
38116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (!canceled) {
38216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                this.channel = channel;
38316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                notifyAll();  // unblock
38416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
38516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
38616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
3870b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly}
388