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