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