Cleanup references when turning BT off.

Bug: 5572649
Change-Id: I62f9e0620832b69995d5c6e1c24634c9a3895a4b
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 96f3290..7300107 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -129,6 +129,10 @@
         }
     }
 
+    /*package*/ void close() {
+        mServiceListener = null;
+    }
+
     /**
      * Initiate connection to a profile of the remote bluetooth device.
      *
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d971652..5f5ba50 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1180,11 +1180,29 @@
      * @param proxy Profile proxy object
      */
     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
-        if (profile == BluetoothProfile.HEADSET) {
-            BluetoothHeadset headset = (BluetoothHeadset)proxy;
-            if (headset != null) {
+        if (proxy == null) return;
+
+        switch (profile) {
+            case BluetoothProfile.HEADSET:
+                BluetoothHeadset headset = (BluetoothHeadset)proxy;
                 headset.close();
-            }
+                break;
+            case BluetoothProfile.A2DP:
+                BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
+                a2dp.close();
+                break;
+            case BluetoothProfile.INPUT_DEVICE:
+                BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
+                iDev.close();
+                break;
+            case BluetoothProfile.PAN:
+                BluetoothPan pan = (BluetoothPan)proxy;
+                pan.close();
+                break;
+            case BluetoothProfile.HEALTH:
+                BluetoothHealth health = (BluetoothHealth)proxy;
+                health.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index b1d0070..c9603bf 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -109,6 +109,8 @@
     private BluetoothA2dpService mA2dpService;
     private BluetoothHeadset  mHeadsetService;
     private BluetoothPbap     mPbapService;
+    private PbapServiceListener mPbap;
+    private BluetoothAdapter mAdapter;
     private boolean mPbapServiceConnected;
     private boolean mAutoConnectionPending;
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -249,11 +251,11 @@
 
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mAdapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                 BluetoothProfile.HEADSET);
         // TODO(): Convert PBAP to the new Profile APIs.
-        PbapServiceListener p = new PbapServiceListener();
+        mPbap = new PbapServiceListener();
 
         mIncomingConnections = mService.getIncomingState(address);
         mIncomingRejectTimer = readTimerValue();
@@ -414,6 +416,26 @@
                 case TRANSITION_TO_STABLE:
                     // ignore.
                     break;
+                case SM_QUIT_CMD:
+                    mContext.unregisterReceiver(mBroadcastReceiver);
+                    mBroadcastReceiver = null;
+                    mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService);
+                    mBluetoothProfileServiceListener = null;
+                    mOutgoingHandsfree = null;
+                    mPbap = null;
+                    mPbapService.close();
+                    mPbapService = null;
+                    mIncomingHid = null;
+                    mOutgoingHid = null;
+                    mIncomingHandsfree = null;
+                    mOutgoingHandsfree = null;
+                    mIncomingA2dp = null;
+                    mOutgoingA2dp = null;
+                    mBondedDevice = null;
+                    // There is a problem in the State Machine code
+                    // where things are not cleaned up properly, when quit message
+                    // is handled so return NOT_HANDLED as a workaround.
+                    return NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 8f2b3d8..2bbf008 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -245,6 +245,7 @@
             mContext.unbindService(mConnection);
             mConnection = null;
         }
+        mServiceListener = null;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 9b2b8ca..f850c02 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -452,6 +452,10 @@
         }
     }
 
+    /*package*/ void close() {
+        mServiceListener = null;
+    }
+
     private boolean isEnabled() {
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
 
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 282b70a..1a9e011 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -118,6 +118,10 @@
         }
     }
 
+    /*package*/ void close() {
+        mServiceListener = null;
+    }
+
     /**
      * Initiate connection to a profile of the remote bluetooth device.
      *
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 7490f9e..5d9d8be 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -139,6 +139,10 @@
         }
     }
 
+    /*package*/ void close() {
+        mServiceListener = null;
+    }
+
     /**
      * Initiate connection to a profile of the remote bluetooth device.
      *
@@ -299,4 +303,4 @@
     private static void log(String msg) {
       Log.d(TAG, msg);
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 4be077c..2683bef 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -69,7 +69,7 @@
 
     private IBluetoothPbap mService;
     private final Context mContext;
-    private final ServiceListener mServiceListener;
+    private ServiceListener mServiceListener;
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
@@ -138,6 +138,7 @@
             mContext.unbindService(mConnection);
             mConnection = null;
         }
+        mServiceListener = null;
     }
 
     /**
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 28e231e..a7d8cac 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -2374,16 +2374,18 @@
     }
 
     BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) {
-        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
-        if (state != null) return state;
-
-        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
+        BluetoothDeviceProfileState state =
+            new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
         mDeviceProfileState.put(address, state);
         state.start();
         return state;
     }
 
     void removeProfileState(String address) {
+        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
+        if (state == null) return;
+
+        state.quit();
         mDeviceProfileState.remove(address);
     }