Check for BR/EDR transport when receiving ACL DISCONNECTED events

The ACTION_ACL_DISCONNECTED broadcast began sending events for both the
BR/EDR and LE transports, but consuming code was not utilizing the
transport when using it to decide if a profile's link was torn down or
not. This was causing the BR/EDR based map and pbap profiles to get torn
down when LE disconnections were happening.

Tag: #stability
Bug: 285326205
Test: atest BluetoothInstrumentationTests
(cherry picked from https://android-review.googlesource.com/q/commit:ce420b04203f03861d6d224b4ada5537730f63b3)
Merged-In: I186040b763cfea43e807f53b87fdbb4bff500d26
Change-Id: I186040b763cfea43e807f53b87fdbb4bff500d26
diff --git a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
index c99d79e..ab2d565 100644
--- a/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
+++ b/android/app/src/com/android/bluetooth/mapclient/MapClientService.java
@@ -743,16 +743,23 @@
                 Log.e(TAG, "broadcast has NO device param!");
                 return;
             }
-            if (DBG) {
-                Log.d(TAG, "broadcast has device: (" + device.getAddress() + ")");
-            }
+
             MceStateMachine stateMachine = mMapInstanceMap.get(device);
             if (stateMachine == null) {
-                Log.e(TAG, "No Statemachine found for the device from broadcast");
+                Log.e(TAG, "No Statemachine found for the device=" + device.toString());
                 return;
             }
 
             if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+                int transport =
+                        intent.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.ERROR);
+                Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
+                        + ", transport=" + transport);
+
+                if (transport != BluetoothDevice.TRANSPORT_BREDR) {
+                    return;
+                }
+
                 if (stateMachine.getState() == BluetoothProfile.STATE_CONNECTED) {
                     stateMachine.disconnect();
                 }
@@ -761,7 +768,8 @@
             if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
                 ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
                 if (DBG) {
-                    Log.d(TAG, "UUID of SDP: " + uuid);
+                    Log.d(TAG, "Received SDP Record event, device=" + device.toString() + ", uuid="
+                            + uuid);
                 }
 
                 if (uuid.equals(BluetoothUuid.MAS)) {
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
index 8845b86..50040dd 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
@@ -293,6 +293,16 @@
             if (DBG) Log.v(TAG, "onReceive" + action);
             if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                int transport =
+                        intent.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.ERROR);
+
+                Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
+                        + ", transport=" + transport);
+
+                if (transport != BluetoothDevice.TRANSPORT_BREDR) {
+                    return;
+                }
+
                 if (getConnectionState(device) == BluetoothProfile.STATE_CONNECTED) {
                     disconnect(device);
                 }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceTest.java
index 060379d..9ec13b9 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientServiceTest.java
@@ -26,12 +26,10 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.content.Intent;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
 import androidx.test.rule.ServiceTestRule;
 import androidx.test.runner.AndroidJUnit4;
@@ -42,7 +40,6 @@
 import com.android.bluetooth.btservice.storage.DatabaseManager;
 
 import org.junit.After;
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -278,7 +275,8 @@
     }
 
     @Test
-    public void broadcastReceiver_withActionAclDisconnected_whenConnected_callsDisconnect() {
+    public void
+            broadcastReceiver_withActionAclDisconnectedNoTransport_whenConnected_doesNotCallDisconnect() {
         int connectionState = BluetoothProfile.STATE_CONNECTED;
         MceStateMachine sm = mock(MceStateMachine.class);
         mService.getInstanceMap().put(mRemoteDevice, sm);
@@ -288,6 +286,38 @@
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
         mService.mMapReceiver.onReceive(mService, intent);
 
+        verify(sm, never()).disconnect();
+    }
+
+    @Test
+    public void
+            broadcastReceiver_withActionAclDisconnectedLeTransport_whenConnected_doesNotCallDisconnect() {
+        int connectionState = BluetoothProfile.STATE_CONNECTED;
+        MceStateMachine sm = mock(MceStateMachine.class);
+        mService.getInstanceMap().put(mRemoteDevice, sm);
+        when(sm.getState()).thenReturn(connectionState);
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+        intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE);
+        mService.mMapReceiver.onReceive(mService, intent);
+
+        verify(sm, never()).disconnect();
+    }
+
+    @Test
+    public void
+            broadcastReceiver_withActionAclDisconnectedBrEdrTransport_whenConnected_callsDisconnect() {
+        int connectionState = BluetoothProfile.STATE_CONNECTED;
+        MceStateMachine sm = mock(MceStateMachine.class);
+        mService.getInstanceMap().put(mRemoteDevice, sm);
+        when(sm.getState()).thenReturn(connectionState);
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+        intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_BREDR);
+        mService.mMapReceiver.onReceive(mService, intent);
+
         verify(sm).disconnect();
     }
 
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
index d01436d..7603c33 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -48,7 +49,6 @@
 
 import org.junit.After;
 import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Rule;
@@ -311,7 +311,7 @@
     }
 
     @Test
-    public void broadcastReceiver_withActionAclDisconnected_callsDisconnect() {
+    public void broadcastReceiver_withActionAclDisconnectedNoTransport_doesNotCallDisconnect() {
         int connectionState = BluetoothProfile.STATE_CONNECTED;
         PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
         mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
@@ -321,6 +321,36 @@
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
         mService.mPbapBroadcastReceiver.onReceive(mService, intent);
 
+        verify(sm, never()).disconnect(mRemoteDevice);
+    }
+
+    @Test
+    public void broadcastReceiver_withActionAclDisconnectedLeTransport_doesNotCallDisconnect() {
+        int connectionState = BluetoothProfile.STATE_CONNECTED;
+        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+        intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE);
+        mService.mPbapBroadcastReceiver.onReceive(mService, intent);
+
+        verify(sm, never()).disconnect(mRemoteDevice);
+    }
+
+    @Test
+    public void broadcastReceiver_withActionAclDisconnectedBrEdrTransport_callsDisconnect() {
+        int connectionState = BluetoothProfile.STATE_CONNECTED;
+        PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+        mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+        when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+        intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_BREDR);
+        mService.mPbapBroadcastReceiver.onReceive(mService, intent);
+
         verify(sm).disconnect(mRemoteDevice);
     }