BluetoothSocket.java revision 6d95fc0a2ca910212a43c4547c0ef000659b72dc
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. 1836d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * <p>Creating new connections to 1846d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * remote Bluetooth devices should not be attempted while device discovery 1856d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * is in progress. Device discovery is a heavyweight procedure on the 1866d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * Bluetooth adapter and will significantly slow a device connection. 1876d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing 1886d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * discovery. Discovery is not managed by the Activity, 1896d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * but is run as a system service, so an application should always call 1906d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * {@link BluetoothAdapter#cancelDiscovery()} even if it 1916d95fc0a2ca910212a43c4547c0ef000659b72dcScott Main * did not directly request a discovery, just to be sure. 19245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>{@link #close} can be used to abort this call from another thread. 19345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * @throws IOException on error, for example connection failure 1940b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 1950b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public void connect() throws IOException { 19671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 19771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 19871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) throw new IOException("socket closed"); 19916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 20016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (mSdp != null) { 20116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mPort = mSdp.doSdp(); // blocks 20216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 20316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 20416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly connectNative(); // blocks 20571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 20671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 20771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 2080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 21145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * Immediately close this socket, and release all associated resources. 21245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>Causes blocked calls on this socket in other threads to immediately 2130b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * throw an IOException. 2140b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public void close() throws IOException { 21671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly // abort blocking operations on the socket 21771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 21871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 21971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) return; 22016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (mSdp != null) { 22116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mSdp.cancel(); 22216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 22371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly abortNative(); 22471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 22571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 22671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 22771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 22816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // all native calls are guaranteed to immediately return after 22971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly // abortNative(), so this lock should immediatley acquire 23071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.writeLock().lock(); 23171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 23271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mClosed = true; 23371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly destroyNative(); 23471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 23571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.writeLock().unlock(); 23671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 24045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * Get the remote device this socket is connecting, or connected, to. 24145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * @return remote device 2420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 243bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothDevice getRemoteDevice() { 244bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mDevice; 2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the input stream associated with this socket. 24945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The input stream will be returned even if the socket is not yet 2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return InputStream 2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public InputStream getInputStream() throws IOException { 2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mInputStream; 2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the output stream associated with this socket. 26045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The output stream will be returned even if the socket is not yet 2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return OutputStream 2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public OutputStream getOutputStream() throws IOException { 2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mOutputStream; 2670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2680b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 26924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 27024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * Currently returns unix errno instead of throwing IOException, 27124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * so that BluetoothAdapter can check the error code for EADDRINUSE 27224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 27324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ int bindListen() { 27471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 27571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 27624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (mClosed) return EBADFD; 27724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return bindListenNative(); 27871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 27971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 28071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 28171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 28271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 28371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ BluetoothSocket accept(int timeout) throws IOException { 28471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 28571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 28671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) throw new IOException("socket closed"); 28771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly return acceptNative(timeout); 28871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 28971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 29071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 29171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 29271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 29371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int available() throws IOException { 29471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 29571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 29671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) throw new IOException("socket closed"); 29771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly return availableNative(); 29871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 29971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 30071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 30171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 30271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 30371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int read(byte[] b, int offset, int length) throws IOException { 30471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 30571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 30671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) throw new IOException("socket closed"); 30771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly return readNative(b, offset, length); 30871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 30971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 31071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 31171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 31271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 31371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int write(byte[] b, int offset, int length) throws IOException { 31471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().lock(); 31571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 31671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly if (mClosed) throw new IOException("socket closed"); 31771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly return writeNative(b, offset, length); 31871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } finally { 31971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly mLock.readLock().unlock(); 32071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 32171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 32271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 3236a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private native void initSocketNative() throws IOException; 3246a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private native void initSocketFromFdNative(int fd) throws IOException; 3256a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private native void connectNative() throws IOException; 32624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native int bindListenNative(); 32771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly private native BluetoothSocket acceptNative(int timeout) throws IOException; 32871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly private native int availableNative() throws IOException; 32971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly private native int readNative(byte[] b, int offset, int length) throws IOException; 33071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly private native int writeNative(byte[] b, int offset, int length) throws IOException; 33171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly private native void abortNative() throws IOException; 3326a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private native void destroyNative() throws IOException; 33324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 33424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * Throws an IOException for given posix errno. Done natively so we can 33524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * use strerr to convert to string error. 33624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 33724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ native void throwErrnoNative(int errno) throws IOException; 33816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 33916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 34016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Helper to perform blocking SDP lookup. 34116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 34216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static class SdpHelper extends IBluetoothCallback.Stub { 34316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final IBluetooth service; 34416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final ParcelUuid uuid; 34516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final BluetoothDevice device; 34616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private int channel; 34716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private boolean canceled; 34816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public SdpHelper(BluetoothDevice device, ParcelUuid uuid) { 34916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly service = BluetoothDevice.getService(); 35016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.device = device; 35116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.uuid = uuid; 35216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly canceled = false; 35316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 35416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 35516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Returns the RFCOMM channel for the UUID, or throws IOException 35616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * on failure. 35716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 35816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized int doSdp() throws IOException { 35916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (canceled) throw new IOException("Service discovery canceled"); 36016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 36116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 36216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly boolean inProgress = false; 36316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 36416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly inProgress = service.fetchRemoteUuids(device.getAddress(), uuid, this); 36516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 36616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 36716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (!inProgress) throw new IOException("Unable to start Service Discovery"); 36816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 36916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 37016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /* 12 second timeout as a precaution - onRfcommChannelFound 37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * should always occur before the timeout */ 37216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly wait(12000); // block 37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (InterruptedException e) {} 37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 37616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (canceled) throw new IOException("Service discovery canceled"); 37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (channel < 1) throw new IOException("Service discovery failed"); 37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 37916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return channel; 38016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 38116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** Object cannot be re-used after calling cancel() */ 38216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized void cancel() { 38316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (!canceled) { 38416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly canceled = true; 38516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 38616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly notifyAll(); // unblock 38716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 38816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 38916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized void onRfcommChannelFound(int channel) { 39016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (!canceled) { 39116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.channel = channel; 39216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly notifyAll(); // unblock 39316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 39416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 39516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 3960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly} 397