Merge "TWS_A2DP: Avoid active device switch during unpairing the earbuds" into q-keystone-qcom-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 521b00c..fd23784 100755
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -628,28 +628,18 @@
         }
 
         // Check priority and accept or reject the connection.
-        // Note: Logic can be simplified, but keeping it this way for readability
         int priority = getPriority(device);
-        int bondState = BluetoothDevice.BOND_NONE;
-        synchronized (mVariableLock) {
-            if (mAdapterService != null)
-                bondState = mAdapterService.getBondState(device);
-        }
-        // If priority is undefined, it is likely that service discovery has not completed and peer
-        // initiated the connection. Allow this connection only if the device is bonded or bonding
-        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
-                && (bondState == BluetoothDevice.BOND_BONDING
-                || bondState == BluetoothDevice.BOND_BONDED);
-        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
-        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
-                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
-                && (bondState == BluetoothDevice.BOND_BONDED
-                || bondState == BluetoothDevice.BOND_BONDING);
-        if (!serviceDiscoveryPending && !isEnabled) {
-            // Otherwise, reject the connection if no service discovery is pending and priority is
-            // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
-            Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState="
-                    + bondState);
+        int bondState = mAdapterService.getBondState(device);
+        // Allow this connection only if the device is bonded. Any attempt to connect while
+        // bonding would potentially lead to an unauthorized connection.
+        if (bondState != BluetoothDevice.BOND_BONDED) {
+            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
+            return false;
+        } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
+                && priority != BluetoothProfile.PRIORITY_ON
+                && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+            // Otherwise, reject the connection if priority is not valid.
+            Log.w(TAG, "okToConnect: return false, priority=" + priority);
             return false;
         }
         return true;
diff --git a/src/com/android/bluetooth/a2dpsink/A2dpSinkStateMachine.java b/src/com/android/bluetooth/a2dpsink/A2dpSinkStateMachine.java
old mode 100644
new mode 100755
index 2bfbb2b..7ea611a
--- a/src/com/android/bluetooth/a2dpsink/A2dpSinkStateMachine.java
+++ b/src/com/android/bluetooth/a2dpsink/A2dpSinkStateMachine.java
@@ -15,12 +15,14 @@
  */
 package com.android.bluetooth.a2dpsink;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothA2dpSink;
 import android.bluetooth.BluetoothAudioConfig;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Intent;
 import android.media.AudioFormat;
+import android.media.AudioSystem;
 import android.os.Message;
 import android.util.Log;
 
@@ -43,6 +45,7 @@
     //100->199 Internal Events
     protected static final int CLEANUP = 100;
     private static final int CONNECT_TIMEOUT = 101;
+    private static final String BT_ADDR_KEY = "bt_addr";
 
     //200->299 Events from Native
     static final int STACK_EVENT = 200;
@@ -56,6 +59,7 @@
     protected final Connecting mConnecting;
     protected final Connected mConnected;
     protected final Disconnecting mDisconnecting;
+    private BluetoothAdapter mAdapter;
 
     protected int mMostRecentState = BluetoothProfile.STATE_DISCONNECTED;
     protected BluetoothAudioConfig mAudioConfig = null;
@@ -71,12 +75,19 @@
         mConnecting = new Connecting();
         mConnected = new Connected();
         mDisconnecting = new Disconnecting();
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
 
         addState(mDisconnected);
         addState(mConnecting);
         addState(mConnected);
         addState(mDisconnecting);
 
+        if (mAdapter != null) {
+            String bdAddr = mAdapter.getAddress();
+            AudioSystem.setParameters(BT_ADDR_KEY + "=" + bdAddr);
+            Log.e(TAG, "AudioSystem.setParameters, Key: " + BT_ADDR_KEY + " Value: " + bdAddr);
+        }
+
         setInitialState(mDisconnected);
     }
 
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index ec85592..e0317f6 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -117,6 +117,7 @@
     boolean mRemoteControlConnected = false;
     boolean mBrowsingConnected = false;
     final BrowseTree mBrowseTree;
+    private boolean smActive = false;
     private AvrcpPlayer mAddressedPlayer = new AvrcpPlayer();
     private RemoteDevice mRemoteDevice;
     private int mPreviousPercentageVol = -1;
@@ -151,6 +152,7 @@
         addState(mConnected);
         addState(mDisconnecting);
 
+        smActive = true;
         mGetFolderList = new GetFolderList();
         addState(mGetFolderList, mConnected);
 
@@ -228,7 +230,7 @@
     }
 
     synchronized void onBrowsingConnected() {
-        if (mBrowsingConnected) return;
+        if (mBrowsingConnected || (!smActive)) return;
         mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
         BluetoothMediaBrowserService.notifyChanged(mService
                 .sBrowseTree.mRootNode);
@@ -237,7 +239,7 @@
     }
 
     synchronized void onBrowsingDisconnected() {
-        if (!mBrowsingConnected) return;
+        if (!mBrowsingConnected || (!smActive)) return;
         mAddressedPlayer.setPlayStatus(PlaybackState.STATE_ERROR);
         mAddressedPlayer.updateCurrentTrack(null);
         if (mBrowseTree != null && mBrowseTree.mNowPlayingNode != null) {
@@ -799,6 +801,9 @@
             // If the receiver was never registered unregister will throw an
             // IllegalArgumentException.
         }
+        synchronized(AvrcpControllerStateMachine.this) {
+            smActive = false;
+        }
         // we should disacrd, all currently queuedup messages.
         quitNow();
     }
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index beff7c8..b9e52e5 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -44,6 +44,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.StatsLog;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.bluetooth.Utils;
 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
@@ -768,6 +769,7 @@
 
     // This function shall be invoked from BondStateMachine whenever the bond
     // state changes.
+    @VisibleForTesting
     void onBondStateChanged(BluetoothDevice device, int state) {
         if (device == null) {
             Log.w(TAG, "onBondStateChanged, device is null");
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index abe9d66..ca54b91 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -2441,6 +2441,18 @@
         }
     }
 
+    /**
+     * Update device UUID changed to {@link BondStateMachine}
+     *
+     * @param device remote device of interest
+     */
+    public void deviceUuidUpdated(BluetoothDevice device) {
+        // Notify BondStateMachine for SDP complete / UUID changed.
+        Message msg = mBondStateMachine.obtainMessage(BondStateMachine.UUID_UPDATE);
+        msg.obj = device;
+        mBondStateMachine.sendMessage(msg);
+    }
+
     boolean cancelBondProcess(BluetoothDevice device) {
         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
         byte[] addr = Utils.getBytesFromAddress(device.getAddress());
@@ -2703,6 +2715,8 @@
     }
 
     boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
+        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+                "Need BLUETOOTH PRIVILEGED permission");
         SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
                 Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = pref.edit();
diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java
index 5985328..4ba610c 100644
--- a/src/com/android/bluetooth/btservice/BondStateMachine.java
+++ b/src/com/android/bluetooth/btservice/BondStateMachine.java
@@ -39,6 +39,7 @@
 import com.android.bluetooth.hfpclient.HeadsetClientService;
 import com.android.bluetooth.hid.HidHostService;
 import com.android.bluetooth.pbapclient.PbapClientService;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
@@ -65,6 +66,7 @@
     static final int BONDING_STATE_CHANGE = 4;
     static final int SSP_REQUEST = 5;
     static final int PIN_REQUEST = 6;
+    static final int UUID_UPDATE = 10;
     static final int BOND_STATE_NONE = 0;
     static final int BOND_STATE_BONDING = 1;
     static final int BOND_STATE_BONDED = 2;
@@ -83,6 +85,8 @@
 
     public static final String OOBDATA = "oobdata";
 
+    @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>();
+
     private final ArrayList<BluetoothDevice> mDevices =
         new ArrayList<BluetoothDevice>();
 
@@ -167,7 +171,11 @@
                                 + state2str(newState));
                     }
                     break;
-
+                case UUID_UPDATE:
+                    if (mPendingBondedDevices.contains(dev)) {
+                        sendIntent(dev, BluetoothDevice.BOND_BONDED, 0);
+                    }
+                    break;
                 case CANCEL_BOND:
                 default:
                     Log.e(TAG, "Received unhandled state: " + msg.what);
@@ -394,15 +402,35 @@
         mWakeLock.release();
     }
 
-    private void sendIntent(BluetoothDevice device, int newState, int reason) {
+    @VisibleForTesting
+    void sendIntent(BluetoothDevice device, int newState, int reason) {
         DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device);
         int oldState = BluetoothDevice.BOND_NONE;
+        if (newState != BluetoothDevice.BOND_NONE
+                && newState != BluetoothDevice.BOND_BONDING
+                && newState != BluetoothDevice.BOND_BONDED) {
+            infoLog("Invalid bond state " + newState);
+            return;
+        }
         if (devProp != null) {
             oldState = devProp.getBondState();
         }
+        if (mPendingBondedDevices.contains(device)) {
+            mPendingBondedDevices.remove(device);
+            if (oldState == BluetoothDevice.BOND_BONDED) {
+                if (newState == BluetoothDevice.BOND_BONDING) {
+                    mAdapterProperties.onBondStateChanged(device, newState);
+                }
+                oldState = BluetoothDevice.BOND_BONDING;
+            } else {
+                // Should not enter here.
+                throw new IllegalArgumentException("Invalid old state " + oldState);
+            }
+        }
         if (oldState == newState) {
             return;
         }
+
         StatsLog.write(StatsLog.BLUETOOTH_BOND_STATE_CHANGED,
                 mAdapterService.obfuscateAddress(device), 0, device.getType(),
                 newState, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN, reason);
@@ -410,8 +438,24 @@
         int classOfDevice = deviceClass == null ? 0 : deviceClass.getClassOfDevice();
         StatsLog.write(StatsLog.BLUETOOTH_CLASS_OF_DEVICE_REPORTED,
                 mAdapterService.obfuscateAddress(device), classOfDevice);
+
         mAdapterProperties.onBondStateChanged(device, newState);
 
+        if (devProp != null && ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC
+                || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL)
+                && newState == BluetoothDevice.BOND_BONDED && devProp.getUuids() == null)) {
+            infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent");
+            if (!mPendingBondedDevices.contains(device)) {
+                mPendingBondedDevices.add(device);
+            }
+            if (oldState == BluetoothDevice.BOND_NONE) {
+                // Broadcast NONE->BONDING for NONE->BONDED case.
+                newState = BluetoothDevice.BOND_BONDING;
+            } else {
+                return;
+            }
+        }
+
         Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
         intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java
index 7374f7a..e2bfddf 100644
--- a/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -223,6 +223,7 @@
         return null;
     }
 
+    @VisibleForTesting
     DeviceProperties addDeviceProperties(byte[] address) {
         synchronized (mDevices) {
             DeviceProperties prop = new DeviceProperties();
@@ -253,16 +254,16 @@
         private byte[] mAddress;
         private int mBluetoothClass = BluetoothClass.Device.Major.UNCATEGORIZED;
         private short mRssi;
-        private ParcelUuid[] mUuids;
-        private int mDeviceType;
         private String mAlias;
-        private int mBondState;
         private BluetoothDevice mDevice;
         private boolean mIsBondingInitiatedLocally;
         private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         private short mTwsPlusDevType;
         private byte[] peerEbAddress;
         private boolean autoConnect;
+        @VisibleForTesting int mBondState;
+        @VisibleForTesting int mDeviceType;
+        @VisibleForTesting ParcelUuid[] mUuids;
 
         DeviceProperties() {
             mBondState = BluetoothDevice.BOND_NONE;
@@ -676,6 +677,7 @@
                             if ((sAdapterService.getState() == BluetoothAdapter.STATE_ON) &&
                                                             device.autoConnect ) {
                                 debugLog("sendUuidIntent as Auto connect is set ");
+                                sAdapterService.deviceUuidUpdated(bdDevice);
                                 sendUuidIntent(bdDevice, device);
                             }
                             break;
diff --git a/src/com/android/bluetooth/hearingaid/HearingAidService.java b/src/com/android/bluetooth/hearingaid/HearingAidService.java
index c38f92c..8cfd180 100644
--- a/src/com/android/bluetooth/hearingaid/HearingAidService.java
+++ b/src/com/android/bluetooth/hearingaid/HearingAidService.java
@@ -357,24 +357,18 @@
             return false;
         }
         // Check priority and accept or reject the connection.
-        // Note: Logic can be simplified, but keeping it this way for readability
         int priority = getPriority(device);
         int bondState = mAdapterService.getBondState(device);
-        // If priority is undefined, it is likely that service discovery has not completed and peer
-        // initiated the connection. Allow this connection only if the device is bonded or bonding
-        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
-                && (bondState == BluetoothDevice.BOND_BONDING
-                   || bondState == BluetoothDevice.BOND_BONDED);
-        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
-        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
-                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
-                && (bondState == BluetoothDevice.BOND_BONDED
-                   || bondState == BluetoothDevice.BOND_BONDING);
-        if (!serviceDiscoveryPending && !isEnabled) {
-            // Otherwise, reject the connection if no service discovery is pending and priority is
-            // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
-            Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState="
-                    + bondState);
+        // Allow this connection only if the device is bonded. Any attempt to connect while
+        // bonding would potentially lead to an unauthorized connection.
+        if (bondState != BluetoothDevice.BOND_BONDED) {
+            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
+            return false;
+        } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
+                && priority != BluetoothProfile.PRIORITY_ON
+                && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+            // Otherwise, reject the connection if priority is not valid.
+            Log.w(TAG, "okToConnect: return false, priority=" + priority);
             return false;
         }
         return true;
diff --git a/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java b/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java
index 8adbdf2..d21d8b6 100644
--- a/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java
+++ b/src/com/android/bluetooth/hfp/HeadsetA2dpSync.java
@@ -38,6 +38,8 @@
 import android.util.Log;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import com.android.bluetooth.hearingaid.HearingAidService;
+import java.util.List;
 
 /**
  * Defines methods used for synchronization between HFP and A2DP
@@ -113,6 +115,17 @@
      */
     public boolean suspendA2DP(int reason, BluetoothDevice device){
         int a2dpState = isA2dpPlaying();
+
+        List<BluetoothDevice> HAActiveDevices = null;
+        HearingAidService mHaService = HearingAidService.getHearingAidService();
+        if (mHaService != null) {
+            HAActiveDevices = mHaService.getActiveDevices();
+        }
+        if (HAActiveDevices != null) {
+            Log.d(TAG,"Ignore suspendA2DP if active device is HearingAid");
+            return false;
+        }
+
         Log.d(TAG," suspendA2DP currPlayingState = "+ a2dpState + " for reason " + reason
               + "mA2dpSuspendTriggered = " + mA2dpSuspendTriggered + " for device " + device);
         if (mA2dpSuspendTriggered != A2DP_SUSPENDED_NOT_TRIGGERED) {
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 8fefdba..421ec73 100755
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -2356,24 +2356,18 @@
         }
         if(!isPts) {
             // Check priority and accept or reject the connection.
-            // Note: Logic can be simplified, but keeping it this way for readability
             int priority = getPriority(device);
             int bondState = mAdapterService.getBondState(device);
-            // If priority is undefined, it is likely that service discovery has not completed and peer
-            // initiated the connection. Allow this connection only if the device is bonded or bonding
-            boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED) && (
-                    bondState == BluetoothDevice.BOND_BONDING
-                            || bondState == BluetoothDevice.BOND_BONDED);
-            // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
-            boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
-                    || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) && (
-                    bondState == BluetoothDevice.BOND_BONDED
-                            || bondState == BluetoothDevice.BOND_BONDING);
-            if (!serviceDiscoveryPending && !isEnabled) {
-                // Otherwise, reject the connection if no service discovery is pending and priority is
-                // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
-                Log.w(TAG,
-                        "okToConnect: return false, priority=" + priority + ", bondState=" + bondState);
+            // Allow this connection only if the device is bonded. Any attempt to connect while
+            // bonding would potentially lead to an unauthorized connection.
+            if (bondState != BluetoothDevice.BOND_BONDED) {
+                Log.w(TAG, "okToAcceptConnection: return false, bondState=" + bondState);
+                return false;
+            } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
+                    && priority != BluetoothProfile.PRIORITY_ON
+                    && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+                // Otherwise, reject the connection if priority is not valid.
+                Log.w(TAG, "okToAcceptConnection: return false, priority=" + priority);
                 return false;
             }
         }
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 491a0bb..fa5a525 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -2208,6 +2208,37 @@
                 mNativeInterface.phoneStateChange(mDevice, updateCallState);
                 mIsCallIndDelay = true;
             }
+
+            /* The device is blacklisted for sending incoming call setup
+             * indicator after SCO disconnection and sending active call end
+             * indicator. While the incoming call setup indicator is in queue,
+             * waiting call moved to active state. Send call setup update first
+             * and remove it from queue. Create SCO since SCO might be in
+             * disconnecting/disconnected state */
+            if (mIsBlacklistedDevice &&
+                callState.mNumActive == 1 &&
+                callState.mNumHeld == 0 &&
+                callState.mCallState == HeadsetHalConstants.CALL_STATE_IDLE &&
+                hasMessages(SEND_INCOMING_CALL_IND)) {
+
+                Log.w(TAG, "waiting call moved to active state while incoming call");
+                Log.w(TAG, "setup indicator is in queue. Send it first and create SCO");
+                //remove call setup indicator from queue.
+                removeMessages(SEND_INCOMING_CALL_IND);
+
+                HeadsetCallState incomingCallSetupState =
+                        new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_INCOMING,
+                               mSystemInterface.getHeadsetPhoneState().getNumber(),
+                                 mSystemInterface.getHeadsetPhoneState().getType(),
+                                 "");
+                mNativeInterface.phoneStateChange(mDevice, incomingCallSetupState);
+
+                if (mDevice.equals(mHeadsetService.getActiveDevice())) {
+                    Message m = obtainMessage(CONNECT_AUDIO);
+                    m.obj = mDevice;
+                    sendMessage(m);
+                }
+            }
         }
         mStateMachineCallState.mNumActive = callState.mNumActive;
         mStateMachineCallState.mNumHeld = callState.mNumHeld;
diff --git a/src/com/android/bluetooth/hid/HidHostService.java b/src/com/android/bluetooth/hid/HidHostService.java
index ca97556..bbde619 100644
--- a/src/com/android/bluetooth/hid/HidHostService.java
+++ b/src/com/android/bluetooth/hid/HidHostService.java
@@ -26,6 +26,7 @@
 import android.os.Message;
 import android.os.UserHandle;
 import android.util.Log;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.bluetooth.BluetoothMetricsProto;
 import com.android.bluetooth.Utils;
@@ -794,16 +795,42 @@
         }
     }
 
-    private boolean okToConnect(BluetoothDevice device) {
+    /**
+     * Check whether can connect to a peer device.
+     * The check considers a number of factors during the evaluation.
+     *
+     * @param device the peer device to connect to
+     * @return true if connection is allowed, otherwise false
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+    public boolean okToConnect(BluetoothDevice device) {
         AdapterService adapterService = AdapterService.getAdapterService();
-        //check if it is inbound connection in Quiet mode, priority and Bond status
-        //to decide if its ok to allow this connection
-        if ((adapterService == null) || ((adapterService.isQuietModeEnabled()) && (mTargetDevice
-                == null)) || (BluetoothProfile.PRIORITY_OFF == getPriority(device)) || (
-                device.getBondState() == BluetoothDevice.BOND_NONE)) {
-             return false;
-         }
-
+        // Check if adapter service is null.
+        if (adapterService == null) {
+            Log.w(TAG, "okToConnect: adapter service is null");
+            return false;
+        }
+        // Check if this is an incoming connection in Quiet mode.
+        if (adapterService.isQuietModeEnabled() && mTargetDevice == null) {
+            Log.w(TAG, "okToConnect: return false as quiet mode enabled");
+            return false;
+        }
+        // Check priority and accept or reject the connection.
+        int priority = getPriority(device);
+        int bondState = adapterService.getBondState(device);
+        // During reconnection bond state may moved to bonding if remote missed key due to collision
+        // Also stack accepts the connection after authentication complete.
+        // Allow the connection in bonding and bonded states
+        if (bondState == BluetoothDevice.BOND_NONE) {
+            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
+            return false;
+        } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
+                && priority != BluetoothProfile.PRIORITY_ON
+                && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+            // Otherwise, reject the connection if priority is not valid.
+            Log.w(TAG, "okToConnect: return false, priority=" + priority);
+            return false;
+        }
         return true;
     }
 
diff --git a/src/com/android/bluetooth/map/BluetoothMapMasInstance.java b/src/com/android/bluetooth/map/BluetoothMapMasInstance.java
index e4270b1..8e0b2d3 100644
--- a/src/com/android/bluetooth/map/BluetoothMapMasInstance.java
+++ b/src/com/android/bluetooth/map/BluetoothMapMasInstance.java
@@ -477,16 +477,17 @@
         }
     }
 
-    public void setRemoteFeatureMask(int supportedFeatures, int remoteProfileVersion) {
-        Log.d(mTag, "setRemoteFeatureMask supportedFeatures : "
+    public void setRemoteFeatureMask(int supportedFeatures, int remoteProfileVersion,
+            BluetoothDevice rd) {
+        if (D) Log.d(mTag, "setRemoteFeatureMask supportedFeatures "
                 + Integer.toHexString(supportedFeatures) +", remoteProfileVersion: "
                 + Integer.toHexString(remoteProfileVersion));
         mPeerProfileVersion = remoteProfileVersion;
         if (Utils.isPtsTestMode()) {
             mRemoteFeatureMask =
                     SDP_MAP_MAS_FEATURES_ADV;
-        } else if ((remoteProfileVersion > SDP_MAP_MAS_VERSION)
-            && (!BluetoothMapFixes.isMapAdvDisabled())){
+        } else if ((remoteProfileVersion > SDP_MAP_MAS_VERSION_ADV)
+            && (!BluetoothMapFixes.isMapAdvDisabled()  && BluetoothMapFixes.isRebonded(rd))){
             mRemoteFeatureMask =
                 supportedFeatures & SDP_MAP_MAS_FEATURES_ADV;
         } else {
diff --git a/src/com/android/bluetooth/map/BluetoothMapService.java b/src/com/android/bluetooth/map/BluetoothMapService.java
index 076916f..5c81376 100644
--- a/src/com/android/bluetooth/map/BluetoothMapService.java
+++ b/src/com/android/bluetooth/map/BluetoothMapService.java
@@ -1100,12 +1100,12 @@
                         mBluetoothMnsObexClient.setMnsRecord(mMnsRecord);
                     }
                     if (status != -1 && mMnsRecord != null) {
+                        BluetoothMapFixes.showNotification(BluetoothMapService.this, remoteDevice);
                         for (int i = 0, c = mMasInstances.size(); i < c; i++) {
                             mMasInstances.valueAt(i)
                                     .setRemoteFeatureMask(mMnsRecord.getSupportedFeatures(),
-                                    mMnsRecord.getProfileVersion());
+                                    mMnsRecord.getProfileVersion(), remoteDevice);
                         }
-                        BluetoothMapFixes.showNotification(BluetoothMapService.this, remoteDevice);
                     }
                     if (mSdpSearchInitiated) {
                         mSdpSearchInitiated = false; // done searching
diff --git a/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java b/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
index df99505..78f4ad0 100644
--- a/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
@@ -314,13 +314,13 @@
         testOkToConnectCase(mTestDevice,
                 BluetoothDevice.BOND_NONE, badPriorityValue, false);
         testOkToConnectCase(mTestDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, false);
         testOkToConnectCase(mTestDevice,
                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
         testOkToConnectCase(mTestDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, false);
         testOkToConnectCase(mTestDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
         testOkToConnectCase(mTestDevice,
                 BluetoothDevice.BOND_BONDING, badPriorityValue, false);
         testOkToConnectCase(mTestDevice,
diff --git a/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java b/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java
new file mode 100644
index 0000000..7666f3a
--- /dev/null
+++ b/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * 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 com.android.bluetooth.btservice;
+
+import static org.mockito.Mockito.*;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+import android.os.HandlerThread;
+import android.os.ParcelUuid;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BondStateMachineTest {
+    private static final int TEST_BOND_REASON = 0;
+    private static final byte[] TEST_BT_ADDR_BYTES = {00, 11, 22, 33, 44, 55};
+    private static final ParcelUuid[] TEST_UUIDS =
+            {ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB")};
+
+    private static final int BOND_NONE = BluetoothDevice.BOND_NONE;
+    private static final int BOND_BONDING = BluetoothDevice.BOND_BONDING;
+    private static final int BOND_BONDED = BluetoothDevice.BOND_BONDED;
+
+    private AdapterProperties mAdapterProperties;
+    private BluetoothDevice mDevice;
+    private Context mTargetContext;
+    private RemoteDevices mRemoteDevices;
+    private BondStateMachine mBondStateMachine;
+    private HandlerThread mHandlerThread;
+    private RemoteDevices.DeviceProperties mDeviceProperties;
+    private int mVerifyCount = 0;
+
+    @Mock private AdapterService mAdapterService;
+
+    @Before
+    public void setUp() throws Exception {
+        mTargetContext = InstrumentationRegistry.getTargetContext();
+        MockitoAnnotations.initMocks(this);
+        TestUtils.setAdapterService(mAdapterService);
+        mHandlerThread = new HandlerThread("BondStateMachineTestHandlerThread");
+        mHandlerThread.start();
+
+        mRemoteDevices = new RemoteDevices(mAdapterService, mHandlerThread.getLooper());
+        mRemoteDevices.reset();
+        when(mAdapterService.getResources()).thenReturn(
+                mTargetContext.getResources());
+        mAdapterProperties = new AdapterProperties(mAdapterService);
+        mAdapterProperties.init(mRemoteDevices);
+        PowerManager powerManager = (PowerManager) mTargetContext.getSystemService(Context.POWER_SERVICE);
+        mBondStateMachine = BondStateMachine.make(powerManager, mAdapterService, mAdapterProperties,
+                mRemoteDevices);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        TestUtils.clearAdapterService(mAdapterService);
+    }
+
+    @Test
+    public void testSendIntent() {
+        int badBondState = 42;
+        mVerifyCount = 0;
+
+        // Reset mRemoteDevices for the test.
+        mRemoteDevices.reset();
+        mDeviceProperties = mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES);
+        mDevice = mDeviceProperties.getDevice();
+        Assert.assertNotNull(mDevice);
+
+        /* Classic / Dualmode test cases*/
+        // Uuid not available, mPendingBondedDevice is empty.
+        testSendIntentNoPendingDevice(BOND_NONE, BOND_NONE, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_NONE, BOND_BONDING, BOND_BONDING,
+                true, BOND_NONE, BOND_BONDING);
+        testSendIntentNoPendingDevice(BOND_NONE, BOND_BONDED, BOND_BONDED,
+                true, BOND_NONE, BOND_BONDING);
+        testSendIntentNoPendingDevice(BOND_NONE, badBondState, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDING, BOND_NONE, BOND_NONE,
+                true, BOND_BONDING, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDING, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDING, BOND_BONDED, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDING, badBondState, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDED, BOND_NONE, BOND_NONE,
+                true, BOND_BONDED, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDED, BOND_BONDING, BOND_BONDING,
+                true, BOND_BONDED, BOND_BONDING);
+        testSendIntentNoPendingDevice(BOND_BONDED, BOND_BONDED, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDevice(BOND_BONDED, badBondState, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+
+        // Uuid not available, mPendingBondedDevice contains a remote device.
+        testSendIntentPendingDevice(BOND_NONE, BOND_NONE, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_NONE, BOND_BONDING, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_NONE, BOND_BONDED, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_NONE, badBondState, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDING, BOND_NONE, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDING, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDING, BOND_BONDED, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDING, badBondState, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDED, BOND_NONE, BOND_NONE,
+                true, BOND_BONDING, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDED, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDED, BOND_BONDED, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDevice(BOND_BONDED, badBondState, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+
+        // Uuid available, mPendingBondedDevice is empty.
+        testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_NONE, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_BONDING, BOND_BONDING,
+                true, BOND_NONE, BOND_BONDING);
+        testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_BONDED, BOND_BONDED,
+                true, BOND_NONE, BOND_BONDED);
+        testSendIntentNoPendingDeviceWithUuid(BOND_NONE, badBondState, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_NONE, BOND_NONE,
+                true, BOND_BONDING, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_BONDED, BOND_BONDED,
+                true, BOND_BONDING, BOND_BONDED);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, badBondState, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_NONE, BOND_NONE,
+                true, BOND_BONDED, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_BONDING, BOND_BONDING,
+                true, BOND_BONDED, BOND_BONDING);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_BONDED, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, badBondState, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+
+        // Uuid available, mPendingBondedDevice contains a remote device.
+        testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_NONE, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_BONDING, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_BONDED, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_NONE, badBondState, BOND_NONE,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_NONE, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_BONDED, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDING, badBondState, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_NONE, BOND_NONE,
+                true, BOND_BONDING, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_BONDING, BOND_BONDING,
+                false, BOND_NONE, BOND_NONE);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_BONDED, BOND_BONDED,
+                true, BOND_BONDING, BOND_BONDED);
+        testSendIntentPendingDeviceWithUuid(BOND_BONDED, badBondState, BOND_BONDED,
+                false, BOND_NONE, BOND_NONE);
+
+        /* Low energy test cases */
+        testSendIntentBle(BOND_NONE, BOND_NONE, BOND_NONE);
+        testSendIntentBle(BOND_NONE, BOND_BONDING, BOND_BONDING);
+        testSendIntentBle(BOND_NONE, BOND_BONDED, BOND_BONDED);
+        testSendIntentBle(BOND_BONDING, BOND_NONE, BOND_NONE);
+        testSendIntentBle(BOND_BONDING, BOND_BONDING, BOND_BONDING);
+        testSendIntentBle(BOND_BONDING, BOND_BONDED, BOND_BONDED);
+        testSendIntentBle(BOND_BONDED, BOND_NONE, BOND_NONE);
+        testSendIntentBle(BOND_BONDED, BOND_BONDING, BOND_BONDING);
+        testSendIntentBle(BOND_BONDED, BOND_BONDED, BOND_BONDED);
+    }
+
+    private void testSendIntentCase(int oldState, int newState, int expectedNewState,
+            boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
+        ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
+
+        // Setup old state before start test.
+        mDeviceProperties.mBondState = oldState;
+
+        try {
+            mBondStateMachine.sendIntent(mDevice, newState, TEST_BOND_REASON);
+        } catch (IllegalArgumentException e) {
+            // Do nothing.
+        }
+        Assert.assertEquals(expectedNewState, mDeviceProperties.getBondState());
+
+        // Check for bond state Intent status.
+        if (shouldBroadcast) {
+            verify(mAdapterService, times(++mVerifyCount)).sendBroadcastAsUser(
+                    intentArgument.capture(), eq(UserHandle.ALL),
+                    eq(AdapterService.BLUETOOTH_PERM));
+            verifyBondStateChangeIntent(broadcastOldState, broadcastNewState,
+                    intentArgument.getValue());
+        } else {
+            verify(mAdapterService, times(mVerifyCount)).sendBroadcastAsUser(any(Intent.class),
+                    any(UserHandle.class), anyString());
+        }
+    }
+
+    private void testSendIntentNoPendingDeviceWithUuid(int oldState, int newState,
+            int expectedNewState, boolean shouldBroadcast, int broadcastOldState,
+            int broadcastNewState) {
+        // Add dummy UUID for the device.
+        mDeviceProperties.mUuids = TEST_UUIDS;
+        testSendIntentNoPendingDevice(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+    }
+
+    private void testSendIntentPendingDeviceWithUuid(int oldState, int newState,
+            int expectedNewState, boolean shouldBroadcast, int broadcastOldState,
+            int broadcastNewState) {
+        // Add dummy UUID for the device.
+        mDeviceProperties.mUuids = TEST_UUIDS;
+        testSendIntentPendingDevice(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+    }
+
+    private void testSendIntentPendingDevice(int oldState, int newState, int expectedNewState,
+            boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
+        // Test for classic remote device.
+        mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_CLASSIC;
+        mBondStateMachine.mPendingBondedDevices.clear();
+        mBondStateMachine.mPendingBondedDevices.add(mDevice);
+        testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+
+        // Test for dual-mode remote device.
+        mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_DUAL;
+        mBondStateMachine.mPendingBondedDevices.clear();
+        mBondStateMachine.mPendingBondedDevices.add(mDevice);
+        testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+    }
+
+    private void testSendIntentNoPendingDevice(int oldState, int newState, int expectedNewState,
+            boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
+        // Test for classic remote device.
+        mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_CLASSIC;
+        mBondStateMachine.mPendingBondedDevices.clear();
+        testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+
+        // Test for dual-mode remote device.
+        mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_DUAL;
+        mBondStateMachine.mPendingBondedDevices.clear();
+        testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
+                broadcastOldState, broadcastNewState);
+    }
+
+    private void testSendIntentBle(int oldState, int newState, int expectedNewState) {
+        // Test for low energy remote device.
+        mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_LE;
+        mBondStateMachine.mPendingBondedDevices.clear();
+        testSendIntentCase(oldState, newState, newState, (oldState != newState),
+                oldState, newState);
+    }
+
+    private void verifyBondStateChangeIntent(int oldState, int newState, Intent intent) {
+        Assert.assertNotNull(intent);
+        Assert.assertEquals(BluetoothDevice.ACTION_BOND_STATE_CHANGED, intent.getAction());
+        Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
+        Assert.assertEquals(newState, intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1));
+        Assert.assertEquals(oldState, intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
+                                                          -1));
+        if (newState == BOND_NONE) {
+            Assert.assertEquals(TEST_BOND_REASON, intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+                                                              -1));
+        } else {
+            Assert.assertEquals(-1, intent.getIntExtra(BluetoothDevice.EXTRA_REASON, -1));
+        }
+    }
+}
diff --git a/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java b/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
index 8efe285..f5f9e76 100644
--- a/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java
@@ -263,13 +263,13 @@
         testOkToConnectCase(mSingleDevice,
                 BluetoothDevice.BOND_NONE, badPriorityValue, false);
         testOkToConnectCase(mSingleDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, false);
         testOkToConnectCase(mSingleDevice,
                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
         testOkToConnectCase(mSingleDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, false);
         testOkToConnectCase(mSingleDevice,
-                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
         testOkToConnectCase(mSingleDevice,
                 BluetoothDevice.BOND_BONDING, badPriorityValue, false);
         testOkToConnectCase(mSingleDevice,
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index a73c05c..57a9a2f 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -204,13 +204,13 @@
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_NONE, badPriorityValue,
                 false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
-                BluetoothProfile.PRIORITY_UNDEFINED, true);
+                BluetoothProfile.PRIORITY_UNDEFINED, false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
                 BluetoothProfile.PRIORITY_OFF, false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
-                BluetoothProfile.PRIORITY_ON, true);
+                BluetoothProfile.PRIORITY_ON, false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
-                BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
+                BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING, badPriorityValue,
                 false);
         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDED,
diff --git a/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java b/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
index 499db4a..4e0ec59 100644
--- a/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hid/HidHostServiceTest.java
@@ -15,7 +15,11 @@
  */
 package com.android.bluetooth.hid;
 
+import static org.mockito.Mockito.*;
+
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 
 import androidx.test.InstrumentationRegistry;
@@ -43,6 +47,7 @@
 public class HidHostServiceTest {
     private HidHostService mService = null;
     private BluetoothAdapter mAdapter = null;
+    private BluetoothDevice mTestDevice;
     private Context mTargetContext;
 
     @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
@@ -62,6 +67,9 @@
         // Try getting the Bluetooth adapter
         mAdapter = BluetoothAdapter.getDefaultAdapter();
         Assert.assertNotNull(mAdapter);
+
+        // Get a device for testing
+        mTestDevice = TestUtils.getTestDevice(mAdapter, 0);
     }
 
     @After
@@ -79,4 +87,79 @@
     public void testInitialize() {
         Assert.assertNotNull(HidHostService.getHidHostService());
     }
+
+    /**
+     *  Test okToConnect method using various test cases
+     */
+    @Test
+    public void testOkToConnect() {
+        int badPriorityValue = 1024;
+        int badBondState = 42;
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_UNDEFINED, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_OFF, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_ON, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_NONE, badPriorityValue, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDING, badPriorityValue, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_UNDEFINED, true);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_OFF, false);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_ON, true);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
+        testOkToConnectCase(mTestDevice,
+                BluetoothDevice.BOND_BONDED, badPriorityValue, false);
+        testOkToConnectCase(mTestDevice,
+                badBondState, BluetoothProfile.PRIORITY_UNDEFINED, false);
+        testOkToConnectCase(mTestDevice,
+                badBondState, BluetoothProfile.PRIORITY_OFF, false);
+        testOkToConnectCase(mTestDevice,
+                badBondState, BluetoothProfile.PRIORITY_ON, false);
+        testOkToConnectCase(mTestDevice,
+                badBondState, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
+        testOkToConnectCase(mTestDevice,
+                badBondState, badPriorityValue, false);
+        // Restore prirority to undefined for this test device
+        Assert.assertTrue(mService.setPriority(
+                mTestDevice, BluetoothProfile.PRIORITY_UNDEFINED));
+    }
+
+    /**
+     * Helper function to test okToConnect() method.
+     *
+     * @param device test device
+     * @param bondState bond state value, could be invalid
+     * @param priority value, could be invalid
+     * @param expected expected result from okToConnect()
+     */
+    private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,
+            boolean expected) {
+        doReturn(bondState).when(mAdapterService).getBondState(device);
+        Assert.assertTrue(mService.setPriority(device, priority));
+
+        // Test when the AdapterService is in non-quiet mode.
+        doReturn(false).when(mAdapterService).isQuietModeEnabled();
+        Assert.assertEquals(expected, mService.okToConnect(device));
+
+        // Test when the AdapterService is in quiet mode.
+        doReturn(true).when(mAdapterService).isQuietModeEnabled();
+        Assert.assertEquals(false, mService.okToConnect(device));
+    }
+
 }