Home | History | Annotate | Download | only in car_bt
      1 #/usr/bin/env python3.4
      2 #
      3 # Copyright (C) 2016 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
      6 # use this file except in compliance with the License. You may obtain a copy of
      7 # the License at
      8 #
      9 # http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     14 # License for the specific language governing permissions and limitations under
     15 # the License.
     16 """Test script to test PBAP contact download between two devices which can run SL4A.
     17 """
     18 
     19 import os
     20 import time
     21 
     22 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     23 from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
     24 from acts.base_test import BaseTestClass
     25 from acts.test_utils.bt import bt_contacts_utils
     26 from acts.test_utils.bt import bt_test_utils
     27 from acts.test_utils.car import car_bt_utils
     28 from acts.utils import exe_cmd
     29 import acts.test_utils.bt.BtEnum as BtEnum
     30 
     31 # Offset call logs by 1 minute
     32 CALL_LOG_TIME_OFFSET_IN_MSEC = 60000
     33 PSE_CONTACTS_FILE = "psecontacts.vcf"
     34 PCE_CONTACTS_FILE = "pcecontacts.vcf"
     35 MERGED_CONTACTS_FILE = "psecombined.vcf"
     36 STANDART_CONTACT_COUNT = 100
     37 
     38 
     39 class BtCarPbapTest(BluetoothBaseTest):
     40     contacts_destination_path = ""
     41 
     42     def __init__(self, controllers):
     43         BaseTestClass.__init__(self, controllers)
     44         self.pce = self.android_devices[0]
     45         self.pse = self.android_devices[1]
     46         self.pse2 = self.android_devices[2]
     47         self.contacts_destination_path = self.log_path + "/"
     48 
     49     def setup_class(self):
     50         if not super(BtCarPbapTest, self).setup_class():
     51             return False
     52         permissions_list = [
     53             "android.permission.READ_CONTACTS",
     54             "android.permission.WRITE_CONTACTS",
     55             "android.permission.READ_EXTERNAL_STORAGE"
     56         ]
     57         for permission in permissions_list:
     58             self.pse.adb.shell(
     59                 "pm grant com.google.android.contacts {}".format(permission))
     60         for permission in permissions_list:
     61             self.pce.adb.shell("pm grant com.android.contacts {}".format(
     62                 permission))
     63 
     64         # Pair the devices.
     65         # This call may block until some specified timeout in bt_test_utils.py.
     66         # Grace time inbetween stack state changes
     67 
     68         setup_multiple_devices_for_bt_test(self.android_devices)
     69         if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
     70             self.log.error("Failed to pair.")
     71             return False
     72         time.sleep(3)
     73         if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
     74             self.log.error("Failed to pair.")
     75             return False
     76 
     77         # Disable the HFP and A2DP profiles. This will ensure only PBAP
     78         # gets connected. Also, this will eliminate the auto-connect loop.
     79         car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
     80         car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
     81 
     82         # Enable PBAP on PSE & PCE.
     83 
     84         self.pse.droid.bluetoothChangeProfileAccessPermission(
     85             self.pce.droid.bluetoothGetLocalAddress(),
     86             BtEnum.BluetoothProfile.PBAP_SERVER.value,
     87             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
     88 
     89         self.pse2.droid.bluetoothChangeProfileAccessPermission(
     90             self.pce.droid.bluetoothGetLocalAddress(),
     91             BtEnum.BluetoothProfile.PBAP_SERVER.value,
     92             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
     93 
     94         bt_test_utils.set_profile_priority(
     95             self.pce, self.pse, [BtEnum.BluetoothProfile.PBAP_CLIENT],
     96             BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
     97         bt_test_utils.set_profile_priority(
     98             self.pce, self.pse2, [BtEnum.BluetoothProfile.PBAP_CLIENT],
     99             BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
    100 
    101         return True
    102 
    103     def setup_test(self):
    104         if not super(BtCarPbapTest, self).setup_test():
    105             return False
    106         self.pse.droid.callLogsEraseAll()
    107         if not (bt_contacts_utils.erase_contacts(self.pse) and
    108                 bt_contacts_utils.erase_contacts(self.pce)):
    109             return False
    110         # Allow all content providers to synchronize.
    111         time.sleep(1)
    112         return True
    113 
    114     def teardown_test(self):
    115         if not super(BtCarPbapTest, self).teardown_test():
    116             return False
    117         self.pce.droid.bluetoothPbapClientDisconnect(
    118             self.pse.droid.bluetoothGetLocalAddress())
    119         bt_contacts_utils.erase_contacts(self.pse)
    120         return True
    121 
    122     def verify_contacts_match(self):
    123         bt_contacts_utils.export_device_contacts_to_vcf(
    124             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    125         return bt_contacts_utils.count_contacts_with_differences(
    126             self.contacts_destination_path, PCE_CONTACTS_FILE,
    127             PSE_CONTACTS_FILE) == 0
    128 
    129     def connect_and_verify(self, count):
    130         bt_test_utils.connect_pri_to_sec(
    131             self.pce, self.pse,
    132             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    133         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
    134                                                                 count)
    135         contacts_added = self.verify_contacts_match()
    136         self.pce.droid.bluetoothPbapClientDisconnect(
    137             self.pse.droid.bluetoothGetLocalAddress())
    138         contacts_removed = bt_contacts_utils.wait_for_phone_number_update_complete(
    139             self.pce, 0)
    140         return contacts_added and contacts_removed
    141 
    142     #@BluetoothTest(UUID=7dcdecfc-42d1-4f41-b66e-823c8f161356)
    143     @BluetoothBaseTest.bt_test_wrap
    144     def test_pbap_connect_and_disconnect(self):
    145         """Test Connectivity
    146 
    147         Test connecting with the server enabled and disabled
    148 
    149         Precondition:
    150         1. Devices are paired.
    151 
    152         Steps:
    153         1. Disable permission on PSE to prevent PCE from connecting
    154         2. Attempt to connect PCE to PSE
    155         3. Verify connection failed
    156         4. Enable permission on PSE to allow PCE to connect
    157         5. Attempt to connect PCE to PSE
    158         6. Verify connection succeeded
    159 
    160         Returns:
    161             Pass if True
    162             Fail if False
    163         """
    164         self.pse.droid.bluetoothChangeProfileAccessPermission(
    165             self.pce.droid.bluetoothGetLocalAddress(),
    166             BtEnum.BluetoothProfile.PBAP_SERVER.value,
    167             BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
    168         if bt_test_utils.connect_pri_to_sec(
    169                 self.pce, self.pse,
    170                 set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
    171             self.log.error("Client connected and shouldn't be.")
    172             return False
    173 
    174         self.pce.droid.bluetoothPbapClientDisconnect(
    175             self.pse.droid.bluetoothGetLocalAddress())
    176 
    177         self.pse.droid.bluetoothChangeProfileAccessPermission(
    178             self.pce.droid.bluetoothGetLocalAddress(),
    179             BtEnum.BluetoothProfile.PBAP_SERVER.value,
    180             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
    181 
    182         if not bt_test_utils.connect_pri_to_sec(
    183                 self.pce, self.pse,
    184                 set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
    185             self.log.error("No client connected and should be.")
    186             return False
    187 
    188         return True
    189 
    190     #@BluetoothTest(UUID=1733efb9-71af-4956-bd3a-0d3167d94d0c)
    191     @BluetoothBaseTest.bt_test_wrap
    192     def test_contact_download(self):
    193         """Test Contact Download
    194 
    195         Test download of contacts from a clean state.
    196 
    197         Precondition:
    198         1. Devices are paired.
    199 
    200         Steps:
    201         1. Erase contacts from PSE and PCE.
    202         2. Add a predefined list of contacts to PSE.
    203         3. Connect PCE to PSE to perform transfer.
    204         4. Compare transfered contacts.
    205         5. Disconnect.
    206         6. Verify PCE cleaned up contact list.
    207 
    208         Returns:
    209             Pass if True
    210             Fail if False
    211         """
    212         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    213                                                 PSE_CONTACTS_FILE, 100)
    214         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    215             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    216         bt_test_utils.connect_pri_to_sec(
    217             self.pce, self.pse,
    218             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    219         bt_contacts_utils.wait_for_phone_number_update_complete(
    220             self.pce, phone_numbers_added)
    221         if not self.verify_contacts_match():
    222             return False
    223         return bt_contacts_utils.erase_contacts(self.pce)
    224 
    225     #@BluetoothTest(UUID=99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664)
    226     @BluetoothBaseTest.bt_test_wrap
    227     def test_modify_phonebook(self):
    228         """Test Modify Phonebook
    229 
    230         Test changing contacts and reconnecting PBAP.
    231 
    232         Precondition:
    233         1. Devices are paired.
    234 
    235         Steps:
    236         1. Add a predefined list of contacts to PSE.
    237         2. Connect PCE to PSE to perform transfer.
    238         3. Verify that contacts match.
    239         4. Change some contacts on the PSE.
    240         5. Reconnect PCE to PSE to perform transfer.
    241         6. Verify that new contacts match.
    242 
    243         Returns:
    244             Pass if True
    245             Fail if False
    246         """
    247         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    248                                                 PSE_CONTACTS_FILE, 100)
    249         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    250             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    251         if not self.connect_and_verify(phone_numbers_added):
    252             return False
    253 
    254         bt_contacts_utils.erase_contacts(self.pse)
    255         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    256                                                 PSE_CONTACTS_FILE, 110, 2)
    257         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    258             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    259         return self.connect_and_verify(phone_numbers_added)
    260 
    261     #@BluetoothTest(UUID=bbe31bf5-51e8-4175-b266-1c7750e44f5b)
    262     @BluetoothBaseTest.bt_test_wrap
    263     def test_special_contacts(self):
    264         """Test Special Contacts
    265 
    266         Test numerous special cases of contacts that could cause errors.
    267 
    268         Precondition:
    269         1. Devices are paired.
    270 
    271         Steps:
    272         1. Add a predefined list of contacts to PSE that includes special cases:
    273         2. Connect PCE to PSE to perform transfer.
    274         3. Verify that contacts match.
    275 
    276         Returns:
    277             Pass if True
    278             Fail if False
    279         """
    280 
    281         vcards = []
    282 
    283         # Generate a contact with no email address
    284         current_contact = bt_contacts_utils.VCard()
    285         current_contact.first_name = "Mr."
    286         current_contact.last_name = "Smiley"
    287         current_contact.add_phone_number(
    288             bt_contacts_utils.generate_random_phone_number())
    289         vcards.append(current_contact)
    290 
    291         # Generate a 2nd contact with the same name but different phone number
    292         current_contact = bt_contacts_utils.VCard()
    293         current_contact.first_name = "Mr."
    294         current_contact.last_name = "Smiley"
    295         current_contact.add_phone_number(
    296             bt_contacts_utils.generate_random_phone_number())
    297         vcards.append(current_contact)
    298 
    299         # Generate a contact with no name
    300         current_contact = bt_contacts_utils.VCard()
    301         current_contact.email = "{}@gmail.com".format(
    302             bt_contacts_utils.generate_random_string())
    303         current_contact.add_phone_number(
    304             bt_contacts_utils.generate_random_phone_number())
    305         vcards.append(current_contact)
    306 
    307         # Generate a contact with random characters in its name
    308         current_contact = bt_contacts_utils.VCard()
    309         current_contact.first_name = bt_contacts_utils.generate_random_string()
    310         current_contact.last_name = bt_contacts_utils.generate_random_string()
    311         current_contact.add_phone_number(
    312             bt_contacts_utils.generate_random_phone_number())
    313         vcards.append(current_contact)
    314 
    315         # Generate a contact with only a phone number
    316         current_contact = bt_contacts_utils.VCard()
    317         current_contact.add_phone_number(
    318             bt_contacts_utils.generate_random_phone_number())
    319         vcards.append(current_contact)
    320 
    321         # Generate a 2nd contact with only a phone number
    322         current_contact = bt_contacts_utils.VCard()
    323         current_contact.add_phone_number(
    324             bt_contacts_utils.generate_random_phone_number())
    325         vcards.append(current_contact)
    326 
    327         bt_contacts_utils.create_new_contacts_vcf_from_vcards(
    328             self.contacts_destination_path, PSE_CONTACTS_FILE, vcards)
    329 
    330         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    331             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    332 
    333         return self.connect_and_verify(phone_numbers_added)
    334 
    335     #@BluetoothTest(UUID=2aa2bd00-86cc-4f39-a06a-90b17ea5b320)
    336     @BluetoothBaseTest.bt_test_wrap
    337     def test_call_log(self):
    338         """Test Call Log
    339 
    340         Test that Call Logs are transfered
    341 
    342         Precondition:
    343         1. Devices are paired.
    344 
    345         Steps:
    346         1. Add a predefined list of calls to the PSE call log.
    347         2. Connect PCE to PSE to allow call log transfer
    348         3. Verify the Missed, Incoming, and Outgoing Call History
    349 
    350         Returns:
    351             Pass if True
    352             Fail if False
    353         """
    354 
    355         bt_contacts_utils.add_call_log(
    356             self.pse, bt_contacts_utils.INCOMMING_CALL_TYPE,
    357             bt_contacts_utils.generate_random_phone_number().phone_number,
    358             int(time.time() * 1000))
    359         bt_contacts_utils.add_call_log(
    360             self.pse, bt_contacts_utils.INCOMMING_CALL_TYPE,
    361             bt_contacts_utils.generate_random_phone_number().phone_number,
    362             int(time.time()) * 1000 - 4 * CALL_LOG_TIME_OFFSET_IN_MSEC)
    363         bt_contacts_utils.add_call_log(
    364             self.pse, bt_contacts_utils.OUTGOING_CALL_TYPE,
    365             bt_contacts_utils.generate_random_phone_number().phone_number,
    366             int(time.time()) * 1000 - CALL_LOG_TIME_OFFSET_IN_MSEC)
    367         bt_contacts_utils.add_call_log(
    368             self.pse, bt_contacts_utils.MISSED_CALL_TYPE,
    369             bt_contacts_utils.generate_random_phone_number().phone_number,
    370             int(time.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
    371         bt_contacts_utils.add_call_log(
    372             self.pse, bt_contacts_utils.MISSED_CALL_TYPE,
    373             bt_contacts_utils.generate_random_phone_number().phone_number,
    374             int(time.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
    375 
    376         self.pce.droid.bluetoothPbapClientDisconnect(
    377             self.pse.droid.bluetoothGetLocalAddress())
    378         self.pce.droid.bluetoothPbapClientDisconnect(
    379             self.pse2.droid.bluetoothGetLocalAddress())
    380 
    381         bt_test_utils.connect_pri_to_sec(
    382             self.pce, self.pse,
    383             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    384         pse_call_log_count = self.pse.droid.callLogGetCount()
    385         self.log.info("Waiting for {} call logs to be transfered".format(
    386             pse_call_log_count))
    387         bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
    388                                                             pse_call_log_count)
    389 
    390         if not bt_contacts_utils.get_and_compare_call_logs(
    391                 self.pse, self.pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
    392             return False
    393         if not bt_contacts_utils.get_and_compare_call_logs(
    394                 self.pse, self.pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
    395             return False
    396         if not bt_contacts_utils.get_and_compare_call_logs(
    397                 self.pse, self.pce, bt_contacts_utils.MISSED_CALL_TYPE):
    398             return False
    399 
    400         return True
    401 
    402     def test_multiple_phones(self):
    403         """Test Multiple Phones
    404 
    405         Test that connects two phones and confirms contacts are transfered
    406         and merged while still being associated with their original phone.
    407 
    408         Precondition:
    409         1. Devices are paired.
    410 
    411         Steps:
    412         1. Add a unique list of contacts to PSE on each phone.
    413         2. Connect PCE to PSE 1 to perform transfer.
    414         3. Verify contacts match.
    415         4. Connect PCE to PSE 2 to perform transfer.
    416         5. Verify that the PCE has a union set of contacts from
    417            PSE 1 and PSE 2.
    418         6. Disconnect PCE from PSE 1 to clean up contacts.
    419         7. Verify that only PSE 2 contacts remain on PCE and they match.
    420         8. Disconnect PCE from PSE 2 to clean up contacts.
    421 
    422         Returns:
    423            Pass if True
    424            Fail if False
    425         """
    426 
    427         PSE1_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "1")
    428         PSE2_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "2")
    429 
    430         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    431                                                 PSE1_CONTACTS_FILE, 100)
    432         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    433             self.pse, self.contacts_destination_path, PSE1_CONTACTS_FILE)
    434         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    435                                                 PSE2_CONTACTS_FILE, 100)
    436         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    437             self.pse2, self.contacts_destination_path, PSE2_CONTACTS_FILE)
    438 
    439         self.pce.droid.bluetoothPbapClientDisconnect(
    440             self.pse.droid.bluetoothGetLocalAddress())
    441         self.pce.droid.bluetoothPbapClientDisconnect(
    442             self.pse2.droid.bluetoothGetLocalAddress())
    443 
    444         bt_test_utils.connect_pri_to_sec(
    445             self.pce, self.pse,
    446             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    447         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
    448         bt_contacts_utils.export_device_contacts_to_vcf(
    449             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    450         pse1_matches = bt_contacts_utils.count_contacts_with_differences(
    451             self.contacts_destination_path, PCE_CONTACTS_FILE,
    452             PSE1_CONTACTS_FILE) == 0
    453 
    454         bt_test_utils.connect_pri_to_sec(
    455             self.pce, self.pse2,
    456             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    457 
    458         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
    459 
    460         bt_contacts_utils.export_device_contacts_to_vcf(
    461             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    462 
    463         merged_file = open('{}{}'.format(self.contacts_destination_path,
    464                                          MERGED_CONTACTS_FILE), 'w')
    465         for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
    466             infile = open(self.contacts_destination_path + contacts_file)
    467             merged_file.write(infile.read())
    468 
    469         self.log.info("Checking combined phonebook.")
    470         pse1andpse2_matches = bt_contacts_utils.count_contacts_with_differences(
    471             self.contacts_destination_path, PCE_CONTACTS_FILE,
    472             MERGED_CONTACTS_FILE) == 0
    473 
    474         self.pce.droid.bluetoothPbapClientDisconnect(
    475             self.pse.droid.bluetoothGetLocalAddress())
    476         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
    477 
    478         self.log.info("Checking phonebook after disconnecting first device.")
    479         bt_contacts_utils.export_device_contacts_to_vcf(
    480             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    481         pse2_matches = bt_contacts_utils.count_contacts_with_differences(
    482             self.contacts_destination_path, PCE_CONTACTS_FILE,
    483             PSE2_CONTACTS_FILE) == 0
    484 
    485         bt_contacts_utils.erase_contacts(self.pse)
    486         bt_contacts_utils.erase_contacts(self.pse2)
    487         return pse1_matches and pse2_matches and pse1andpse2_matches
    488