FileDocCategorySizeDatePackage
RfcommSocket.javaAPI DocAndroid 1.5 API23431Wed May 06 22:41:54 BST 2009android.bluetooth

RfcommSocket

public class RfcommSocket extends Object
The Android Bluetooth API is not finalized, and *will* change. Use at your own risk. This class implements an API to the Bluetooth RFCOMM layer. An RFCOMM socket is similar to a normal socket in that it takes an address and a port number. The difference is of course that the address is a Bluetooth-device address, and the port number is an RFCOMM channel. The API allows for the establishment of listening sockets via methods {@link #bind(String, int) bind}, {@link #listen(int) listen}, and {@link #accept(RfcommSocket, int) accept}, as well as for the making of outgoing connections with {@link #connect(String, int) connect}, {@link #connectAsync(String, int) connectAsync}, and {@link #waitForAsyncConnect(int) waitForAsyncConnect}. After constructing a socket, you need to {@link #create() create} it and then {@link #destroy() destroy} it when you are done using it. Both {@link #create() create} and {@link #accept(RfcommSocket, int) accept} return a {@link java.io.FileDescriptor FileDescriptor} for the actual data. Alternatively, you may call {@link #getInputStream() getInputStream} and {@link #getOutputStream() getOutputStream} to retrieve the respective streams without going through the FileDescriptor.
hide

Fields Summary
private int
mNativeData
Used by the native implementation of the class.
private int
mPort
Used by the native implementation of the class.
private String
mAddress
Used by the native implementation of the class.
private FileDescriptor
mFd
We save the return value of {@link #create() create} and {@link #accept(RfcommSocket,int) accept} in this variable, and use it to retrieve the I/O streams.
private int
mTimeoutRemainingMs
After a call to {@link #waitForAsyncConnect(int) waitForAsyncConnect}, if the return value is zero, then, the the remaining time left to wait is written into this variable (by the native implementation). It is possible that {@link #waitForAsyncConnect(int) waitForAsyncConnect} returns before the user-specified timeout expires, which is why we save the remaining time in this member variable for the user to retrieve by calling method {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs}.
private boolean
mIsConnecting
Set to true when an asynchronous (nonblocking) connect is in progress. {@see #connectAsync(String,int)}.
private boolean
mIsBound
Set to true after a successful call to {@link #bind(String,int) bind} and used for error checking in {@link #listen(int) listen}. Reset to false on {@link #destroy() destroy}.
private boolean
mIsListening
Set to true after a successful call to {@link #listen(int) listen} and used for error checking in {@link #accept(RfcommSocket,int) accept}. Reset to false on {@link #destroy() destroy}.
private int
mAcceptTimeoutRemainingMs
Used to store the remaining time after an accept with a non-negative timeout returns unsuccessfully. It is possible that a blocking {@link #accept(int) accept} may wait for less than the time specified by the user, which is why we store the remainder in this member variable for it to be retrieved with method {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs}.
protected FileInputStream
mInputStream
Maintained by {@link #getInputStream() getInputStream}.
protected FileOutputStream
mOutputStream
Maintained by {@link #getOutputStream() getOutputStream}.
Constructors Summary
public RfcommSocket()
Constructor.


       

          
      
        initializeNativeDataNative();
    
Methods Summary
public java.io.FileDescriptoraccept(android.bluetooth.RfcommSocket newSock, int timeoutMs)
Accepts incoming-connection requests for a listening socket bound to an RFCOMM channel. The user may provide a time to wait for an incoming connection. Note that this method may return null (i.e., no incoming connection) before the user-specified timeout expires. For this reason, on a null return value, you need to call {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs} in order to see how much time is left to wait, before you call this method again.

param
newSock is set to the new socket that is created as a result of a successful accept.
param
timeoutMs time (in milliseconds) to block while waiting to an incoming-connection request. A negative value is an infinite wait.
return
FileDescriptor of newSock on success, null on failure. Failure occurs if the timeout expires without a successful connect.
throws
IOException if the socket has not been {@link #create() create}ed, is not bound, or is not a listening socket.
see
#bind(String, int)
see
#listen(int)
see
#getRemainingAcceptWaitingTimeMs()

        synchronized (newSock) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            if (mIsListening == false) {
                throw new IOException("not listening on socket");
            }
            newSock.mFd = acceptNative(newSock, timeoutMs);
            return newSock.mFd;
        }
    
private native java.io.FileDescriptoracceptNative(android.bluetooth.RfcommSocket newSock, int timeoutMs)

public booleanbind(java.lang.String device)
Binds a listening socket to the local device, or a non-listening socket to a remote device. The port is automatically selected as the first available port in the range 12 to 30. NOTE: Currently we ignore the device parameter and always bind the socket to the local device, assuming that it is a listening socket. TODO: Use bind(0) in native code to have the kernel select an unused port.

param
device Bluetooth address of device to bind to (currently ignored).
return
true on success, false on failure
throws
IOException if you have not called {@link #create() create}
see
#listen(int)
see
#accept(RfcommSocket,int)

        if (mFd == null) {
            throw new IOException("socket not created");
        }
        for (int port = 12; port <= 30; port++) {
            if (bindNative(device, port)) {
                mIsBound = true;
                return true;
            }
        }
        mIsBound = false;
        return false;
    
public booleanbind(java.lang.String device, int port)
Binds a listening socket to the local device, or a non-listening socket to a remote device. NOTE: Currently we ignore the device parameter and always bind the socket to the local device, assuming that it is a listening socket.

param
device Bluetooth address of device to bind to (currently ignored).
param
port RFCOMM channel to bind socket to.
return
true on success, false on failure
throws
IOException if you have not called {@link #create() create}
see
#listen(int)
see
#accept(RfcommSocket,int)

        if (mFd == null) {
            throw new IOException("socket not created");
        }
        mIsBound = bindNative(device, port);
        return mIsBound;
    
private native booleanbindNative(java.lang.String device, int port)

private static native voidclassInitNative()

private native voidcleanupNativeDataNative()

public booleanconnect(java.lang.String address, int port)
Starts a blocking connect to a remote RFCOMM socket. It takes the address of a device and the RFCOMM channel (port) to which to connect.

param
address is the Bluetooth address of the remote device.
param
port is the RFCOMM channel
return
true on success, false on failure
throws
IOException if {@link #create() create} has not been called.
see
#connectAsync(String, int)

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            return connectNative(address, port);
        }
    
public booleanconnectAsync(java.lang.String address, int port)
Starts an asynchronous (nonblocking) connect to a remote RFCOMM socket. It takes the address of the device to connect to, as well as the RFCOMM channel (port). On successful return (return value is true), you need to call method {@link #waitForAsyncConnect(int) waitForAsyncConnect} to block for up to a specified number of milliseconds while waiting for the asyncronous connect to complete.

param
address of remote device
param
port the RFCOMM channel
return
true when the asynchronous connect has successfully started, false if there was an error.
throws
IOException is you have not called {@link #create() create}
see
#waitForAsyncConnect(int)
see
#getRemainingAsyncConnectWaitingTimeMs()
see
#connect(String, int)

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            mIsConnecting = connectAsyncNative(address, port);
            return mIsConnecting;
        }
    
private native booleanconnectAsyncNative(java.lang.String address, int port)

private native booleanconnectNative(java.lang.String address, int port)

public java.io.FileDescriptorcreate()
Creates a socket. You need to call this method before performing any other operation on a socket.

return
FileDescriptor for the data stream.
throws
IOException
see
#destroy()

        classInitNative();
    
        if (mFd == null) {
            mFd = createNative();
        }
        if (mFd == null) {
            throw new IOException("socket not created");
        }
        return mFd;
    
private native java.io.FileDescriptorcreateNative()

public voiddestroy()
Destroys a socket created by {@link #create() create}. Call this function when you no longer use the socket in order to release the underlying OS resources.

see
#create()

        synchronized (this) {
            destroyNative();
            mFd = null;
            mIsBound = false;
            mIsListening = false;
        }
    
private native voiddestroyNative()

protected voidfinalize()
Called by the GC to clean up the native data that we set up when we construct the object.

        try {
            cleanupNativeDataNative();
        } finally {
            super.finalize();
        }
    
public java.io.FileDescriptorgetFileDescriptor()
Returns the {@link java.io.FileDescriptor FileDescriptor} of the socket.

return
the FileDescriptor
throws
IOException when the socket has not been {@link #create() created}.

        if (mFd == null) {
            throw new IOException("socket not created");
        }
        return mFd;
    
public java.io.InputStreamgetInputStream()
Retrieves the input stream from the socket. Alternatively, you can do that from the FileDescriptor returned by {@link #create() create} or {@link #accept(RfcommSocket, int) accept}.

return
InputStream
throws
IOException if you have not called {@link #create() create} on the socket.

        if (mFd == null) {
            throw new IOException("socket not created");
        }

        synchronized (this) {
            if (mInputStream == null) {
                mInputStream = new FileInputStream(mFd);
            }

            return mInputStream;
        }
    
public java.io.OutputStreamgetOutputStream()
Retrieves the output stream from the socket. Alternatively, you can do that from the FileDescriptor returned by {@link #create() create} or {@link #accept(RfcommSocket, int) accept}.

return
OutputStream
throws
IOException if you have not called {@link #create() create} on the socket.

        if (mFd == null) {
            throw new IOException("socket not created");
        }

        synchronized (this) {
            if (mOutputStream == null) {
                mOutputStream = new FileOutputStream(mFd);
            }

            return mOutputStream;
        }
    
public intgetPort()
Get the port (rfcomm channel) associated with this socket. This is only valid if the port has been set via a successful call to {@link #bind(String, int)}, {@link #connect(String, int)} or {@link #connectAsync(String, int)}. This can be checked with {@link #isListening()} and {@link #isConnected()}.

return
Port (rfcomm channel)

        if (mFd == null) {
            throw new IOException("socket not created");
        }
        if (!mIsListening && !isConnected()) {
            throw new IOException("not listening or connected on socket");
        }
        return mPort;
    
public intgetRemainingAcceptWaitingTimeMs()
Returns the number of milliseconds left to wait after the last call to {@link #accept(RfcommSocket, int) accept}. Since accept() may return null (i.e., no incoming connection) before the user-specified timeout expires, you need to call this method in order to see how much time is left to wait, and wait for that amount of time before you call accept again.

return
the remaining time, in milliseconds.

        return mAcceptTimeoutRemainingMs;
    
public intgetRemainingAsyncConnectWaitingTimeMs()
Returns the number of milliseconds left to wait after the last call to {@link #waitForAsyncConnect(int) waitForAsyncConnect}. It is possible that waitForAsyncConnect() waits for less than the time specified by the user, and still returns zero (i.e., async connect is still in progress.) For this reason, if the return value is zero, you need to call this method to retrieve the remaining time before you call waitForAsyncConnect again.

return
the remaining timeout in milliseconds.
see
#waitForAsyncConnect(int)
see
#connectAsync(String, int)

        return mTimeoutRemainingMs;
    
private native voidinitializeNativeDataNative()

public voidinterruptAsyncConnect()
Interrupts an asynchronous connect in progress. This method does nothing when there is no asynchronous connect in progress.

throws
IOException if you have not called {@link #create() create}.
see
#connectAsync(String, int)

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            if (mIsConnecting) {
                mIsConnecting = !interruptAsyncConnectNative();
            }
        }
    
private native booleaninterruptAsyncConnectNative()

public booleanisConnected()
Tells you whether a socket is connected to another socket. This could be for input or output or both.

return
true if connected, false otherwise.
see
#isInputConnected()
see
#isOutputConnected()

        return isConnectedNative() > 0;
    
private native intisConnectedNative()

public booleanisConnecting()
Tells you whether there is an asynchronous connect in progress. This method returns an undefined value when there is a synchronous connect in progress.

return
true if there is an asyc connect in progress, false otherwise
see
#connectAsync(String, int)

        return mIsConnecting;
    
public booleanisInputConnected()
Determines whether input is connected (i.e., whether you can receive data on this socket.)

return
true if input is connected, false otherwise.
see
#isConnected()
see
#isOutputConnected()

        return (isConnectedNative() & 1) != 0;
    
public booleanisListening()
Return true if this socket is listening ({@link #listen(int)} has been called successfully).

        return mIsListening;
    
public booleanisOutputConnected()
Determines whether output is connected (i.e., whether you can send data on this socket.)

return
true if output is connected, false otherwise.
see
#isConnected()
see
#isInputConnected()

        return (isConnectedNative() & 2) != 0;
    
public booleanlisten(int backlog)
Starts listening for incoming connections on this socket, after it has been bound to an address and RFCOMM channel with {@link #bind(String,int) bind}.

param
backlog the number of pending incoming connections to queue for {@link #accept(RfcommSocket, int) accept}.
return
true on success, false on failure
throws
IOException if you have not called {@link #create() create} or if the socket has not been bound to a device and RFCOMM channel.

        if (mFd == null) {
            throw new IOException("socket not created");
        }
        if (!mIsBound) {
            throw new IOException("socket not bound");
        }
        mIsListening = listenNative(backlog);
        return mIsListening;
    
private native booleanlistenNative(int backlog)

public booleanshutdown()
Shuts down both directions on a socket.

return
true on success, false on failure; if the return value is false, the socket might be left in a patially shut-down state (i.e. one direction is shut down, but the other is still open.) In this case, you should {@link #destroy() destroy} and then {@link #create() create} the socket again.
throws
IOException is you have not caled {@link #create() create}.
see
#shutdownInput()
see
#shutdownOutput()

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            if (shutdownNative(true)) {
                return shutdownNative(false);
            }

            return false;
        }
    
public booleanshutdownInput()
Shuts down the input stream of the socket, but leaves the output stream in its current state.

return
true on success, false on failure
throws
IOException is you have not called {@link #create() create}
see
#shutdown()
see
#shutdownOutput()

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            return shutdownNative(true);
        }
    
private native booleanshutdownNative(boolean shutdownInput)

public booleanshutdownOutput()
Shut down the output stream of the socket, but leaves the input stream in its current state.

return
true on success, false on failure
throws
IOException is you have not called {@link #create() create}
see
#shutdown()
see
#shutdownInput()

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            return shutdownNative(false);
        }
    
public intwaitForAsyncConnect(int timeoutMs)
Blocks for a specified amount of milliseconds while waiting for an asynchronous connect to complete. Returns an integer value to indicate one of the following: the connect succeeded, the connect is still in progress, or the connect failed. It is possible for this method to block for less than the time specified by the user, and still return zero (i.e., async connect is still in progress.) For this reason, if the return value is zero, you need to call method {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs} to retrieve the remaining time.

param
timeoutMs the time to block while waiting for the async connect to complete.
return
a positive value if the connect succeeds; zero, if the connect is still in progress, and a negative value if the connect failed.
throws
IOException
see
#getRemainingAsyncConnectWaitingTimeMs()
see
#connectAsync(String, int)

        synchronized (this) {
            if (mFd == null) {
                throw new IOException("socket not created");
            }
            int ret = waitForAsyncConnectNative(timeoutMs);
            if (ret != 0) {
                mIsConnecting = false;
            }
            return ret;
        }
    
private native intwaitForAsyncConnectNative(int timeoutMs)