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 permission in permissions_list:
     59             self.pse.adb.shell(
     60                 "pm grant com.google.android.contacts {}".format(permission))
     61         for permission in permissions_list:
     62             self.pce.adb.shell("pm grant com.android.contacts {}".format(
     63                 permission))
     64 
     65         # Pair the devices.
     66         # This call may block until some specified timeout in bt_test_utils.py.
     67         # Grace time inbetween stack state changes
     68 
     69         setup_multiple_devices_for_bt_test(self.android_devices)
     70         if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
     71             self.log.error("Failed to pair.")
     72             return False
     73         time.sleep(3)
     74         if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
     75             self.log.error("Failed to pair.")
     76             return False
     77 
     78         # Disable the HFP and A2DP profiles. This will ensure only PBAP
     79         # gets connected. Also, this will eliminate the auto-connect loop.
     80         car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
     81         car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
     82 
     83         # Enable PBAP on PSE & PCE.
     84 
     85         self.pse.droid.bluetoothChangeProfileAccessPermission(
     86             self.pce.droid.bluetoothGetLocalAddress(),
     87             BtEnum.BluetoothProfile.PBAP_SERVER.value,
     88             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
     89 
     90         self.pse2.droid.bluetoothChangeProfileAccessPermission(
     91             self.pce.droid.bluetoothGetLocalAddress(),
     92             BtEnum.BluetoothProfile.PBAP_SERVER.value,
     93             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
     94 
     95         bt_test_utils.set_profile_priority(
     96             self.pce, self.pse, [BtEnum.BluetoothProfile.PBAP_CLIENT],
     97             BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
     98         bt_test_utils.set_profile_priority(
     99             self.pce, self.pse2, [BtEnum.BluetoothProfile.PBAP_CLIENT],
    100             BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
    101 
    102         return True
    103 
    104     def setup_test(self):
    105         if not super(BtCarPbapTest, self).setup_test():
    106             return False
    107         self.pse.droid.callLogsEraseAll()
    108         if not (bt_contacts_utils.erase_contacts(self.pse) and
    109                 bt_contacts_utils.erase_contacts(self.pce)):
    110             return False
    111         # Allow all content providers to synchronize.
    112         time.sleep(1)
    113         return True
    114 
    115     def teardown_test(self):
    116         if not super(BtCarPbapTest, self).teardown_test():
    117             return False
    118         self.pce.droid.bluetoothPbapClientDisconnect(
    119             self.pse.droid.bluetoothGetLocalAddress())
    120         bt_contacts_utils.erase_contacts(self.pse)
    121         return True
    122 
    123     def verify_contacts_match(self):
    124         bt_contacts_utils.export_device_contacts_to_vcf(
    125             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    126         return bt_contacts_utils.count_contacts_with_differences(
    127             self.contacts_destination_path, PCE_CONTACTS_FILE,
    128             PSE_CONTACTS_FILE) == 0
    129 
    130     def connect_and_verify(self, count):
    131         bt_test_utils.connect_pri_to_sec(
    132             self.pce, self.pse,
    133             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    134         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
    135                                                                 count)
    136         contacts_added = self.verify_contacts_match()
    137         self.pce.droid.bluetoothPbapClientDisconnect(
    138             self.pse.droid.bluetoothGetLocalAddress())
    139         contacts_removed = bt_contacts_utils.wait_for_phone_number_update_complete(
    140             self.pce, 0)
    141         return contacts_added and contacts_removed
    142 
    143     @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    144     @BluetoothBaseTest.bt_test_wrap
    145     def test_pbap_connect_and_disconnect(self):
    146         """Test Connectivity
    147 
    148         Test connecting with the server enabled and disabled
    149 
    150         Precondition:
    151         1. Devices are paired.
    152 
    153         Steps:
    154         1. Disable permission on PSE to prevent PCE from connecting
    155         2. Attempt to connect PCE to PSE
    156         3. Verify connection failed
    157         4. Enable permission on PSE to allow PCE to connect
    158         5. Attempt to connect PCE to PSE
    159         6. Verify connection succeeded
    160 
    161         Returns:
    162             Pass if True
    163             Fail if False
    164         """
    165         self.pse.droid.bluetoothChangeProfileAccessPermission(
    166             self.pce.droid.bluetoothGetLocalAddress(),
    167             BtEnum.BluetoothProfile.PBAP_SERVER.value,
    168             BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
    169         if bt_test_utils.connect_pri_to_sec(
    170                 self.pce, self.pse,
    171                 set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
    172             self.log.error("Client connected and shouldn't be.")
    173             return False
    174 
    175         self.pce.droid.bluetoothPbapClientDisconnect(
    176             self.pse.droid.bluetoothGetLocalAddress())
    177 
    178         self.pse.droid.bluetoothChangeProfileAccessPermission(
    179             self.pce.droid.bluetoothGetLocalAddress(),
    180             BtEnum.BluetoothProfile.PBAP_SERVER.value,
    181             BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)
    182 
    183         if not bt_test_utils.connect_pri_to_sec(
    184                 self.pce, self.pse,
    185                 set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
    186             self.log.error("No client connected and should be.")
    187             return False
    188 
    189         return True
    190 
    191     @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    192     @BluetoothBaseTest.bt_test_wrap
    193     def test_contact_download(self):
    194         """Test Contact Download
    195 
    196         Test download of contacts from a clean state.
    197 
    198         Precondition:
    199         1. Devices are paired.
    200 
    201         Steps:
    202         1. Erase contacts from PSE and PCE.
    203         2. Add a predefined list of contacts to PSE.
    204         3. Connect PCE to PSE to perform transfer.
    205         4. Compare transfered contacts.
    206         5. Disconnect.
    207         6. Verify PCE cleaned up contact list.
    208 
    209         Returns:
    210             Pass if True
    211             Fail if False
    212         """
    213         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    214                                                 PSE_CONTACTS_FILE, 100)
    215         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    216             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    217         bt_test_utils.connect_pri_to_sec(
    218             self.pce, self.pse,
    219             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    220         bt_contacts_utils.wait_for_phone_number_update_complete(
    221             self.pce, phone_numbers_added)
    222         if not self.verify_contacts_match():
    223             return False
    224         return bt_contacts_utils.erase_contacts(self.pce)
    225 
    226     @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    227     @BluetoothBaseTest.bt_test_wrap
    228     def test_modify_phonebook(self):
    229         """Test Modify Phonebook
    230 
    231         Test changing contacts and reconnecting PBAP.
    232 
    233         Precondition:
    234         1. Devices are paired.
    235 
    236         Steps:
    237         1. Add a predefined list of contacts to PSE.
    238         2. Connect PCE to PSE to perform transfer.
    239         3. Verify that contacts match.
    240         4. Change some contacts on the PSE.
    241         5. Reconnect PCE to PSE to perform transfer.
    242         6. Verify that new contacts match.
    243 
    244         Returns:
    245             Pass if True
    246             Fail if False
    247         """
    248         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    249                                                 PSE_CONTACTS_FILE, 100)
    250         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    251             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    252         if not self.connect_and_verify(phone_numbers_added):
    253             return False
    254 
    255         bt_contacts_utils.erase_contacts(self.pse)
    256         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    257                                                 PSE_CONTACTS_FILE, 110, 2)
    258         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    259             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    260         return self.connect_and_verify(phone_numbers_added)
    261 
    262     @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    263     @BluetoothBaseTest.bt_test_wrap
    264     def test_special_contacts(self):
    265         """Test Special Contacts
    266 
    267         Test numerous special cases of contacts that could cause errors.
    268 
    269         Precondition:
    270         1. Devices are paired.
    271 
    272         Steps:
    273         1. Add a predefined list of contacts to PSE that includes special cases:
    274         2. Connect PCE to PSE to perform transfer.
    275         3. Verify that contacts match.
    276 
    277         Returns:
    278             Pass if True
    279             Fail if False
    280         """
    281 
    282         vcards = []
    283 
    284         # Generate a contact with no email address
    285         current_contact = bt_contacts_utils.VCard()
    286         current_contact.first_name = "Mr."
    287         current_contact.last_name = "Smiley"
    288         current_contact.add_phone_number(
    289             bt_contacts_utils.generate_random_phone_number())
    290         vcards.append(current_contact)
    291 
    292         # Generate a 2nd contact with the same name but different phone number
    293         current_contact = bt_contacts_utils.VCard()
    294         current_contact.first_name = "Mr."
    295         current_contact.last_name = "Smiley"
    296         current_contact.add_phone_number(
    297             bt_contacts_utils.generate_random_phone_number())
    298         vcards.append(current_contact)
    299 
    300         # Generate a contact with no name
    301         current_contact = bt_contacts_utils.VCard()
    302         current_contact.email = "{}@gmail.com".format(
    303             bt_contacts_utils.generate_random_string())
    304         current_contact.add_phone_number(
    305             bt_contacts_utils.generate_random_phone_number())
    306         vcards.append(current_contact)
    307 
    308         # Generate a contact with random characters in its name
    309         current_contact = bt_contacts_utils.VCard()
    310         current_contact.first_name = bt_contacts_utils.generate_random_string()
    311         current_contact.last_name = bt_contacts_utils.generate_random_string()
    312         current_contact.add_phone_number(
    313             bt_contacts_utils.generate_random_phone_number())
    314         vcards.append(current_contact)
    315 
    316         # Generate a contact with only a phone number
    317         current_contact = bt_contacts_utils.VCard()
    318         current_contact.add_phone_number(
    319             bt_contacts_utils.generate_random_phone_number())
    320         vcards.append(current_contact)
    321 
    322         # Generate a 2nd contact with only a phone number
    323         current_contact = bt_contacts_utils.VCard()
    324         current_contact.add_phone_number(
    325             bt_contacts_utils.generate_random_phone_number())
    326         vcards.append(current_contact)
    327 
    328         bt_contacts_utils.create_new_contacts_vcf_from_vcards(
    329             self.contacts_destination_path, PSE_CONTACTS_FILE, vcards)
    330 
    331         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    332             self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
    333 
    334         return self.connect_and_verify(phone_numbers_added)
    335 
    336     @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    337     @BluetoothBaseTest.bt_test_wrap
    338     def test_call_log(self):
    339         """Test Call Log
    340 
    341         Test that Call Logs are transfered
    342 
    343         Precondition:
    344         1. Devices are paired.
    345 
    346         Steps:
    347         1. Add a predefined list of calls to the PSE call log.
    348         2. Connect PCE to PSE to allow call log transfer
    349         3. Verify the Missed, Incoming, and Outgoing Call History
    350 
    351         Returns:
    352             Pass if True
    353             Fail if False
    354         """
    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 
    430         PSE1_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "1")
    431         PSE2_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "2")
    432 
    433         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    434                                                 PSE1_CONTACTS_FILE, 100)
    435         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    436             self.pse, self.contacts_destination_path, PSE1_CONTACTS_FILE)
    437         bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
    438                                                 PSE2_CONTACTS_FILE, 100)
    439         phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
    440             self.pse2, self.contacts_destination_path, PSE2_CONTACTS_FILE)
    441 
    442         self.pce.droid.bluetoothPbapClientDisconnect(
    443             self.pse.droid.bluetoothGetLocalAddress())
    444         self.pce.droid.bluetoothPbapClientDisconnect(
    445             self.pse2.droid.bluetoothGetLocalAddress())
    446 
    447         bt_test_utils.connect_pri_to_sec(
    448             self.pce, self.pse,
    449             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    450         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
    451         bt_contacts_utils.export_device_contacts_to_vcf(
    452             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    453         pse1_matches = bt_contacts_utils.count_contacts_with_differences(
    454             self.contacts_destination_path, PCE_CONTACTS_FILE,
    455             PSE1_CONTACTS_FILE) == 0
    456 
    457         bt_test_utils.connect_pri_to_sec(
    458             self.pce, self.pse2,
    459             set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
    460 
    461         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
    462 
    463         bt_contacts_utils.export_device_contacts_to_vcf(
    464             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    465 
    466         merged_file = open('{}{}'.format(self.contacts_destination_path,
    467                                          MERGED_CONTACTS_FILE), 'w')
    468         for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
    469             infile = open(self.contacts_destination_path + contacts_file)
    470             merged_file.write(infile.read())
    471 
    472         self.log.info("Checking combined phonebook.")
    473         pse1andpse2_matches = bt_contacts_utils.count_contacts_with_differences(
    474             self.contacts_destination_path, PCE_CONTACTS_FILE,
    475             MERGED_CONTACTS_FILE) == 0
    476 
    477         self.pce.droid.bluetoothPbapClientDisconnect(
    478             self.pse.droid.bluetoothGetLocalAddress())
    479         bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
    480 
    481         self.log.info("Checking phonebook after disconnecting first device.")
    482         bt_contacts_utils.export_device_contacts_to_vcf(
    483             self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
    484         pse2_matches = bt_contacts_utils.count_contacts_with_differences(
    485             self.contacts_destination_path, PCE_CONTACTS_FILE,
    486             PSE2_CONTACTS_FILE) == 0
    487 
    488         bt_contacts_utils.erase_contacts(self.pse)
    489         bt_contacts_utils.erase_contacts(self.pse2)
    490         return pse1_matches and pse2_matches and pse1andpse2_matches
    491