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