Fix Bluetooth GATT API default handler assignment

Restores previous behaviour where GATT callbacks are invoked on the
binder thread and not the calling process main looper thread.

This fixes performance regressions as well as some
NetworkOnMainThreadException's for some applications.

Bug: 37544152
Bug: 37871717
Test: Covered by prior API tests.
Change-Id: Id8ab705dd4d7f00030e6ac29e056dde5180670e9
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c427268..e8ad69d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1703,7 +1703,7 @@
      *             an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
      *             if {@code autoConnect} is set to true.
      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
-     *             on the service's main thread.
+     *             on an un-specified background thread.
      * @throws NullPointerException if callback is null
      */
     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
@@ -1712,9 +1712,6 @@
         if (callback == null)
             throw new NullPointerException("callback is null");
 
-        if (handler == null)
-            handler = new Handler(Looper.getMainLooper());
-
         // TODO(Bluetooth) check whether platform support BLE
         //     Do the check here or in GattServer?
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 0f01d62..5fabbb6 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -156,7 +156,7 @@
                 }
                 mClientIf = clientIf;
                 if (status != GATT_SUCCESS) {
-                    mHandler.post(new Runnable() {
+                    runOrQueueCallback(new Runnable() {
                         @Override
                         public void run() {
                             if (mCallback != null) {
@@ -191,7 +191,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -213,7 +213,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -238,7 +238,7 @@
                 int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
                                                BluetoothProfile.STATE_DISCONNECTED;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -300,7 +300,7 @@
                     }
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -352,7 +352,7 @@
 
                 if (status == 0) characteristic.setValue(value);
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -401,7 +401,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -430,7 +430,7 @@
 
                 characteristic.setValue(value);
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -477,7 +477,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -523,7 +523,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -549,7 +549,7 @@
                     mDeviceBusy = false;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -570,7 +570,7 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -592,7 +592,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -616,7 +616,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -703,6 +703,22 @@
     }
 
     /**
+     * Queue the runnable on a {@link Handler} provided by the user, or execute the runnable
+     * immediately if no Handler was provided.
+     */
+    private void runOrQueueCallback(final Runnable cb) {
+        if (mHandler == null) {
+          try {
+            cb.run();
+          } catch (Exception ex) {
+            Log.w(TAG, "Unhandled exception in callback", ex);
+          }
+        } else {
+          mHandler.post(cb);
+        }
+    }
+
+    /**
      * Register an application callback to start using GATT.
      *
      * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}