#/usr/bin/env python3.4
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Test script to test PBAP contact download between two devices which can run SL4A.
"""

import os
import time

from acts.test_decorators import test_tracker_info
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
from acts.base_test import BaseTestClass
from acts.test_utils.bt import bt_contacts_utils
from acts.test_utils.bt import bt_test_utils
from acts.test_utils.car import car_bt_utils
from acts.utils import exe_cmd
import acts.test_utils.bt.BtEnum as BtEnum

# Offset call logs by 1 minute
CALL_LOG_TIME_OFFSET_IN_MSEC = 60000
PSE_CONTACTS_FILE = "psecontacts.vcf"
PCE_CONTACTS_FILE = "pcecontacts.vcf"
MERGED_CONTACTS_FILE = "psecombined.vcf"
STANDART_CONTACT_COUNT = 100


class BtCarPbapTest(BluetoothBaseTest):
    contacts_destination_path = ""

    def __init__(self, controllers):
        BaseTestClass.__init__(self, controllers)
        self.pce = self.android_devices[0]
        self.pse = self.android_devices[1]
        self.pse2 = self.android_devices[2]
        self.contacts_destination_path = self.log_path + "/"

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = [
            "android.permission.READ_CONTACTS",
            "android.permission.WRITE_CONTACTS",
            "android.permission.READ_EXTERNAL_STORAGE"
        ]
        for permission in permissions_list:
            self.pse.adb.shell(
                "pm grant com.google.android.contacts {}".format(permission))
        for permission in permissions_list:
            self.pce.adb.shell("pm grant com.android.contacts {}".format(
                permission))

        # Pair the devices.
        # This call may block until some specified timeout in bt_test_utils.py.
        # Grace time inbetween stack state changes

        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error("Failed to pair.")
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error("Failed to pair.")
            return False

        # Disable the HFP and A2DP profiles. This will ensure only PBAP
        # gets connected. Also, this will eliminate the auto-connect loop.
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)

        # Enable PBAP on PSE & PCE.

        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        self.pse2.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        bt_test_utils.set_profile_priority(
            self.pce, self.pse, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
        bt_test_utils.set_profile_priority(
            self.pce, self.pse2, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)

        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
                bt_contacts_utils.erase_contacts(self.pce)):
            return False
        # Allow all content providers to synchronize.
        time.sleep(1)
        return True

    def teardown_test(self):
        if not super(BtCarPbapTest, self).teardown_test():
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        bt_contacts_utils.erase_contacts(self.pse)
        return True

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE_CONTACTS_FILE) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
                                                                count)
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        contacts_removed = bt_contacts_utils.wait_for_phone_number_update_complete(
            self.pce, 0)
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(
                self.pce, self.pse,
                set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())

        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        if not bt_test_utils.connect_pri_to_sec(
                self.pce, self.pse,
                set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("No client connected and should be.")
            return False

        return True

    @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    @BluetoothBaseTest.bt_test_wrap
    def test_contact_download(self):
        """Test Contact Download

        Test download of contacts from a clean state.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Erase contacts from PSE and PCE.
        2. Add a predefined list of contacts to PSE.
        3. Connect PCE to PSE to perform transfer.
        4. Compare transfered contacts.
        5. Disconnect.
        6. Verify PCE cleaned up contact list.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(
            self.pce, phone_numbers_added)
        if not self.verify_contacts_match():
            return False
        return bt_contacts_utils.erase_contacts(self.pce)

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        if not self.connect_and_verify(phone_numbers_added):
            return False

        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """

        vcards = []

        # Generate a contact with no email address
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = "Mr."
        current_contact.last_name = "Smiley"
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a 2nd contact with the same name but different phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = "Mr."
        current_contact.last_name = "Smiley"
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with no name
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = "{}@gmail.com".format(
            bt_contacts_utils.generate_random_string())
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with random characters in its name
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with only a phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a 2nd contact with only a phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        bt_contacts_utils.create_new_contacts_vcf_from_vcards(
            self.contacts_destination_path, PSE_CONTACTS_FILE, vcards)

        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)

        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """

        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.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.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.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.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.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse2.droid.bluetoothGetLocalAddress())

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info("Waiting for {} call logs to be transfered".format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
                                                            pse_call_log_count)

        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False

        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """

        PSE1_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "1")
        PSE2_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "2")

        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE1_CONTACTS_FILE)
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse2, self.contacts_destination_path, PSE2_CONTACTS_FILE)

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse2.droid.bluetoothGetLocalAddress())

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE1_CONTACTS_FILE) == 0

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse2,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))

        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)

        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)

        merged_file = open('{}{}'.format(self.contacts_destination_path,
                                         MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())

        self.log.info("Checking combined phonebook.")
        pse1andpse2_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            MERGED_CONTACTS_FILE) == 0

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)

        self.log.info("Checking phonebook after disconnecting first device.")
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE2_CONTACTS_FILE) == 0

        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches

5fa77c1a658f4e0ad8bd6d85b3d788454f7a1fb6
<mask token>


class BtCarPbapTest(BluetoothBaseTest):
    <mask token>
    <mask token>

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = ['android.permission.READ_CONTACTS',
            'android.permission.WRITE_CONTACTS',
            'android.permission.READ_EXTERNAL_STORAGE']
        for permission in permissions_list:
            self.pse.adb.shell('pm grant com.google.android.contacts {}'.
                format(permission))
        for permission in permissions_list:
            self.pce.adb.shell('pm grant com.android.contacts {}'.format(
                permission))
        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error('Failed to pair.')
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error('Failed to pair.')
            return False
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        self.pse2.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        bt_test_utils.set_profile_priority(self.pce, self.pse, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        bt_test_utils.set_profile_priority(self.pce, self.pse2, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
            bt_contacts_utils.erase_contacts(self.pce)):
            return False
        time.sleep(1)
        return True
    <mask token>

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(self.
            contacts_destination_path, PCE_CONTACTS_FILE, PSE_CONTACTS_FILE
            ) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, count
            )
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        contacts_removed = (bt_contacts_utils.
            wait_for_phone_number_update_complete(self.pce, 0))
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum
            .BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        if not bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([
            BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error('No client connected and should be.')
            return False
        return True
    <mask token>

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        if not self.connect_and_verify(phone_numbers_added):
            return False
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        vcards = []
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = '{}@gmail.com'.format(bt_contacts_utils.
            generate_random_string())
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        bt_contacts_utils.create_new_contacts_vcf_from_vcards(self.
            contacts_destination_path, PSE_CONTACTS_FILE, vcards)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """
        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.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.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.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.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.time()) *
            1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info('Waiting for {} call logs to be transfered'.format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
            pse_call_log_count)
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False
        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """
        PSE1_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '1')
        PSE2_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '2')
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE1_CONTACTS_FILE))
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse2, self.
            contacts_destination_path, PSE2_CONTACTS_FILE))
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE1_CONTACTS_FILE
            ) == 0
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse2, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        merged_file = open('{}{}'.format(self.contacts_destination_path,
            MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())
        self.log.info('Checking combined phonebook.')
        pse1andpse2_matches = (bt_contacts_utils.
            count_contacts_with_differences(self.contacts_destination_path,
            PCE_CONTACTS_FILE, MERGED_CONTACTS_FILE) == 0)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        self.log.info('Checking phonebook after disconnecting first device.')
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE2_CONTACTS_FILE
            ) == 0
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches

<mask token>


class BtCarPbapTest(BluetoothBaseTest):
    <mask token>
    <mask token>

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = ['android.permission.READ_CONTACTS',
            'android.permission.WRITE_CONTACTS',
            'android.permission.READ_EXTERNAL_STORAGE']
        for permission in permissions_list:
            self.pse.adb.shell('pm grant com.google.android.contacts {}'.
                format(permission))
        for permission in permissions_list:
            self.pce.adb.shell('pm grant com.android.contacts {}'.format(
                permission))
        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error('Failed to pair.')
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error('Failed to pair.')
            return False
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        self.pse2.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        bt_test_utils.set_profile_priority(self.pce, self.pse, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        bt_test_utils.set_profile_priority(self.pce, self.pse2, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
            bt_contacts_utils.erase_contacts(self.pce)):
            return False
        time.sleep(1)
        return True
    <mask token>

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(self.
            contacts_destination_path, PCE_CONTACTS_FILE, PSE_CONTACTS_FILE
            ) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, count
            )
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        contacts_removed = (bt_contacts_utils.
            wait_for_phone_number_update_complete(self.pce, 0))
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum
            .BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        if not bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([
            BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error('No client connected and should be.')
            return False
        return True

    @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    @BluetoothBaseTest.bt_test_wrap
    def test_contact_download(self):
        """Test Contact Download

        Test download of contacts from a clean state.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Erase contacts from PSE and PCE.
        2. Add a predefined list of contacts to PSE.
        3. Connect PCE to PSE to perform transfer.
        4. Compare transfered contacts.
        5. Disconnect.
        6. Verify PCE cleaned up contact list.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
            phone_numbers_added)
        if not self.verify_contacts_match():
            return False
        return bt_contacts_utils.erase_contacts(self.pce)

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        if not self.connect_and_verify(phone_numbers_added):
            return False
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        vcards = []
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = '{}@gmail.com'.format(bt_contacts_utils.
            generate_random_string())
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        bt_contacts_utils.create_new_contacts_vcf_from_vcards(self.
            contacts_destination_path, PSE_CONTACTS_FILE, vcards)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """
        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.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.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.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.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.time()) *
            1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info('Waiting for {} call logs to be transfered'.format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
            pse_call_log_count)
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False
        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """
        PSE1_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '1')
        PSE2_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '2')
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE1_CONTACTS_FILE))
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse2, self.
            contacts_destination_path, PSE2_CONTACTS_FILE))
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE1_CONTACTS_FILE
            ) == 0
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse2, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        merged_file = open('{}{}'.format(self.contacts_destination_path,
            MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())
        self.log.info('Checking combined phonebook.')
        pse1andpse2_matches = (bt_contacts_utils.
            count_contacts_with_differences(self.contacts_destination_path,
            PCE_CONTACTS_FILE, MERGED_CONTACTS_FILE) == 0)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        self.log.info('Checking phonebook after disconnecting first device.')
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE2_CONTACTS_FILE
            ) == 0
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches

<mask token>


class BtCarPbapTest(BluetoothBaseTest):
    <mask token>

    def __init__(self, controllers):
        BaseTestClass.__init__(self, controllers)
        self.pce = self.android_devices[0]
        self.pse = self.android_devices[1]
        self.pse2 = self.android_devices[2]
        self.contacts_destination_path = self.log_path + '/'

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = ['android.permission.READ_CONTACTS',
            'android.permission.WRITE_CONTACTS',
            'android.permission.READ_EXTERNAL_STORAGE']
        for permission in permissions_list:
            self.pse.adb.shell('pm grant com.google.android.contacts {}'.
                format(permission))
        for permission in permissions_list:
            self.pce.adb.shell('pm grant com.android.contacts {}'.format(
                permission))
        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error('Failed to pair.')
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error('Failed to pair.')
            return False
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        self.pse2.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        bt_test_utils.set_profile_priority(self.pce, self.pse, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        bt_test_utils.set_profile_priority(self.pce, self.pse2, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
            bt_contacts_utils.erase_contacts(self.pce)):
            return False
        time.sleep(1)
        return True
    <mask token>

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(self.
            contacts_destination_path, PCE_CONTACTS_FILE, PSE_CONTACTS_FILE
            ) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, count
            )
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        contacts_removed = (bt_contacts_utils.
            wait_for_phone_number_update_complete(self.pce, 0))
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum
            .BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        if not bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([
            BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error('No client connected and should be.')
            return False
        return True

    @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    @BluetoothBaseTest.bt_test_wrap
    def test_contact_download(self):
        """Test Contact Download

        Test download of contacts from a clean state.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Erase contacts from PSE and PCE.
        2. Add a predefined list of contacts to PSE.
        3. Connect PCE to PSE to perform transfer.
        4. Compare transfered contacts.
        5. Disconnect.
        6. Verify PCE cleaned up contact list.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
            phone_numbers_added)
        if not self.verify_contacts_match():
            return False
        return bt_contacts_utils.erase_contacts(self.pce)

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        if not self.connect_and_verify(phone_numbers_added):
            return False
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        vcards = []
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = '{}@gmail.com'.format(bt_contacts_utils.
            generate_random_string())
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        bt_contacts_utils.create_new_contacts_vcf_from_vcards(self.
            contacts_destination_path, PSE_CONTACTS_FILE, vcards)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """
        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.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.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.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.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.time()) *
            1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info('Waiting for {} call logs to be transfered'.format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
            pse_call_log_count)
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False
        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """
        PSE1_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '1')
        PSE2_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '2')
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE1_CONTACTS_FILE))
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse2, self.
            contacts_destination_path, PSE2_CONTACTS_FILE))
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE1_CONTACTS_FILE
            ) == 0
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse2, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        merged_file = open('{}{}'.format(self.contacts_destination_path,
            MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())
        self.log.info('Checking combined phonebook.')
        pse1andpse2_matches = (bt_contacts_utils.
            count_contacts_with_differences(self.contacts_destination_path,
            PCE_CONTACTS_FILE, MERGED_CONTACTS_FILE) == 0)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        self.log.info('Checking phonebook after disconnecting first device.')
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE2_CONTACTS_FILE
            ) == 0
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches

<mask token>


class BtCarPbapTest(BluetoothBaseTest):
    <mask token>

    def __init__(self, controllers):
        BaseTestClass.__init__(self, controllers)
        self.pce = self.android_devices[0]
        self.pse = self.android_devices[1]
        self.pse2 = self.android_devices[2]
        self.contacts_destination_path = self.log_path + '/'

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = ['android.permission.READ_CONTACTS',
            'android.permission.WRITE_CONTACTS',
            'android.permission.READ_EXTERNAL_STORAGE']
        for permission in permissions_list:
            self.pse.adb.shell('pm grant com.google.android.contacts {}'.
                format(permission))
        for permission in permissions_list:
            self.pce.adb.shell('pm grant com.android.contacts {}'.format(
                permission))
        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error('Failed to pair.')
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error('Failed to pair.')
            return False
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        self.pse2.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        bt_test_utils.set_profile_priority(self.pce, self.pse, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        bt_test_utils.set_profile_priority(self.pce, self.pse2, [BtEnum.
            BluetoothProfile.PBAP_CLIENT], BtEnum.BluetoothPriorityLevel.
            PRIORITY_ON)
        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
            bt_contacts_utils.erase_contacts(self.pce)):
            return False
        time.sleep(1)
        return True

    def teardown_test(self):
        if not super(BtCarPbapTest, self).teardown_test():
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        bt_contacts_utils.erase_contacts(self.pse)
        return True

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(self.
            contacts_destination_path, PCE_CONTACTS_FILE, PSE_CONTACTS_FILE
            ) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, count
            )
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        contacts_removed = (bt_contacts_utils.
            wait_for_phone_number_update_complete(self.pce, 0))
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum
            .BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pse.droid.bluetoothChangeProfileAccessPermission(self.pce.
            droid.bluetoothGetLocalAddress(), BtEnum.BluetoothProfile.
            PBAP_SERVER.value, BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value
            )
        if not bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([
            BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error('No client connected and should be.')
            return False
        return True

    @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    @BluetoothBaseTest.bt_test_wrap
    def test_contact_download(self):
        """Test Contact Download

        Test download of contacts from a clean state.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Erase contacts from PSE and PCE.
        2. Add a predefined list of contacts to PSE.
        3. Connect PCE to PSE to perform transfer.
        4. Compare transfered contacts.
        5. Disconnect.
        6. Verify PCE cleaned up contact list.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
            phone_numbers_added)
        if not self.verify_contacts_match():
            return False
        return bt_contacts_utils.erase_contacts(self.pce)

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        if not self.connect_and_verify(phone_numbers_added):
            return False
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        vcards = []
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = 'Mr.'
        current_contact.last_name = 'Smiley'
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = '{}@gmail.com'.format(bt_contacts_utils.
            generate_random_string())
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(bt_contacts_utils.
            generate_random_phone_number())
        vcards.append(current_contact)
        bt_contacts_utils.create_new_contacts_vcf_from_vcards(self.
            contacts_destination_path, PSE_CONTACTS_FILE, vcards)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE_CONTACTS_FILE))
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """
        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.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.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.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.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.time()) *
            1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info('Waiting for {} call logs to be transfered'.format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
            pse_call_log_count)
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(self.pse, self.
            pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False
        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """
        PSE1_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '1')
        PSE2_CONTACTS_FILE = '{}{}'.format(PSE_CONTACTS_FILE, '2')
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse, self.
            contacts_destination_path, PSE1_CONTACTS_FILE))
        bt_contacts_utils.generate_contact_list(self.
            contacts_destination_path, PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = (bt_contacts_utils.
            import_device_contacts_from_vcf(self.pse2, self.
            contacts_destination_path, PSE2_CONTACTS_FILE))
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse2.droid.
            bluetoothGetLocalAddress())
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE1_CONTACTS_FILE
            ) == 0
        bt_test_utils.connect_pri_to_sec(self.pce, self.pse2, set([BtEnum.
            BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        merged_file = open('{}{}'.format(self.contacts_destination_path,
            MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())
        self.log.info('Checking combined phonebook.')
        pse1andpse2_matches = (bt_contacts_utils.
            count_contacts_with_differences(self.contacts_destination_path,
            PCE_CONTACTS_FILE, MERGED_CONTACTS_FILE) == 0)
        self.pce.droid.bluetoothPbapClientDisconnect(self.pse.droid.
            bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        self.log.info('Checking phonebook after disconnecting first device.')
        bt_contacts_utils.export_device_contacts_to_vcf(self.pce, self.
            contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(self
            .contacts_destination_path, PCE_CONTACTS_FILE, PSE2_CONTACTS_FILE
            ) == 0
        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches

#/usr/bin/env python3.4
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Test script to test PBAP contact download between two devices which can run SL4A.
"""

import os
import time

from acts.test_decorators import test_tracker_info
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
from acts.base_test import BaseTestClass
from acts.test_utils.bt import bt_contacts_utils
from acts.test_utils.bt import bt_test_utils
from acts.test_utils.car import car_bt_utils
from acts.utils import exe_cmd
import acts.test_utils.bt.BtEnum as BtEnum

# Offset call logs by 1 minute
CALL_LOG_TIME_OFFSET_IN_MSEC = 60000
PSE_CONTACTS_FILE = "psecontacts.vcf"
PCE_CONTACTS_FILE = "pcecontacts.vcf"
MERGED_CONTACTS_FILE = "psecombined.vcf"
STANDART_CONTACT_COUNT = 100


class BtCarPbapTest(BluetoothBaseTest):
    contacts_destination_path = ""

    def __init__(self, controllers):
        BaseTestClass.__init__(self, controllers)
        self.pce = self.android_devices[0]
        self.pse = self.android_devices[1]
        self.pse2 = self.android_devices[2]
        self.contacts_destination_path = self.log_path + "/"

    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        permissions_list = [
            "android.permission.READ_CONTACTS",
            "android.permission.WRITE_CONTACTS",
            "android.permission.READ_EXTERNAL_STORAGE"
        ]
        for permission in permissions_list:
            self.pse.adb.shell(
                "pm grant com.google.android.contacts {}".format(permission))
        for permission in permissions_list:
            self.pce.adb.shell("pm grant com.android.contacts {}".format(
                permission))

        # Pair the devices.
        # This call may block until some specified timeout in bt_test_utils.py.
        # Grace time inbetween stack state changes

        setup_multiple_devices_for_bt_test(self.android_devices)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error("Failed to pair.")
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error("Failed to pair.")
            return False

        # Disable the HFP and A2DP profiles. This will ensure only PBAP
        # gets connected. Also, this will eliminate the auto-connect loop.
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)

        # Enable PBAP on PSE & PCE.

        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        self.pse2.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        bt_test_utils.set_profile_priority(
            self.pce, self.pse, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
        bt_test_utils.set_profile_priority(
            self.pce, self.pse2, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)

        return True

    def setup_test(self):
        if not super(BtCarPbapTest, self).setup_test():
            return False
        self.pse.droid.callLogsEraseAll()
        if not (bt_contacts_utils.erase_contacts(self.pse) and
                bt_contacts_utils.erase_contacts(self.pce)):
            return False
        # Allow all content providers to synchronize.
        time.sleep(1)
        return True

    def teardown_test(self):
        if not super(BtCarPbapTest, self).teardown_test():
            return False
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        bt_contacts_utils.erase_contacts(self.pse)
        return True

    def verify_contacts_match(self):
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        return bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE_CONTACTS_FILE) == 0

    def connect_and_verify(self, count):
        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce,
                                                                count)
        contacts_added = self.verify_contacts_match()
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        contacts_removed = bt_contacts_utils.wait_for_phone_number_update_complete(
            self.pce, 0)
        return contacts_added and contacts_removed

    @test_tracker_info(uuid='7dcdecfc-42d1-4f41-b66e-823c8f161356')
    @BluetoothBaseTest.bt_test_wrap
    def test_pbap_connect_and_disconnect(self):
        """Test Connectivity

        Test connecting with the server enabled and disabled

        Precondition:
        1. Devices are paired.

        Steps:
        1. Disable permission on PSE to prevent PCE from connecting
        2. Attempt to connect PCE to PSE
        3. Verify connection failed
        4. Enable permission on PSE to allow PCE to connect
        5. Attempt to connect PCE to PSE
        6. Verify connection succeeded

        Returns:
            Pass if True
            Fail if False
        """
        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_DENIED.value)
        if bt_test_utils.connect_pri_to_sec(
                self.pce, self.pse,
                set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("Client connected and shouldn't be.")
            return False

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())

        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        if not bt_test_utils.connect_pri_to_sec(
                self.pce, self.pse,
                set([BtEnum.BluetoothProfile.PBAP_CLIENT.value])):
            self.log.error("No client connected and should be.")
            return False

        return True

    @test_tracker_info(uuid='1733efb9-71af-4956-bd3a-0d3167d94d0c')
    @BluetoothBaseTest.bt_test_wrap
    def test_contact_download(self):
        """Test Contact Download

        Test download of contacts from a clean state.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Erase contacts from PSE and PCE.
        2. Add a predefined list of contacts to PSE.
        3. Connect PCE to PSE to perform transfer.
        4. Compare transfered contacts.
        5. Disconnect.
        6. Verify PCE cleaned up contact list.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(
            self.pce, phone_numbers_added)
        if not self.verify_contacts_match():
            return False
        return bt_contacts_utils.erase_contacts(self.pce)

    @test_tracker_info(uuid='99dc6ac6-b7cf-45ce-927b-8c4ebf8ab664')
    @BluetoothBaseTest.bt_test_wrap
    def test_modify_phonebook(self):
        """Test Modify Phonebook

        Test changing contacts and reconnecting PBAP.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE.
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.
        4. Change some contacts on the PSE.
        5. Reconnect PCE to PSE to perform transfer.
        6. Verify that new contacts match.

        Returns:
            Pass if True
            Fail if False
        """
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        if not self.connect_and_verify(phone_numbers_added):
            return False

        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE_CONTACTS_FILE, 110, 2)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)
        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='bbe31bf5-51e8-4175-b266-1c7750e44f5b')
    @BluetoothBaseTest.bt_test_wrap
    def test_special_contacts(self):
        """Test Special Contacts

        Test numerous special cases of contacts that could cause errors.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of contacts to PSE that includes special cases:
        2. Connect PCE to PSE to perform transfer.
        3. Verify that contacts match.

        Returns:
            Pass if True
            Fail if False
        """

        vcards = []

        # Generate a contact with no email address
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = "Mr."
        current_contact.last_name = "Smiley"
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a 2nd contact with the same name but different phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = "Mr."
        current_contact.last_name = "Smiley"
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with no name
        current_contact = bt_contacts_utils.VCard()
        current_contact.email = "{}@gmail.com".format(
            bt_contacts_utils.generate_random_string())
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with random characters in its name
        current_contact = bt_contacts_utils.VCard()
        current_contact.first_name = bt_contacts_utils.generate_random_string()
        current_contact.last_name = bt_contacts_utils.generate_random_string()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a contact with only a phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        # Generate a 2nd contact with only a phone number
        current_contact = bt_contacts_utils.VCard()
        current_contact.add_phone_number(
            bt_contacts_utils.generate_random_phone_number())
        vcards.append(current_contact)

        bt_contacts_utils.create_new_contacts_vcf_from_vcards(
            self.contacts_destination_path, PSE_CONTACTS_FILE, vcards)

        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE_CONTACTS_FILE)

        return self.connect_and_verify(phone_numbers_added)

    @test_tracker_info(uuid='2aa2bd00-86cc-4f39-a06a-90b17ea5b320')
    @BluetoothBaseTest.bt_test_wrap
    def test_call_log(self):
        """Test Call Log

        Test that Call Logs are transfered

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a predefined list of calls to the PSE call log.
        2. Connect PCE to PSE to allow call log transfer
        3. Verify the Missed, Incoming, and Outgoing Call History

        Returns:
            Pass if True
            Fail if False
        """

        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.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.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.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.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.time()) * 1000 - 2 * CALL_LOG_TIME_OFFSET_IN_MSEC)

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse2.droid.bluetoothGetLocalAddress())

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        pse_call_log_count = self.pse.droid.callLogGetCount()
        self.log.info("Waiting for {} call logs to be transfered".format(
            pse_call_log_count))
        bt_contacts_utils.wait_for_call_log_update_complete(self.pce,
                                                            pse_call_log_count)

        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.INCOMMING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.OUTGOING_CALL_TYPE):
            return False
        if not bt_contacts_utils.get_and_compare_call_logs(
                self.pse, self.pce, bt_contacts_utils.MISSED_CALL_TYPE):
            return False

        return True

    @test_tracker_info(uuid='bb018bf4-5a61-478d-acce-eef88050e489')
    @BluetoothBaseTest.bt_test_wrap
    def test_multiple_phones(self):
        """Test Multiple Phones

        Test that connects two phones and confirms contacts are transfered
        and merged while still being associated with their original phone.

        Precondition:
        1. Devices are paired.

        Steps:
        1. Add a unique list of contacts to PSE on each phone.
        2. Connect PCE to PSE 1 to perform transfer.
        3. Verify contacts match.
        4. Connect PCE to PSE 2 to perform transfer.
        5. Verify that the PCE has a union set of contacts from
           PSE 1 and PSE 2.
        6. Disconnect PCE from PSE 1 to clean up contacts.
        7. Verify that only PSE 2 contacts remain on PCE and they match.
        8. Disconnect PCE from PSE 2 to clean up contacts.

        Returns:
           Pass if True
           Fail if False
        """

        PSE1_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "1")
        PSE2_CONTACTS_FILE = "{}{}".format(PSE_CONTACTS_FILE, "2")

        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE1_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse, self.contacts_destination_path, PSE1_CONTACTS_FILE)
        bt_contacts_utils.generate_contact_list(self.contacts_destination_path,
                                                PSE2_CONTACTS_FILE, 100)
        phone_numbers_added = bt_contacts_utils.import_device_contacts_from_vcf(
            self.pse2, self.contacts_destination_path, PSE2_CONTACTS_FILE)

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse2.droid.bluetoothGetLocalAddress())

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        pse1_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE1_CONTACTS_FILE) == 0

        bt_test_utils.connect_pri_to_sec(
            self.pce, self.pse2,
            set([BtEnum.BluetoothProfile.PBAP_CLIENT.value]))

        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 200)

        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)

        merged_file = open('{}{}'.format(self.contacts_destination_path,
                                         MERGED_CONTACTS_FILE), 'w')
        for contacts_file in [PSE1_CONTACTS_FILE, PSE2_CONTACTS_FILE]:
            infile = open(self.contacts_destination_path + contacts_file)
            merged_file.write(infile.read())

        self.log.info("Checking combined phonebook.")
        pse1andpse2_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            MERGED_CONTACTS_FILE) == 0

        self.pce.droid.bluetoothPbapClientDisconnect(
            self.pse.droid.bluetoothGetLocalAddress())
        bt_contacts_utils.wait_for_phone_number_update_complete(self.pce, 100)

        self.log.info("Checking phonebook after disconnecting first device.")
        bt_contacts_utils.export_device_contacts_to_vcf(
            self.pce, self.contacts_destination_path, PCE_CONTACTS_FILE)
        pse2_matches = bt_contacts_utils.count_contacts_with_differences(
            self.contacts_destination_path, PCE_CONTACTS_FILE,
            PSE2_CONTACTS_FILE) == 0

        bt_contacts_utils.erase_contacts(self.pse)
        bt_contacts_utils.erase_contacts(self.pse2)
        return pse1_matches and pse2_matches and pse1andpse2_matches
