LE: Add notification sent and congestion callbacks (3/4)

This change introduces two new callbacks for applications to better
handle LE notification flow control and transport congestion. The
notification callback is invoked when the remote platform confirms an
indication or when a local notification has been passed to the
controller. No new notifications should be sent until a callback is
received.

Congestion callbacks are triggered when a GATT operation cannot be sent
to the local Bluetooth controller. Repeatedly calling
writeCharacteristic() for example will eventually trigger a congestion
callback. Applications cannot send additional data until a further
callback is received, indicating that the congestion has cleared up.

Also made server callbacks "oneway" in the AIDL definition file.

Change-Id: I7fa3324712205c79efce58e5e3df8b80a265a442
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ba42f51b..2287246 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2079,12 +2079,15 @@
         public void onMultiAdvertiseCallback(int status) {
             // no op
         }
-        /**
-         * Callback reporting LE ATT MTU.
-         * @hide
-         */
+
+        @Override
         public void onConfigureMTU(String address, int mtu, int status) {
             // no op
         }
+
+        @Override
+        public void onConnectionCongested(String address, boolean congested) {
+            // no op
+        }
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 7b5bfbd..c63de62 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -85,6 +85,9 @@
     /** A write operation exceeds the maximum length of the attribute */
     public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd;
 
+    /** A remote device connection is congested. */
+    public static final int GATT_CONNECTION_CONGESTED = 0x8f;
+
     /** A GATT operation failed, errors other than the above */
     public static final int GATT_FAILURE = 0x101;
 
@@ -607,6 +610,21 @@
                     Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
+
+            /**
+             * Callback indicating the remote device connection is congested.
+             * @hide
+             */
+            public void onConnectionCongested(String address, boolean congested) {
+                if (DBG) Log.d(TAG, "onConnectionCongested() - Device=" + address
+                        + " congested=" + congested);
+                if (!address.equals(mDevice.getAddress())) return;
+                try {
+                    mCallback.onConnectionCongested(BluetoothGatt.this, congested);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception in callback", ex);
+                }
+            }
         };
 
     /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 5180259..b5e60f2 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -153,4 +153,19 @@
      */
     public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
     }
+
+    /**
+     * Callback indicating that a remote device connection congestestion status has changed.
+     *
+     * An application should refrain from sending additional data to a remote device when
+     * a callback is received with the congested flag set to true. Once the congestion status
+     * is cleared up, the application will receive an additional callback with the congested
+     * flag set to false.
+     *
+     * @param gatt The GATT client associated with the remote device
+     * @param congested true, if the connection is currently congested
+     * @hide
+     */
+    public void onConnectionCongested(BluetoothGatt gatt, boolean congested) {
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 34e8605..2e993c9d 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -265,6 +265,42 @@
                     Log.w(TAG, "Unhandled exception in callback", ex);
                 }
             }
+
+            /**
+             * A notification/indication has been sent.
+             * @hide
+             */
+            public void onNotificationSent(String address, int status) {
+                if (DBG) Log.d(TAG, "onNotificationSent() - "
+                    + "device=" + address + ", status=" + status);
+
+                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (device == null) return;
+
+                try {
+                    mCallback.onNotificationSent(device, status);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception: " + ex);
+                }
+            }
+
+            /**
+             * Callback indicating the remote device connection is congested.
+             * @hide
+             */
+            public void onConnectionCongested(String address, boolean congested) {
+                if (DBG) Log.d(TAG, "onConnectionCongested() - Device=" + address
+                        + " congested=" + congested);
+
+                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (device == null) return;
+
+                try {
+                    mCallback.onConnectionCongested(device, congested);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception in callback", ex);
+                }
+            }
         };
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index fc3ffe8..4fbeb46 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -131,4 +131,34 @@
      */
     public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
     }
+
+    /**
+     * Callback invoked when a notification or indication has been sent to
+     * a remote device.
+     *
+     * <p>When multiple notifications are to be sent, an application must
+     * wait for this callback to be received before sending additional
+     * notifications.
+     *
+     * @param device The remote device the notification has been sent to
+     * @param status 0 if the operation was successful
+     * @hide
+     */
+    public void onNotificationSent(BluetoothDevice device, int status) {
+    }
+
+    /**
+     * Callback indicating that a remote device connection congestestion status has changed.
+     *
+     * An application should refrain from sending additional data (notifications, indications
+     * etc.) to a remote device when a callback is received with the congested flag set
+     * to true. Once the congestion status is cleared up, the application will receive an
+     * additional callback with the congested flag set to false.
+     *
+     * @param device The remote device that triggered the congestion state change
+     * @param congested true, if the connection is currently congested
+     * @hide
+     */
+    public void onConnectionCongested(BluetoothDevice device, boolean congested) {
+    }
 }
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 2d8eed4..946a6f6 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -66,4 +66,5 @@
     void onAdvertiseStateChange(in int advertiseState, in int status);
     void onMultiAdvertiseCallback(in int status);
     void onConfigureMTU(in String address, in int mtu, in int status);
+    void onConnectionCongested(in String address, in boolean congested);
 }
diff --git a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl
index ae9bffc..6e31da1 100644
--- a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl
@@ -22,7 +22,7 @@
  * Callback definitions for interacting with BLE / GATT
  * @hide
  */
-interface IBluetoothGattServerCallback {
+oneway interface IBluetoothGattServerCallback {
     void onServerRegistered(in int status, in int serverIf);
     void onScanResult(in String address, in int rssi, in byte[] advData);
     void onServerConnectionState(in int status, in int serverIf,
@@ -58,4 +58,6 @@
                                      in ParcelUuid descrId,
                                      in byte[] value);
     void onExecuteWrite(in String address, in int transId, in boolean execWrite);
+    void onNotificationSent(in String address, in int status);
+    void onConnectionCongested(in String address, in boolean congested);
 }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index ed43407..c20b81b 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -355,6 +355,11 @@
         public void onConfigureMTU(String address, int mtu, int status) {
             // no op
         }
+
+        @Override
+        public void onConnectionCongested(String address, boolean congested) {
+            // no op
+        }
     }
 
     private void postCallbackFailure(final AdvertiseCallback callback, final int error) {
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 4c6346c..fbaf5d2 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -358,6 +358,11 @@
         public void onConfigureMTU(String address, int mtu, int status) {
             // no op
         }
+
+        @Override
+        public void onConnectionCongested(String address, boolean congested) {
+            // no op
+        }
     }
 
     private void postCallbackError(final ScanCallback callback, final int errorCode) {