Stability improvements to BtCar tests

Check profile connected apis before
trying to look for the broadcast
receivers.

Increase pair attemps for non-pairing
attempt testcases.

Add sleep between clearing bonded devices
and pairing where necessary since the
stack needs time to reset.

Test: manual - execute automation manually
Change-Id: Icca05c1aca386da6422587b7fa67e10ed53c87b0
diff --git a/acts/framework/acts/test_utils/bt/BluetoothCarHfpBaseTest.py b/acts/framework/acts/test_utils/bt/BluetoothCarHfpBaseTest.py
index fd5e240..a858068 100644
--- a/acts/framework/acts/test_utils/bt/BluetoothCarHfpBaseTest.py
+++ b/acts/framework/acts/test_utils/bt/BluetoothCarHfpBaseTest.py
@@ -19,6 +19,7 @@
 """
 
 import os
+import time
 from queue import Empty
 
 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
@@ -75,7 +76,10 @@
             self.re2_phone_number = get_phone_number(self.log, self.re2)
             self.log.info("re2 tel: {}".format(self.re2_phone_number))
         # Pair and connect the devices.
-        if not pair_pri_to_sec(self.hf, self.ag):
+        # Grace time inbetween stack state changes
+        time.sleep(5)
+        if not pair_pri_to_sec(
+                self.hf, self.ag, attempts=4, auto_confirm=False):
             self.log.error("Failed to pair")
             return False
         return True
diff --git a/acts/framework/acts/test_utils/bt/bt_test_utils.py b/acts/framework/acts/test_utils/bt/bt_test_utils.py
index e0510b2..400b6c5 100644
--- a/acts/framework/acts/test_utils/bt/bt_test_utils.py
+++ b/acts/framework/acts/test_utils/bt/bt_test_utils.py
@@ -614,6 +614,7 @@
     profile_dict['pbap_client'] = droid.bluetoothPbapClientIsReady()
     return profile_dict
 
+
 def log_energy_info(android_devices, state):
     """Logs energy info of input Android devices.
 
@@ -648,6 +649,7 @@
             log.error("Profile {} not yet supported for priority settings".
                       format(profile))
 
+
 def pair_pri_to_sec(pri_ad, sec_ad, attempts=2, auto_confirm=True):
     """Pairs pri droid to secondary droid.
 
@@ -661,16 +663,18 @@
         Pass if True
         Fail if False
     """
+    pri_ad.droid.bluetoothStartConnectionStateChangeMonitor(
+        sec_ad.droid.bluetoothGetLocalAddress())
     curr_attempts = 0
     while curr_attempts < attempts:
         if _pair_pri_to_sec(pri_ad, sec_ad, auto_confirm):
             return True
         curr_attempts += 1
-        time.sleep(DEFAULT_TIMEOUT)
     log.error("pair_pri_to_sec failed to connect after {} attempts".format(
         str(attempts)))
     return False
 
+
 def _wait_for_passkey_match(pri_ad, sec_ad):
     pri_pin, sec_pin = -1, 1
     pri_variant, sec_variant = -1, 1
@@ -682,18 +686,18 @@
         pri_variant = pri_pairing_req["data"]["PairingVariant"]
         pri_pin = pri_pairing_req["data"]["Pin"]
         log.info("Primary device received Pin: {}, Variant: {}"
-            .format(pri_pin, pri_variant))
+                 .format(pri_pin, pri_variant))
         sec_pairing_req = sec_ad.ed.pop_event(
             event_name="BluetoothActionPairingRequest",
             timeout=DEFAULT_TIMEOUT)
         sec_variant = sec_pairing_req["data"]["PairingVariant"]
         sec_pin = sec_pairing_req["data"]["Pin"]
         log.info("Secondary device received Pin: {}, Variant: {}"
-            .format(sec_pin, sec_variant))
+                 .format(sec_pin, sec_variant))
     except Empty as err:
         log.error("Wait for pin error: {}".format(err))
         log.error("Pairing request state, Primary: {}, Secondary: {}"
-            .format(pri_pairing_req, sec_pairing_req))
+                  .format(pri_pairing_req, sec_pairing_req))
         return False
     if pri_variant == sec_variant == PAIRING_VARIANT_PASSKEY_CONFIRMATION:
         confirmation = pri_pin == sec_pin
@@ -701,10 +705,10 @@
             log.info("Pairing code matched, accepting connection")
         else:
             log.info("Pairing code mismatched, rejecting connection")
-        pri_ad.droid.eventPost(
-            "BluetoothActionPairingRequestUserConfirm", str(confirmation))
-        sec_ad.droid.eventPost(
-            "BluetoothActionPairingRequestUserConfirm", str(confirmation))
+        pri_ad.droid.eventPost("BluetoothActionPairingRequestUserConfirm",
+                               str(confirmation))
+        sec_ad.droid.eventPost("BluetoothActionPairingRequestUserConfirm",
+                               str(confirmation))
         if not confirmation:
             return False
     elif pri_variant != sec_variant:
@@ -712,6 +716,7 @@
         return False
     return True
 
+
 def _pair_pri_to_sec(pri_ad, sec_ad, auto_confirm):
     # Enable discovery on sec_ad so that pri_ad can find it.
     # The timeout here is based on how much time it would take for two devices
@@ -748,6 +753,7 @@
     log.info("Failed to bond devices.")
     return False
 
+
 def connect_pri_to_sec(pri_ad, sec_ad, profiles_set, attempts=2):
     """Connects pri droid to secondary droid.
 
@@ -813,12 +819,40 @@
     pri_ad.droid.bluetoothConnectBonded(sec_ad.droid.bluetoothGetLocalAddress(
     ))
 
+    end_time = time.time() + 10
     profile_connected = set()
+    sec_addr = sec_ad.droid.bluetoothGetLocalAddress()
     log.info("Profiles to be connected {}".format(profiles_set))
+    # First use APIs to check profile connection state
+    while (time.time() < end_time and
+           not profile_connected.issuperset(profiles_set)):
+        if (BluetoothProfile.HEADSET_CLIENT.value not in profile_connected and
+                BluetoothProfile.HEADSET_CLIENT.value in profiles_set):
+            if is_hfp_client_device_connected(pri_ad, sec_addr):
+                profile_connected.add(BluetoothProfile.HEADSET_CLIENT.value)
+        if (BluetoothProfile.A2DP.value not in profile_connected and
+                BluetoothProfile.A2DP.value in profiles_set):
+            if is_a2dp_src_device_connected(pri_ad, sec_addr):
+                profile_connected.add(BluetoothProfile.A2DP.value)
+        if (BluetoothProfile.A2DP_SINK.value not in profile_connected and
+                BluetoothProfile.A2DP_SINK.value in profiles_set):
+            if is_a2dp_snk_device_connected(pri_ad, sec_addr):
+                profile_connected.add(BluetoothProfile.A2DP_SINK.value)
+        if (BluetoothProfile.MAP_MCE.value not in profile_connected and
+                BluetoothProfile.MAP_MCE.value in profiles_set):
+            if is_map_mce_device_connected(pri_ad, sec_addr):
+                profile_connected.add(BluetoothProfile.MAP_MCE.value)
+        if (BluetoothProfile.MAP.value not in profile_connected and
+                BluetoothProfile.MAP.value in profiles_set):
+            if is_map_mse_device_connected(pri_ad, sec_addr):
+                profile_connected.add(BluetoothProfile.MAP.value)
+        time.sleep(0.1)
+    # If APIs fail, try to find the connection broadcast receiver.
     while not profile_connected.issuperset(profiles_set):
         try:
             profile_event = pri_ad.ed.pop_event(
-                bluetooth_profile_connection_state_changed, DEFAULT_TIMEOUT)
+                bluetooth_profile_connection_state_changed,
+                DEFAULT_TIMEOUT + 10)
             log.info("Got event {}".format(profile_event))
         except Exception:
             log.error("Did not get {} profiles left {}".format(
@@ -906,6 +940,7 @@
     for a in android_devices:
         take_btsnoop_log(a, testcase, testname)
 
+
 def take_btsnoop_log(ad, testcase, testname):
     """Grabs the btsnoop_hci log on a device and stores it in the log directory
     of the test class.
@@ -926,12 +961,13 @@
     out_name = ','.join((testname, device_model, serial))
     snoop_path = ad.log_path + "/BluetoothSnoopLogs"
     utils.create_dir(snoop_path)
-    cmd = ''.join(("adb -s ", serial, " pull ", BTSNOOP_LOG_PATH_ON_DEVICE, " ",
-                   snoop_path + '/' + out_name, ".btsnoop_hci.log"))
+    cmd = ''.join(("adb -s ", serial, " pull ", BTSNOOP_LOG_PATH_ON_DEVICE,
+                   " ", snoop_path + '/' + out_name, ".btsnoop_hci.log"))
     testcase.log.info("Test failed, grabbing the bt_snoop logs on {} {}."
                       .format(device_model, serial))
     exe_cmd(cmd)
 
+
 def kill_bluetooth_process(ad):
     """Kill Bluetooth process on Android device.
 
diff --git a/acts/tests/google/bt/car_bt/BtCarHfpConferenceTest.py b/acts/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
index 40e346e..5f85289 100644
--- a/acts/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
@@ -50,13 +50,6 @@
                 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value]))
             self.log.info("Connected {}".format(connected))
             attempts -= 1
-        # Additional profile connection check for b/
-        if bt_test_utils.is_hfp_client_device_connected(
-                self.hf, self.ag.droid.bluetoothGetLocalAddress()):
-            connected = True
-            self.log.info(
-                "HFP Client connected even though connection state changed " +
-                " event not found")
         return connected
 
     #@BluetoothTest(UUID=a9657693-b534-4625-bf91-69a1d1b9a943)
diff --git a/acts/tests/google/bt/car_bt/BtCarHfpConnectionTest.py b/acts/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
index 4760ccb..76416a7 100644
--- a/acts/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
@@ -103,13 +103,7 @@
             self.log.error("Could not connect HF and AG {} {}".format(
                 self.hf.droid.getBuildSerial(), self.ag.droid.getBuildSerial(
                 )))
-            # Additional profile connection check
-            if not bt_test_utils.is_hfp_client_device_connected(
-                    self.hf, self.ag.droid.bluetoothGetLocalAddress()):
-                self.log.info(
-                    "HFP Client connected even though connection state changed "
-                    + " event not found")
-                return False
+            return False
 
         # Check that HF is in active state
         if not car_telecom_utils.wait_for_active(self.log, self.hf):
diff --git a/acts/tests/google/bt/car_bt/BtCarHfpFuzzTest.py b/acts/tests/google/bt/car_bt/BtCarHfpFuzzTest.py
index 0ffd959..f951db1 100644
--- a/acts/tests/google/bt/car_bt/BtCarHfpFuzzTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarHfpFuzzTest.py
@@ -44,13 +44,6 @@
                 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value]))
             self.log.info("Connected {}".format(connected))
             attempts -= 1
-        # Additional profile connection check for b/
-        if bt_test_utils.is_hfp_client_device_connected(
-                self.hf, self.ag.droid.bluetoothGetLocalAddress()):
-            connected = True
-            self.log.info(
-                "HFP Client connected even though connection state changed " +
-                " event not found")
 
         if not connected:
             self.log.error("Failed to connect")
diff --git a/acts/tests/google/bt/car_bt/BtCarHfpTest.py b/acts/tests/google/bt/car_bt/BtCarHfpTest.py
index dca44b8..ad852e0 100644
--- a/acts/tests/google/bt/car_bt/BtCarHfpTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarHfpTest.py
@@ -48,14 +48,7 @@
         if not bt_test_utils.connect_pri_to_sec(self.hf, self.ag, set(
             [BtEnum.BluetoothProfile.HEADSET_CLIENT.value])):
             self.log.error("Failed to connect")
-            # Additional profile connection check
-            if bt_test_utils.is_hfp_client_device_connected(
-                    self.hf, self.ag.droid.bluetoothGetLocalAddress()):
-                self.log.info(
-                    "HFP Client connected even though connection state changed "
-                    + " event not found")
-            else:
-                return False
+            return False
         return True
 
     #@BluetoothTest(UUID=4ce2195a-b70a-4584-912e-cbd20d20e19d)
diff --git a/acts/tests/google/bt/car_bt/BtCarMapMceTest.py b/acts/tests/google/bt/car_bt/BtCarMapMceTest.py
index b8c7a0a..5d143e7 100644
--- a/acts/tests/google/bt/car_bt/BtCarMapMceTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarMapMceTest.py
@@ -31,7 +31,6 @@
 from acts.test_utils.tel.tel_test_utils import get_phone_number
 from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
 
-
 EVENT_MAP_MESSAGE_RECEIVED = "MapMessageReceived"
 TIMEOUT = 2000
 MESSAGE_TO_SEND = "Don't text and Drive!"
@@ -49,6 +48,7 @@
         self.MCE = self.hf
         # Phone device
         self.MSE = self.ag
+        # Remote device
         self.REMOTE = self.re
         time.sleep(4)
         return True
@@ -160,8 +160,7 @@
     @BluetoothBaseTest.bt_test_wrap
     def manual_test_send_message_to_contact(self):
         bt_test_utils.connect_pri_to_sec(
-            self.MCE, self.MSE,
-            set([BtEnum.BluetoothProfile.MAP_MCE.value]))
+            self.MCE, self.MSE, set([BtEnum.BluetoothProfile.MAP_MCE.value]))
         contacts = self.MCE.droid.contactsGetContactIds()
         self.log.info(contacts)
         selected_contact = self.MCE.droid.contactsDisplayContactPickList()
@@ -174,6 +173,5 @@
     @BluetoothBaseTest.bt_test_wrap
     def test_send_message_to_multiple_phones(self):
         bt_test_utils.connect_pri_to_sec(
-            self.MCE, self.MSE,
-            set([BtEnum.BluetoothProfile.MAP_MCE.value]))
+            self.MCE, self.MSE, set([BtEnum.BluetoothProfile.MAP_MCE.value]))
         return self.send_message([self.REMOTE, self.REMOTE])
diff --git a/acts/tests/google/bt/car_bt/BtCarMediaConnectionTest.py b/acts/tests/google/bt/car_bt/BtCarMediaConnectionTest.py
index d400bad..1d58aec 100644
--- a/acts/tests/google/bt/car_bt/BtCarMediaConnectionTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarMediaConnectionTest.py
@@ -41,8 +41,11 @@
         self.btAddrCT = self.CT.droid.bluetoothGetLocalAddress()
         self.btAddrTG = self.TG.droid.bluetoothGetLocalAddress()
 
+        # Additional time from the stack reset in setup.
+        time.sleep(4)
         # Pair the devices.
-        if not bt_test_utils.pair_pri_to_sec(self.CT, self.TG):
+        if not bt_test_utils.pair_pri_to_sec(
+                self.CT, self.TG, attempts=4, auto_confirm=False):
             self.log.error("Failed to pair")
             return False
 
@@ -97,14 +100,9 @@
         if (car_media_utils.is_a2dp_connected(self.log, self.SNK, self.SRC)):
             self.log.info("Already Connected")
         else:
-            result = bt_test_utils.connect_pri_to_sec(
-                self.SRC, self.SNK, set([BtEnum.BluetoothProfile.A2DP.value]))
-            if not result:
-                # Additional profile connection check for b/
-                if not bt_test_utils.is_a2dp_src_device_connected(
-                        self.SRC, self.SNK.droid.bluetoothGetLocalAddress()):
-                    self.log.error("Failed to connect on A2dp")
-                    return False
+            if (not bt_test_utils.connect_pri_to_sec(self.SRC, self.SNK, set(
+                [BtEnum.BluetoothProfile.A2DP.value]))):
+                return False
 
         result = bt_test_utils.disconnect_pri_from_sec(
             self.SRC, self.SNK, [BtEnum.BluetoothProfile.A2DP.value])
@@ -148,15 +146,9 @@
         if car_media_utils.is_a2dp_connected(self.log, self.SNK, self.SRC):
             self.log.info("Already Connected")
         else:
-            result = bt_test_utils.connect_pri_to_sec(
-                self.SNK, self.SRC,
-                set([BtEnum.BluetoothProfile.A2DP_SINK.value]))
-            if not result:
-                # Additional profile connection check for b/
-                if not bt_test_utils.is_a2dp_snk_device_connected(
-                        self.SNK, self.SRC.droid.bluetoothGetLocalAddress()):
-                    self.log.error("Failed to connect on A2dp Sink")
-                    return False
+            if (not bt_test_utils.connect_pri_to_sec(self.SNK, self.SRC, set(
+                [BtEnum.BluetoothProfile.A2DP_SINK.value]))):
+                return False
         # Disconnect
         result = bt_test_utils.disconnect_pri_from_sec(
             self.SNK, self.SRC, [BtEnum.BluetoothProfile.A2DP_SINK.value])
diff --git a/acts/tests/google/bt/car_bt/BtCarMediaPassthroughTest.py b/acts/tests/google/bt/car_bt/BtCarMediaPassthroughTest.py
index 96a6252..28b8b7e 100644
--- a/acts/tests/google/bt/car_bt/BtCarMediaPassthroughTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarMediaPassthroughTest.py
@@ -71,8 +71,11 @@
                                local_media_path + " from test config file.")
                 return False
 
+        # Additional time from the stack reset in setup.
+        time.sleep(4)
         # Pair and connect the devices.
-        if not bt_test_utils.pair_pri_to_sec(self.CT, self.TG):
+        if not bt_test_utils.pair_pri_to_sec(
+                self.CT, self.TG, attempts=4, auto_confirm=False):
             self.log.error("Failed to pair")
             return False
 
@@ -397,13 +400,9 @@
             return False
 
         # Now connect to Car on Bluetooth
-        result = bt_test_utils.connect_pri_to_sec(
-            self.SRC, self.SNK, set([BtEnum.BluetoothProfile.A2DP.value]))
-        if not result:
-            if not bt_test_utils.is_a2dp_src_device_connected(
-                    self.SRC, self.SNK.droid.bluetoothGetLocalAddress()):
-                self.log.error("Failed to connect on A2dp")
-                return False
+        if (not bt_test_utils.connect_pri_to_sec(
+            self.SRC, self.SNK, set([BtEnum.BluetoothProfile.A2DP.value]))):
+            return False
 
         # Wait for a bit for the information to show up in the car side
         time.sleep(2)
diff --git a/acts/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py b/acts/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
index 95a166b..ee01607 100644
--- a/acts/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
@@ -45,7 +45,8 @@
 
         # Pair the devices.
         # This call may block until some specified timeout in bt_test_utils.py.
-        result = bt_test_utils.pair_pri_to_sec(self.car, self.ph)
+        result = bt_test_utils.pair_pri_to_sec(
+            self.car, self.ph, auto_confirm=False)
 
         asserts.assert_true(result, "pair_pri_to_sec returned false.")
 
diff --git a/acts/tests/google/bt/car_bt/BtCarPairingTest.py b/acts/tests/google/bt/car_bt/BtCarPairingTest.py
index 3c71191..34958aa 100644
--- a/acts/tests/google/bt/car_bt/BtCarPairingTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarPairingTest.py
@@ -54,7 +54,8 @@
         Priority: 0
         """
         # Pair the devices.
-        if not bt_test_utils.pair_pri_to_sec(self.car, self.ph):
+        if not bt_test_utils.pair_pri_to_sec(
+                self.car, self.ph, attempts=1, auto_confirm=False):
             self.log.error("cannot pair")
             return False
 
@@ -108,7 +109,8 @@
         """
         # Pair the devices.
         self.log.info("Pairing the devices ...")
-        if not bt_test_utils.pair_pri_to_sec(self.car, self.ph):
+        if not bt_test_utils.pair_pri_to_sec(
+                self.car, self.ph, attempts=1, auto_confirm=False):
             self.log.error("cannot pair")
             return False
 
@@ -126,7 +128,8 @@
 
         # Pair them again!
         self.log.info("Pairing them again ...")
-        if not bt_test_utils.pair_pri_to_sec(self.car, self.ph):
+        if not bt_test_utils.pair_pri_to_sec(
+                self.car, self.ph, attempts=1, auto_confirm=False):
             self.log.error("cannot re-pair")
             return False
 
diff --git a/acts/tests/google/bt/car_bt/BtCarPbapTest.py b/acts/tests/google/bt/car_bt/BtCarPbapTest.py
index 5c20939..c59d9e4 100644
--- a/acts/tests/google/bt/car_bt/BtCarPbapTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarPbapTest.py
@@ -17,8 +17,7 @@
 """
 
 import os
-from time import sleep
-from time import time
+import time
 
 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
 from acts.base_test import BaseTestClass
@@ -49,7 +48,11 @@
 
         # Pair the devices.
         # This call may block until some specified timeout in bt_test_utils.py.
-        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
+        # Grace time inbetween stack state changes
+
+        time.sleep(5)
+        if not bt_test_utils.pair_pri_to_sec(
+                self.pce, self.pse, attempts=4, auto_confirm=False):
             self.log.error("Failed to pair.")
             return False
 
@@ -77,7 +80,7 @@
                 bt_contacts_utils.erase_contacts(self.pce)):
             return False
         # Allow all content providers to synchronize.
-        sleep(1)
+        time.sleep(1)
         return True
 
     def teardown_test(self):
@@ -323,23 +326,23 @@
         bt_contacts_utils.add_call_log(
             self.pse, bt_contacts_utils.INCOMMING_CALL_TYPE,
             bt_contacts_utils.generate_random_phone_number().phone_number,
-            int(time()) * 1000)
+            int(time.time() * 1000))
         bt_contacts_utils.add_call_log(
             self.pse, bt_contacts_utils.INCOMMING_CALL_TYPE,
             bt_contacts_utils.generate_random_phone_number().phone_number,
-            int(time()) * 1000 - 4 * CALL_LOG_TIME_OFFSET_IN_MSEC)
+            int(time.time()) * 1000 - 4 * CALL_LOG_TIME_OFFSET_IN_MSEC)
         bt_contacts_utils.add_call_log(
             self.pse, bt_contacts_utils.OUTGOING_CALL_TYPE,
             bt_contacts_utils.generate_random_phone_number().phone_number,
-            int(time()) * 1000 - CALL_LOG_TIME_OFFSET_IN_MSEC)
+            int(time.time()) * 1000 - CALL_LOG_TIME_OFFSET_IN_MSEC)
         bt_contacts_utils.add_call_log(
             self.pse, bt_contacts_utils.MISSED_CALL_TYPE,
             bt_contacts_utils.generate_random_phone_number().phone_number,
-            int(time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
+            int(time.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
         bt_contacts_utils.add_call_log(
             self.pse, bt_contacts_utils.MISSED_CALL_TYPE,
             bt_contacts_utils.generate_random_phone_number().phone_number,
-            int(time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
+            int(time.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
 
         bt_test_utils.connect_pri_to_sec(
             self.pce, self.pse,