summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorVinit Deshpande <vinitd@google.com>2015-04-16 02:36:02 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-16 02:36:30 +0000
commitcb43ebb3604d45da8677b8d19c935f0ace08ea53 (patch)
treecaf1ac41223ad3999b134d49fcd62a7f6783b41b /core/java/android
parent7400df9487151a9d53d00a0cc973a0164d22aecd (diff)
parent80047faad914c9b9b4966d6b58fc22800c3fcebc (diff)
downloadframeworks_base-cb43ebb3604d45da8677b8d19c935f0ace08ea53.zip
frameworks_base-cb43ebb3604d45da8677b8d19c935f0ace08ea53.tar.gz
frameworks_base-cb43ebb3604d45da8677b8d19c935f0ace08ea53.tar.bz2
Merge "am b5e0cfb..557d2f5 from mirror-m-wireless-internal-release"
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java48
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java69
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java52
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java197
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl2
-rw-r--r--core/java/android/bluetooth/SdpMasRecord.java147
-rw-r--r--core/java/android/bluetooth/SdpMnsRecord.java112
-rw-r--r--core/java/android/bluetooth/SdpOppOpsRecord.java118
-rw-r--r--core/java/android/bluetooth/SdpPseRecord.java125
-rw-r--r--core/java/android/bluetooth/SdpRecord.java76
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java102
-rw-r--r--core/java/android/net/IConnectivityManager.aidl7
-rw-r--r--core/java/android/net/NetworkAgent.java6
14 files changed, 981 insertions, 84 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2b3cf34..87d5bb0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2009-2014 The Android Open Source Project
+ * Copyright (C) 2009-2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -374,6 +375,18 @@ public final class BluetoothAdapter {
/** @hide */
public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
+
+ /** When creating a ServerSocket using listenUsingRfcommOn() or
+ * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
+ * a ServerSocket that auto assigns a channel number to the first
+ * bluetooth socket.
+ * The channel number assigned to this first Bluetooth Socket will
+ * be stored in the ServerSocket, and reused for subsequent Bluetooth
+ * sockets.
+ * @hide */
+ public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
+
+
private static final int ADDRESS_LENGTH = 17;
private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30;
@@ -1141,6 +1154,9 @@ public final class BluetoothAdapter {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, true, true, channel);
int errno = socket.mSocket.bindListen();
+ if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
if (errno != 0) {
//TODO(BT): Throw the same exception error code
// that the previous code was using.
@@ -1275,6 +1291,9 @@ public final class BluetoothAdapter {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, false, false, port);
int errno = socket.mSocket.bindListen();
+ if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
if (errno != 0) {
//TODO(BT): Throw the same exception error code
// that the previous code was using.
@@ -1297,6 +1316,9 @@ public final class BluetoothAdapter {
BluetoothServerSocket socket = new BluetoothServerSocket(
BluetoothSocket.TYPE_RFCOMM, false, true, port);
int errno = socket.mSocket.bindListen();
+ if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
if (errno < 0) {
//TODO(BT): Throw the same exception error code
// that the previous code was using.
@@ -1327,6 +1349,30 @@ public final class BluetoothAdapter {
}
/**
+ * Construct an encrypted, authenticated, L2CAP server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return An L2CAP BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_L2CAP, true, true, port);
+ int errno = socket.mSocket.bindListen();
+ if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ socket.setChannel(socket.mSocket.getPort());
+ }
+ if (errno != 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
+ }
+ return socket;
+ }
+
+ /**
* Read the local Out of Band Pairing Data
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bb0d0a3..1fdf9f4 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -302,6 +302,12 @@ public final class BluetoothDevice implements Parcelable {
*/
public static final int DEVICE_TYPE_DUAL = 3;
+
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SDP_RECORD =
+ "android.bluetooth.device.action.SDP_RECORD";
+
/**
* Broadcast Action: This intent is used to broadcast the {@link UUID}
* wrapped as a {@link android.os.ParcelUuid} of the remote device after it
@@ -526,6 +532,13 @@ public final class BluetoothDevice implements Parcelable {
*/
public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+ /** @hide */
+ public static final String EXTRA_SDP_RECORD =
+ "android.bluetooth.device.extra.SDP_RECORD";
+
+ /** @hide */
+ public static final String EXTRA_SDP_SEARCH_STATUS =
+ "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
/**
* For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
* {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -1054,14 +1067,34 @@ public final class BluetoothDevice implements Parcelable {
return false;
}
+ /**
+ * Perform a service discovery on the remote device to get the SDP records associated
+ * with the specified UUID.
+ *
+ * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
+ * with the SDP records found on the remote end. If there is an error
+ * in getting the SDP records or if the process takes a long time,
+ * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
+ * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
+ * Detailed status error codes can be found by members of the Bluetooth package in
+ * the AbstractionLayer class.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
+ * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
+ * for.
+ *
+ * @return False if the sanity check fails, True if the process
+ * of initiating an ACL connection to the remote device
+ * was started.
+ */
/** @hide */
- public boolean fetchMasInstances() {
+ public boolean sdpSearch(ParcelUuid uuid) {
if (sService == null) {
- Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances");
+ Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
return false;
}
try {
- return sService.fetchRemoteMasInstances(this);
+ return sService.sdpSearch(this,uuid);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -1261,6 +1294,36 @@ public final class BluetoothDevice implements Parcelable {
}
/**
+ * Create an L2cap {@link BluetoothSocket} ready to start a secure
+ * outgoing connection to this remote device on given channel.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p> Use this socket only if an authenticated socket link is possible.
+ * Authentication refers to the authentication of the link key to
+ * prevent man-in-the-middle type of attacks.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not
+ * have an input and output capability or just has the ability to
+ * display a numeric key, a secure socket connection is not possible.
+ * In such a case, use {#link createInsecureRfcommSocket}.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+ * connection.
+ * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param channel L2cap PSM/channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ * @hide
+ */
+ public BluetoothSocket createL2capSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
+ null);
+ }
+
+ /**
* Create an RFCOMM {@link BluetoothSocket} ready to start a secure
* outgoing connection to this remote device using SDP lookup of uuid.
* <p>This is designed to be used with {@link
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index bc56e55..21024a6 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import android.os.Handler;
import android.os.ParcelUuid;
+import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
@@ -66,10 +67,11 @@ import java.io.IOException;
*/
public final class BluetoothServerSocket implements Closeable {
+ private static final String TAG = "BluetoothServerSocket";
/*package*/ final BluetoothSocket mSocket;
private Handler mHandler;
private int mMessage;
- private final int mChannel;
+ private int mChannel;
/**
* Construct a socket for incoming connections.
@@ -84,6 +86,9 @@ public final class BluetoothServerSocket implements Closeable {
throws IOException {
mChannel = port;
mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
+ if(port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+ mSocket.setExcludeSdp(true);
+ }
}
/**
@@ -98,6 +103,7 @@ public final class BluetoothServerSocket implements Closeable {
/*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
throws IOException {
mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
+ // TODO: This is the same as mChannel = -1 - is this intentional?
mChannel = mSocket.getPort();
}
@@ -153,6 +159,7 @@ public final class BluetoothServerSocket implements Closeable {
/*package*/ void setServiceName(String ServiceName) {
mSocket.setServiceName(ServiceName);
}
+
/**
* Returns the channel on which this socket is bound.
* @hide
@@ -160,4 +167,47 @@ public final class BluetoothServerSocket implements Closeable {
public int getChannel() {
return mChannel;
}
+
+ /**
+ * Sets the channel on which future sockets are bound.
+ * Currently used only when a channel is auto generated.
+ */
+ /*package*/ void setChannel(int newChannel) {
+ /* TODO: From a design/architecture perspective this is wrong.
+ * The bind operation should be conducted through this class
+ * and the resulting port should be kept in mChannel, and
+ * not set from BluetoothAdapter. */
+ if(mSocket != null) {
+ if(mSocket.getPort() != newChannel) {
+ Log.w(TAG,"The port set is different that the underlying port. mSocket.getPort(): "
+ + mSocket.getPort() + " requested newChannel: " + newChannel);
+ }
+ }
+ mChannel = newChannel;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("ServerSocket: Type: ");
+ switch(mSocket.getConnectionType()) {
+ case BluetoothSocket.TYPE_RFCOMM:
+ {
+ sb.append("TYPE_RFCOMM");
+ break;
+ }
+ case BluetoothSocket.TYPE_L2CAP:
+ {
+ sb.append("TYPE_L2CAP");
+ break;
+ }
+ case BluetoothSocket.TYPE_SCO:
+ {
+ sb.append("TYPE_SCO");
+ break;
+ }
+ }
+ sb.append(" Channel: ").append(mChannel);
+ return sb.toString();
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 36997e5..5702d11 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -21,6 +21,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
+import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -29,6 +30,8 @@ import java.io.OutputStream;
import java.util.Locale;
import java.util.UUID;
import android.net.LocalSocket;
+
+import java.nio.Buffer;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
/**
@@ -86,17 +89,19 @@ public final class BluetoothSocket implements Closeable {
/** @hide */
public static final int MAX_RFCOMM_CHANNEL = 30;
+ /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
/** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
- /*package*/ static final int TYPE_RFCOMM = 1;
- /*package*/ static final int TYPE_SCO = 2;
- /*package*/ static final int TYPE_L2CAP = 3;
+ public static final int TYPE_RFCOMM = 1;
+ public static final int TYPE_SCO = 2;
+ public static final int TYPE_L2CAP = 3;
/*package*/ static final int EBADFD = 77;
/*package*/ static final int EADDRINUSE = 98;
/*package*/ static final int SEC_FLAG_ENCRYPT = 1;
/*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
+ /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2;
private final int mType; /* one of TYPE_RFCOMM etc */
private BluetoothDevice mDevice; /* remote device */
@@ -106,6 +111,7 @@ public final class BluetoothSocket implements Closeable {
private final BluetoothInputStream mInputStream;
private final BluetoothOutputStream mOutputStream;
private final ParcelUuid mUuid;
+ private boolean mExcludeSdp = false;
private ParcelFileDescriptor mPfd;
private LocalSocket mSocket;
private InputStream mSocketIS;
@@ -115,7 +121,11 @@ public final class BluetoothSocket implements Closeable {
private String mServiceName;
private static int PROXY_CONNECTION_TIMEOUT = 5000;
- private static int SOCK_SIGNAL_SIZE = 16;
+ private static int SOCK_SIGNAL_SIZE = 20;
+
+ private ByteBuffer mL2capBuffer = null;
+ private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
+ private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
private enum SocketState {
INIT,
@@ -144,12 +154,14 @@ public final class BluetoothSocket implements Closeable {
*/
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
- if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
+ if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
+ if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
+ && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
throw new IOException("Invalid RFCOMM channel: " + port);
}
}
- if(uuid != null)
+ if (uuid != null)
mUuid = uuid;
else mUuid = new ParcelUuid(new UUID(0, 0));
mType = type;
@@ -172,6 +184,7 @@ public final class BluetoothSocket implements Closeable {
mOutputStream = new BluetoothOutputStream(this);
}
private BluetoothSocket(BluetoothSocket s) {
+ if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
mUuid = s.mUuid;
mType = s.mType;
mAuth = s.mAuth;
@@ -179,7 +192,11 @@ public final class BluetoothSocket implements Closeable {
mPort = s.mPort;
mInputStream = new BluetoothInputStream(this);
mOutputStream = new BluetoothOutputStream(this);
+ mMaxRxPacketSize = s.mMaxRxPacketSize;
+ mMaxTxPacketSize = s.mMaxTxPacketSize;
+
mServiceName = s.mServiceName;
+ mExcludeSdp = s.mExcludeSdp;
}
private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException {
BluetoothSocket as = new BluetoothSocket(this);
@@ -229,6 +246,8 @@ public final class BluetoothSocket implements Closeable {
flags |= SEC_FLAG_AUTH;
if(mEncrypt)
flags |= SEC_FLAG_ENCRYPT;
+ if(mExcludeSdp)
+ flags |= BTSOCK_FLAG_NO_SDP;
return flags;
}
@@ -298,7 +317,8 @@ public final class BluetoothSocket implements Closeable {
try {
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ IBluetooth bluetoothProxy =
+ BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
mPfd = bluetoothProxy.connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
@@ -370,7 +390,7 @@ public final class BluetoothSocket implements Closeable {
mSocketState = SocketState.LISTENING;
}
if (DBG) Log.d(TAG, "channel: " + channel);
- if (mPort == -1) {
+ if (mPort <= -1) {
mPort = channel;
} // else ASSERT(mPort == channel)
ret = 0;
@@ -391,7 +411,8 @@ public final class BluetoothSocket implements Closeable {
/*package*/ BluetoothSocket accept(int timeout) throws IOException {
BluetoothSocket acceptedSocket;
- if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
+ if (mSocketState != SocketState.LISTENING)
+ throw new IOException("bt socket is not in listen state");
if(timeout > 0) {
Log.d(TAG, "accept() set timeout (ms):" + timeout);
mSocket.setSoTimeout(timeout);
@@ -427,27 +448,80 @@ public final class BluetoothSocket implements Closeable {
}
/*package*/ int read(byte[] b, int offset, int length) throws IOException {
- if (mSocketIS == null) throw new IOException("read is called on null InputStream");
+ int ret = 0;
if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length);
- int ret = mSocketIS.read(b, offset, length);
- if(ret < 0)
+ if(mType == TYPE_L2CAP)
+ {
+ int bytesToRead = length;
+ if (VDBG) Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
+ + "mL2capBuffer= " + mL2capBuffer);
+ if (mL2capBuffer == null) {
+ createL2capRxBuffer();
+ }
+ if (mL2capBuffer.remaining() == 0) {
+ if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
+ if (fillL2capRxBuffer() == -1) {
+ return -1;
+ }
+ }
+ if (bytesToRead > mL2capBuffer.remaining()) {
+ bytesToRead = mL2capBuffer.remaining();
+ }
+ if(VDBG) Log.v(TAG, "get(): offset: " + offset
+ + " bytesToRead: " + bytesToRead);
+ mL2capBuffer.get(b, offset, bytesToRead);
+ ret = bytesToRead;
+ }else {
+ if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
+ ret = mSocketIS.read(b, offset, length);
+ }
+ if (ret < 0)
throw new IOException("bt socket closed, read return: " + ret);
if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
return ret;
}
/*package*/ int write(byte[] b, int offset, int length) throws IOException {
- if (mSocketOS == null) throw new IOException("write is called on null OutputStream");
- if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
- mSocketOS.write(b, offset, length);
- // There is no good way to confirm since the entire process is asynchronous anyway
- if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
- return length;
+
+ //TODO: Since bindings can exist between the SDU size and the
+ // protocol, we might need to throw an exception instead of just
+ // splitting the write into multiple smaller writes.
+ // Rfcomm uses dynamic allocation, and should not have any bindings
+ // to the actual message length.
+ if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
+ if (mType == TYPE_L2CAP) {
+ if(length <= mMaxTxPacketSize) {
+ mSocketOS.write(b, offset, length);
+ } else {
+ int tmpOffset = offset;
+ int tmpLength = mMaxTxPacketSize;
+ int endIndex = offset + length;
+ boolean done = false;
+ if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
+ + "Packet will be divided into SDU packets of size "
+ + mMaxTxPacketSize);
+ do{
+ mSocketOS.write(b, tmpOffset, tmpLength);
+ tmpOffset += mMaxTxPacketSize;
+ if((tmpOffset + mMaxTxPacketSize) > endIndex) {
+ tmpLength = endIndex - tmpOffset;
+ done = true;
+ }
+ } while(!done);
+
+ }
+ } else {
+ mSocketOS.write(b, offset, length);
+ }
+ // There is no good way to confirm since the entire process is asynchronous anyway
+ if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
+ return length;
}
@Override
public void close() throws IOException {
- if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
+ if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: "
+ + mSocketState);
if(mSocketState == SocketState.CLOSED)
return;
else
@@ -457,8 +531,9 @@ public final class BluetoothSocket implements Closeable {
if(mSocketState == SocketState.CLOSED)
return;
mSocketState = SocketState.CLOSED;
- if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
- ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
+ if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort +
+ ", mSocketIS: " + mSocketIS + ", mSocketOS: " + mSocketOS +
+ "mSocket: " + mSocket);
if(mSocket != null) {
if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
mSocket.shutdownInput();
@@ -480,6 +555,47 @@ public final class BluetoothSocket implements Closeable {
/*package */ int getPort() {
return mPort;
}
+
+ /**
+ * Get the maximum supported Transmit packet size for the underlying transport.
+ * Use this to optimize the writes done to the output socket, to avoid sending
+ * half full packets.
+ * @return the maximum supported Transmit packet size for the underlying transport.
+ */
+ public int getMaxTransmitPacketSize(){
+ return mMaxTxPacketSize;
+ }
+
+ /**
+ * Get the maximum supported Receive packet size for the underlying transport.
+ * Use this to optimize the reads done on the input stream, as any call to read
+ * will return a maximum of this amount of bytes - or for some transports a
+ * multiple of this value.
+ * @return the maximum supported Receive packet size for the underlying transport.
+ */
+ public int getMaxReceivePacketSize(){
+ return mMaxRxPacketSize;
+ }
+
+ /**
+ * Get the type of the underlying connection
+ * @return one of TYPE_
+ */
+ public int getConnectionType() {
+ return mType;
+ }
+
+ /**
+ * Change if a SDP entry should be automatically created.
+ * Must be called before calling .bind, for the call to have any effect.
+ * @param mExcludeSdp <li>TRUE - do not auto generate SDP record.
+ * <li>FALSE - default - auto generate SPP SDP record.
+ * @hide
+ */
+ public void setExcludeSdp(boolean excludeSdp) {
+ this.mExcludeSdp = excludeSdp;
+ }
+
private String convertAddr(final byte[] addr) {
return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
@@ -487,8 +603,10 @@ public final class BluetoothSocket implements Closeable {
private String waitSocketSignal(InputStream is) throws IOException {
byte [] sig = new byte[SOCK_SIGNAL_SIZE];
int ret = readAll(is, sig);
- if (VDBG) Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret);
+ if (VDBG) Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE +
+ " bytes signal ret: " + ret);
ByteBuffer bb = ByteBuffer.wrap(sig);
+ /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
bb.order(ByteOrder.nativeOrder());
int size = bb.getShort();
if(size != SOCK_SIGNAL_SIZE)
@@ -497,19 +615,36 @@ public final class BluetoothSocket implements Closeable {
bb.get(addr);
int channel = bb.getInt();
int status = bb.getInt();
+ mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
+ mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
String RemoteAddr = convertAddr(addr);
if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
- + RemoteAddr + ", channel: " + channel + ", status: " + status);
+ + RemoteAddr + ", channel: " + channel + ", status: " + status
+ + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
if(status != 0)
throw new IOException("Connection failure, status: " + status);
return RemoteAddr;
}
+
+ private void createL2capRxBuffer(){
+ if(mType == TYPE_L2CAP) {
+ // Allocate the buffer to use for reads.
+ if(VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
+ mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
+ if(VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
+ mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
+ if(VDBG) Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" +
+ mL2capBuffer.remaining());
+ }
+ }
+
private int readAll(InputStream is, byte[] b) throws IOException {
int left = b.length;
while(left > 0) {
int ret = is.read(b, b.length - left, left);
if(ret <= 0)
- throw new IOException("read failed, socket might closed or timeout, read ret: " + ret);
+ throw new IOException("read failed, socket might closed or timeout, read ret: "
+ + ret);
left -= ret;
if(left != 0)
Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
@@ -526,4 +661,18 @@ public final class BluetoothSocket implements Closeable {
bb.order(ByteOrder.nativeOrder());
return bb.getInt();
}
+
+ private int fillL2capRxBuffer() throws IOException {
+ mL2capBuffer.rewind();
+ int ret = mSocketIS.read(mL2capBuffer.array());
+ if(ret == -1) {
+ // reached end of stream - return -1
+ mL2capBuffer.limit(0);
+ return -1;
+ }
+ mL2capBuffer.limit(ret);
+ return ret;
+ }
+
+
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 299f4c8..af560df 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -68,7 +68,7 @@ interface IBluetooth
int getRemoteClass(in BluetoothDevice device);
ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
boolean fetchRemoteUuids(in BluetoothDevice device);
- boolean fetchRemoteMasInstances(in BluetoothDevice device);
+ boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
diff --git a/core/java/android/bluetooth/SdpMasRecord.java b/core/java/android/bluetooth/SdpMasRecord.java
new file mode 100644
index 0000000..fa164c0
--- /dev/null
+++ b/core/java/android/bluetooth/SdpMasRecord.java
@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpMasRecord implements Parcelable {
+ private final int mMasInstanceId;
+ private final int mL2capPsm;
+ private final int mRfcommChannelNumber;
+ private final int mProfileVersion;
+ private final int mSupportedFeatures;
+ private final int mSupportedMessageTypes;
+ private final String mServiceName;
+ public static final class MessageType {
+ public static final int EMAIL = 0x01;
+ public static final int SMS_GSM = 0x02;
+ public static final int SMS_CDMA = 0x04;
+ public static final int MMS = 0x08;
+ }
+
+ public SdpMasRecord(int mas_instance_id,
+ int l2cap_psm,
+ int rfcomm_channel_number,
+ int profile_version,
+ int supported_features,
+ int supported_message_types,
+ String service_name){
+ this.mMasInstanceId = mas_instance_id;
+ this.mL2capPsm = l2cap_psm;
+ this.mRfcommChannelNumber = rfcomm_channel_number;
+ this.mProfileVersion = profile_version;
+ this.mSupportedFeatures = supported_features;
+ this.mSupportedMessageTypes = supported_message_types;
+ this.mServiceName = service_name;
+ }
+
+ public SdpMasRecord(Parcel in){
+ this.mMasInstanceId = in.readInt();
+ this.mL2capPsm = in.readInt();
+ this.mRfcommChannelNumber = in.readInt();
+ this.mProfileVersion = in.readInt();
+ this.mSupportedFeatures = in.readInt();
+ this.mSupportedMessageTypes = in.readInt();
+ this.mServiceName = in.readString();
+ }
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getMasInstanceId() {
+ return mMasInstanceId;
+ }
+
+ public int getL2capPsm() {
+ return mL2capPsm;
+ }
+
+ public int getRfcommCannelNumber() {
+ return mRfcommChannelNumber;
+ }
+
+ public int getProfileVersion() {
+ return mProfileVersion;
+ }
+
+ public int getSupportedFeatures() {
+ return mSupportedFeatures;
+ }
+
+ public int getSupportedMessageTypes() {
+ return mSupportedMessageTypes;
+ }
+
+ public boolean msgSupported(int msg) {
+ return (mSupportedMessageTypes & msg) != 0;
+ }
+
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+
+ dest.writeInt(this.mMasInstanceId);
+ dest.writeInt(this.mL2capPsm);
+ dest.writeInt(this.mRfcommChannelNumber);
+ dest.writeInt(this.mProfileVersion);
+ dest.writeInt(this.mSupportedFeatures);
+ dest.writeInt(this.mSupportedMessageTypes);
+ dest.writeString(this.mServiceName);
+
+ }
+ @Override
+ public String toString(){
+ String ret = "Bluetooth MAS SDP Record:\n";
+
+ if(mMasInstanceId != -1){
+ ret += "Mas Instance Id: " + mMasInstanceId + "\n";
+ }
+ if(mRfcommChannelNumber != -1){
+ ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+ }
+ if(mL2capPsm != -1){
+ ret += "L2CAP PSM: " + mL2capPsm + "\n";
+ }
+ if(mServiceName != null){
+ ret += "Service Name: " + mServiceName + "\n";
+ }
+ if(mProfileVersion != -1){
+ ret += "Profile version: " + mProfileVersion + "\n";
+ }
+ if(mSupportedMessageTypes != -1){
+ ret += "Supported msg types: " + mSupportedMessageTypes + "\n";
+ }
+ if(mSupportedFeatures != -1){
+ ret += "Supported features: " + mSupportedFeatures + "\n";
+ }
+ return ret;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public SdpMasRecord createFromParcel(Parcel in) {
+ return new SdpMasRecord(in);
+ }
+ public SdpRecord[] newArray(int size) {
+ return new SdpRecord[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/SdpMnsRecord.java b/core/java/android/bluetooth/SdpMnsRecord.java
new file mode 100644
index 0000000..c02bb5a
--- /dev/null
+++ b/core/java/android/bluetooth/SdpMnsRecord.java
@@ -0,0 +1,112 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpMnsRecord implements Parcelable {
+ private final int mL2capPsm;
+ private final int mRfcommChannelNumber;
+ private final int mSupportedFeatures;
+ private final int mProfileVersion;
+ private final String mServiceName;
+
+ public SdpMnsRecord(int l2cap_psm,
+ int rfcomm_channel_number,
+ int profile_version,
+ int supported_features,
+ String service_name){
+ this.mL2capPsm = l2cap_psm;
+ this.mRfcommChannelNumber = rfcomm_channel_number;
+ this.mSupportedFeatures = supported_features;
+ this.mServiceName = service_name;
+ this.mProfileVersion = profile_version;
+ }
+
+ public SdpMnsRecord(Parcel in){
+ this.mRfcommChannelNumber = in.readInt();
+ this.mL2capPsm = in.readInt();
+ this.mServiceName = in.readString();
+ this.mSupportedFeatures = in.readInt();
+ this.mProfileVersion = in.readInt();
+ }
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public int getL2capPsm() {
+ return mL2capPsm;
+ }
+
+ public int getRfcommChannelNumber() {
+ return mRfcommChannelNumber;
+ }
+
+ public int getSupportedFeatures() {
+ return mSupportedFeatures;
+ }
+
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ public int getProfileVersion() {
+ return mProfileVersion;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRfcommChannelNumber);
+ dest.writeInt(mL2capPsm);
+ dest.writeString(mServiceName);
+ dest.writeInt(mSupportedFeatures);
+ dest.writeInt(mProfileVersion);
+ }
+
+ public String toString(){
+ String ret = "Bluetooth MNS SDP Record:\n";
+
+ if(mRfcommChannelNumber != -1){
+ ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+ }
+ if(mL2capPsm != -1){
+ ret += "L2CAP PSM: " + mL2capPsm + "\n";
+ }
+ if(mServiceName != null){
+ ret += "Service Name: " + mServiceName + "\n";
+ }
+ if(mSupportedFeatures != -1){
+ ret += "Supported features: " + mSupportedFeatures + "\n";
+ }
+ if(mProfileVersion != -1){
+ ret += "Profile_version: " + mProfileVersion+"\n";
+ }
+ return ret;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public SdpMnsRecord createFromParcel(Parcel in) {
+ return new SdpMnsRecord(in);
+ }
+ public SdpMnsRecord[] newArray(int size) {
+ return new SdpMnsRecord[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/SdpOppOpsRecord.java b/core/java/android/bluetooth/SdpOppOpsRecord.java
new file mode 100644
index 0000000..e0e4007
--- /dev/null
+++ b/core/java/android/bluetooth/SdpOppOpsRecord.java
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.bluetooth;
+
+import java.util.Arrays;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Data representation of a Object Push Profile Server side SDP record.
+ */
+/** @hide */
+public class SdpOppOpsRecord implements Parcelable {
+
+ private final String mServiceName;
+ private final int mRfcommChannel;
+ private final int mL2capPsm;
+ private final int mProfileVersion;
+ private final byte[] mFormatsList;
+
+ public SdpOppOpsRecord(String serviceName, int rfcommChannel,
+ int l2capPsm, int version, byte[] formatsList) {
+ super();
+ this.mServiceName = serviceName;
+ this.mRfcommChannel = rfcommChannel;
+ this.mL2capPsm = l2capPsm;
+ this.mProfileVersion = version;
+ this.mFormatsList = formatsList;
+ }
+
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ public int getRfcommChannel() {
+ return mRfcommChannel;
+ }
+
+ public int getL2capPsm() {
+ return mL2capPsm;
+ }
+
+ public int getProfileVersion() {
+ return mProfileVersion;
+ }
+
+ public byte[] getFormatsList() {
+ return mFormatsList;
+ }
+
+ @Override
+ public int describeContents() {
+ /* No special objects */
+ return 0;
+ }
+
+ public SdpOppOpsRecord(Parcel in){
+ this.mRfcommChannel = in.readInt();
+ this.mL2capPsm = in.readInt();
+ this.mProfileVersion = in.readInt();
+ this.mServiceName = in.readString();
+ int arrayLength = in.readInt();
+ if(arrayLength > 0) {
+ byte[] bytes = new byte[arrayLength];
+ in.readByteArray(bytes);
+ this.mFormatsList = bytes;
+ } else {
+ this.mFormatsList = null;
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRfcommChannel);
+ dest.writeInt(mL2capPsm);
+ dest.writeInt(mProfileVersion);
+ dest.writeString(mServiceName);
+ if(mFormatsList!= null && mFormatsList.length > 0) {
+ dest.writeInt(mFormatsList.length);
+ dest.writeByteArray(mFormatsList);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public String toString(){
+ StringBuilder sb = new StringBuilder("Bluetooth OPP Server SDP Record:\n");
+ sb.append(" RFCOMM Chan Number: ").append(mRfcommChannel);
+ sb.append("\n L2CAP PSM: ").append(mL2capPsm);
+ sb.append("\n Profile version: ").append(mProfileVersion);
+ sb.append("\n Service Name: ").append(mServiceName);
+ sb.append("\n Formats List: ").append(Arrays.toString(mFormatsList));
+ return sb.toString();
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public SdpOppOpsRecord createFromParcel(Parcel in) {
+ return new SdpOppOpsRecord(in);
+ }
+ public SdpOppOpsRecord[] newArray(int size) {
+ return new SdpOppOpsRecord[size];
+ }
+ };
+
+}
diff --git a/core/java/android/bluetooth/SdpPseRecord.java b/core/java/android/bluetooth/SdpPseRecord.java
new file mode 100644
index 0000000..2c159cc
--- /dev/null
+++ b/core/java/android/bluetooth/SdpPseRecord.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpPseRecord implements Parcelable {
+ private final int mL2capPsm;
+ private final int mRfcommChannelNumber;
+ private final int mProfileVersion;
+ private final int mSupportedFeatures;
+ private final int mSupportedRepositories;
+ private final String mServiceName;
+
+ public SdpPseRecord(int l2cap_psm,
+ int rfcomm_channel_number,
+ int profile_version,
+ int supported_features,
+ int supported_repositories,
+ String service_name){
+ this.mL2capPsm = l2cap_psm;
+ this.mRfcommChannelNumber = rfcomm_channel_number;
+ this.mProfileVersion = profile_version;
+ this.mSupportedFeatures = supported_features;
+ this.mSupportedRepositories = supported_repositories;
+ this.mServiceName = service_name;
+ }
+
+ public SdpPseRecord(Parcel in){
+ this.mRfcommChannelNumber = in.readInt();
+ this.mL2capPsm = in.readInt();
+ this.mProfileVersion = in.readInt();
+ this.mSupportedFeatures = in.readInt();
+ this.mSupportedRepositories = in.readInt();
+ this.mServiceName = in.readString();
+ }
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getL2capPsm() {
+ return mL2capPsm;
+ }
+
+ public int getRfcommChannelNumber() {
+ return mRfcommChannelNumber;
+ }
+
+ public int getSupportedFeatures() {
+ return mSupportedFeatures;
+ }
+
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ public int getProfileVersion() {
+ return mProfileVersion;
+ }
+
+ public int getSupportedRepositories() {
+ return mSupportedRepositories;
+ }
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRfcommChannelNumber);
+ dest.writeInt(mL2capPsm);
+ dest.writeInt(mProfileVersion);
+ dest.writeInt(mSupportedFeatures);
+ dest.writeInt(mSupportedRepositories);
+ dest.writeString(mServiceName);
+
+ }
+
+ public String toString(){
+ String ret = "Bluetooth MNS SDP Record:\n";
+
+ if(mRfcommChannelNumber != -1){
+ ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+ }
+ if(mL2capPsm != -1){
+ ret += "L2CAP PSM: " + mL2capPsm + "\n";
+ }
+ if(mProfileVersion != -1){
+ ret += "profile version: " + mProfileVersion + "\n";
+ }
+ if(mServiceName != null){
+ ret += "Service Name: " + mServiceName + "\n";
+ }
+ if(mSupportedFeatures != -1){
+ ret += "Supported features: " + mSupportedFeatures + "\n";
+ }
+ if(mSupportedRepositories != -1){
+ ret += "Supported repositories: " + mSupportedRepositories + "\n";
+ }
+
+ return ret;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public SdpPseRecord createFromParcel(Parcel in) {
+ return new SdpPseRecord(in);
+ }
+ public SdpPseRecord[] newArray(int size) {
+ return new SdpPseRecord[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/SdpRecord.java b/core/java/android/bluetooth/SdpRecord.java
new file mode 100644
index 0000000..6f1065e
--- /dev/null
+++ b/core/java/android/bluetooth/SdpRecord.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/** @hide */
+public class SdpRecord implements Parcelable{
+
+ private final byte[] mRawData;
+ private final int mRawSize;
+
+ @Override
+ public String toString() {
+ return "BluetoothSdpRecord [rawData=" + Arrays.toString(mRawData)
+ + ", rawSize=" + mRawSize + "]";
+ }
+
+ public SdpRecord(int size_record, byte[] record){
+ this.mRawData = record;
+ this.mRawSize = size_record;
+ }
+
+ public SdpRecord(Parcel in){
+ this.mRawSize = in.readInt();
+ this.mRawData = new byte[mRawSize];
+ in.readByteArray(this.mRawData);
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this.mRawSize);
+ dest.writeByteArray(this.mRawData);
+
+
+ }
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public SdpRecord createFromParcel(Parcel in) {
+ return new SdpRecord(in);
+ }
+
+ public SdpRecord[] newArray(int size) {
+ return new SdpRecord[size];
+ }
+ };
+
+ public byte[] getRawData() {
+ return mRawData;
+ }
+
+ public int getRawSize() {
+ return mRawSize;
+ }
+}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index b6bcfb8..3078951 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -409,8 +409,8 @@ public final class BluetoothLeScanner {
List <ScanFilter> filterList) {
final int callbackType = settings.getCallbackType();
// If onlost/onfound is requested, a non-empty filter is expected
- if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH
- | ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
+ if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH
+ | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) {
if (filterList == null) {
return false;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 55e39b1..ce1b01e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -611,6 +611,27 @@ public class ConnectivityManager {
}
/**
+ * Returns a {@link Network} object corresponding to the currently active
+ * default data network. In the event that the current active default data
+ * network disconnects, the returned {@code Network} object will no longer
+ * be usable. This will return {@code null} when there is no default
+ * network.
+ *
+ * @return a {@link Network} object for the current default network or
+ * {@code null} if no default network is currently active
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ */
+ public Network getActiveNetwork() {
+ try {
+ return mService.getActiveNetwork();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns details about the currently active default data network
* for a given uid. This is for internal use only to avoid spying
* other apps.
@@ -831,48 +852,6 @@ public class ConnectivityManager {
}
/**
- * Tells each network type to set its radio power state as directed.
- *
- * @param turnOn a boolean, {@code true} to turn the radios on,
- * {@code false} to turn them off.
- * @return a boolean, {@code true} indicating success. All network types
- * will be tried, even if some fail.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
- * {@hide}
- */
-// TODO - check for any callers and remove
-// public boolean setRadios(boolean turnOn) {
-// try {
-// return mService.setRadios(turnOn);
-// } catch (RemoteException e) {
-// return false;
-// }
-// }
-
- /**
- * Tells a given networkType to set its radio power state as directed.
- *
- * @param networkType the int networkType of interest.
- * @param turnOn a boolean, {@code true} to turn the radio on,
- * {@code} false to turn it off.
- * @return a boolean, {@code true} indicating success.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
- * {@hide}
- */
-// TODO - check for any callers and remove
-// public boolean setRadio(int networkType, boolean turnOn) {
-// try {
-// return mService.setRadio(networkType, turnOn);
-// } catch (RemoteException e) {
-// return false;
-// }
-// }
-
- /**
* Tells the underlying networking system that the caller wants to
* begin using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
@@ -1738,10 +1717,33 @@ public class ConnectivityManager {
*
* @param network The {@link Network} the application was attempting to use
* or {@code null} to indicate the current default network.
+ * @deprecated Use {@link #reportNetworkConnectivity} which allows reporting both
+ * working and non-working connectivity.
*/
public void reportBadNetwork(Network network) {
try {
- mService.reportBadNetwork(network);
+ // One of these will be ignored because it matches system's current state.
+ // The other will trigger the necessary reevaluation.
+ mService.reportNetworkConnectivity(network, true);
+ mService.reportNetworkConnectivity(network, false);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Report to the framework whether a network has working connectivity.
+ * This provides a hint to the system that a particular network is providing
+ * working connectivity or not. In response the framework may re-evaluate
+ * the network's connectivity and might take further action thereafter.
+ *
+ * @param network The {@link Network} the application was attempting to use
+ * or {@code null} to indicate the current default network.
+ * @param hasConnectivity {@code true} if the application was able to successfully access the
+ * Internet using {@code network} or {@code false} if not.
+ */
+ public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ try {
+ mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
}
}
@@ -1978,12 +1980,18 @@ public class ConnectivityManager {
} catch (RemoteException e) { }
}
- /** {@hide} */
- public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ /**
+ * @hide
+ * Register a NetworkAgent with ConnectivityService.
+ * @return NetID corresponding to NetworkAgent.
+ */
+ public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
try {
- mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
- } catch (RemoteException e) { }
+ return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
+ } catch (RemoteException e) {
+ return NETID_UNSET;
+ }
}
/**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1aa9c45..055f1ab 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -43,6 +43,7 @@ import com.android.internal.net.VpnProfile;
/** {@hide} */
interface IConnectivityManager
{
+ Network getActiveNetwork();
NetworkInfo getActiveNetworkInfo();
NetworkInfo getActiveNetworkInfoForUid(int uid);
NetworkInfo getNetworkInfo(int networkType);
@@ -95,7 +96,7 @@ interface IConnectivityManager
void reportInetCondition(int networkType, int percentage);
- void reportBadNetwork(in Network network);
+ void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
ProxyInfo getGlobalProxy();
@@ -121,8 +122,6 @@ interface IConnectivityManager
void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal);
- int findConnectionTypeForIface(in String iface);
-
int checkMobileProvisioning(int suggestedTimeOutMs);
String getMobileProvisioningUrl();
@@ -137,7 +136,7 @@ interface IConnectivityManager
void unregisterNetworkFactory(in Messenger messenger);
- void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+ int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
in NetworkCapabilities nc, int score, in NetworkMisc misc);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 95ceb2a..3f2dd28 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -39,6 +39,10 @@ import java.util.ArrayList;
* @hide
*/
public abstract class NetworkAgent extends Handler {
+ // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown
+ // an exception.
+ public final int netId;
+
private volatile AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private static final boolean DBG = true;
@@ -151,7 +155,7 @@ public abstract class NetworkAgent extends Handler {
if (VDBG) log("Registering NetworkAgent");
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
+ netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}