Implements bluetooth test checking that contact details have been
imported correctly from the connected device.

Test: https://paste.googleplex.com/6695844559454208
Bug: 273366005
Change-Id: I36a280ad4f9befe98045f5b9cbe202b3bb78251f
diff --git a/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoDialHelper.java b/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoDialHelper.java
index 2d47492..c657ddb 100644
--- a/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoDialHelper.java
+++ b/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoDialHelper.java
@@ -218,6 +218,13 @@
     String getFirstContactFromContactList();
 
     /**
+     * Setup expectations: A Contact details page is open.
+     *
+     * <p>This method is used to get the home address from the currently-open contact.
+     */
+    String getHomeAddress();
+
+    /**
      * Setup expectations: The app is open.
      *
      * <p>This method is used to verify if a contact is added to Favorites.
@@ -248,6 +255,14 @@
     void openContacts();
 
     /**
+     * Setup expectations: The contacts page is open.
+     *
+     * <p>This method is used to open the contact details page of the first visible contact. Throws
+     * an error if no contacts are visible.
+     */
+    void openFirstContactDetails();
+
+    /**
      * Setup expectations: The app is open and there is an ongoing call.
      *
      * <p>This method is used check if ongoing call is displayed on home.
diff --git a/libraries/automotive-helpers/auto-default-config/resources/assets/defaultSpectatioConfig.json b/libraries/automotive-helpers/auto-default-config/resources/assets/defaultSpectatioConfig.json
index 9e6d41c..af57dba 100644
--- a/libraries/automotive-helpers/auto-default-config/resources/assets/defaultSpectatioConfig.json
+++ b/libraries/automotive-helpers/auto-default-config/resources/assets/defaultSpectatioConfig.json
@@ -199,11 +199,43 @@
       "VALUE": "title",
       "PACKAGE": "com.android.car.dialer"
     },
+    "CONTACT_ADDRESS": {
+      "TYPE": "RESOURCE_ID",
+      "VALUE": "title",
+      "PACKAGE": "com.android.car.dialer"
+    },
+    "CONTACT_HOME_ADDRESS": {
+      "TYPE": "MULTIPLE",
+      "SPECIFIERS": [
+        {
+          "TYPE": "RESOURCE_ID",
+          "VALUE": "title"
+        },
+        {
+          "TYPE": "HAS_ANCESTOR",
+          "MAX_DEPTH": 1,
+          "ANCESTOR": {
+            "TYPE": "HAS_DESCENDANT",
+            "MAX_DEPTH": 1,
+            "DESCENDANT": {
+              "TYPE": "TEXT",
+              "VALUE": "Home"
+            }
+          }
+        }
+
+      ]
+    },
     "CONTACT_DETAIL": {
       "TYPE": "RESOURCE_ID",
       "VALUE": "show_contact_detail_id",
       "PACKAGE": "com.android.car.dialer"
     },
+    "CONTACT_DETAILS_PAGE": {
+      "TYPE": "DESCRIPTION",
+      "VALUE": "com.android.car.ui.utils.ROTARY_CONTAINER"
+    },
+
     "CALL_HISTORY_INFO": {
       "TYPE": "RESOURCE_ID",
       "VALUE": "call_action_id",
diff --git a/libraries/automotive-helpers/auto-default-config/src/android/platform/helpers/AutomotiveConfigConstants.java b/libraries/automotive-helpers/auto-default-config/src/android/platform/helpers/AutomotiveConfigConstants.java
index 75f1668..0763056 100644
--- a/libraries/automotive-helpers/auto-default-config/src/android/platform/helpers/AutomotiveConfigConstants.java
+++ b/libraries/automotive-helpers/auto-default-config/src/android/platform/helpers/AutomotiveConfigConstants.java
@@ -55,6 +55,12 @@
     public static final String SORT_BY_LAST_NAME = "SORT_BY_LAST_NAME";
     public static final String CONTACTS_MENU = "CONTACTS_MENU";
     public static final String CONTACT_NAME = "CONTACT_NAME";
+
+    public static final String CONTACT_ADDRESS = "CONTACT_ADDRESS";
+
+    public static final String CONTACT_HOME_ADDRESS = "CONTACT_HOME_ADDRESS";
+
+    public static final String CONTACT_DETAILS_PAGE = "CONTACT_DETAILS_PAGE";
     public static final String CONTACT_DETAIL = "CONTACT_DETAIL";
     public static final String CALL_HISTORY_INFO = "CALL_HISTORY_INFO";
     public static final String SEARCH_CONTACT = "SEARCH_CONTACT";
diff --git a/libraries/automotive-helpers/dial-app-helper/src/android/platform/helpers/DialHelperImpl.java b/libraries/automotive-helpers/dial-app-helper/src/android/platform/helpers/DialHelperImpl.java
index 92c02c3..d8ade89 100644
--- a/libraries/automotive-helpers/dial-app-helper/src/android/platform/helpers/DialHelperImpl.java
+++ b/libraries/automotive-helpers/dial-app-helper/src/android/platform/helpers/DialHelperImpl.java
@@ -45,6 +45,7 @@
     private BySelector mForwardButtonSelector;
     private BySelector mScrollableElementSelector;
     private ScrollDirection mScrollDirection;
+    private UiObject2 mHomeAddress;
 
     public DialHelperImpl(Instrumentation instr) {
         super(instr);
@@ -454,6 +455,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public boolean isContactInFavorites(String contact) {
         openFavorites();
         UiObject2 uiObject = getSpectatioUiUtil().findUiObject(contact);
@@ -529,6 +531,32 @@
         getSpectatioUiUtil().clickAndWait(contactDetailButton);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public String getHomeAddress() {
+
+        BySelector homeAddressSelector =
+                getUiElementFromConfig(AutomotiveConfigConstants.CONTACT_HOME_ADDRESS);
+
+        BySelector detailsScrollableSelector =
+                getUiElementFromConfig(AutomotiveConfigConstants.CONTACT_DETAILS_PAGE);
+
+        UiObject2 homeAddress =
+                mScrollUtility.scrollAndFindUiObject(
+                        mScrollAction,
+                        mScrollDirection,
+                        mForwardButtonSelector,
+                        mBackwardButtonSelector,
+                        detailsScrollableSelector,
+                        homeAddressSelector,
+                        String.format("scroll to find home address."));
+
+        getSpectatioUiUtil()
+                .validateUiObject(homeAddress, AutomotiveConfigConstants.CONTACT_HOME_ADDRESS);
+
+        return homeAddress.getText();
+    }
+
     /** This method is used to get the first history in the Recents tab. */
     private UiObject2 getCallHistory() {
         BySelector callHistorySelector =
@@ -550,6 +578,16 @@
         getSpectatioUiUtil().clickAndWait(contactMenuButton);
     }
 
+    /** This method opens the details page of the first contact on the page. */
+    public void openFirstContactDetails() {
+        BySelector contactDetailsSelector =
+                getUiElementFromConfig(AutomotiveConfigConstants.CONTACT_DETAIL);
+        UiObject2 contactDetailButton = getSpectatioUiUtil().findUiObject(contactDetailsSelector);
+        getSpectatioUiUtil()
+                .validateUiObject(contactDetailButton, AutomotiveConfigConstants.CONTACT_DETAIL);
+        getSpectatioUiUtil().clickAndWait(contactDetailButton);
+    }
+
     /** This method opens the contact search window. */
     private void openSearchContact() {
         BySelector searchContactSelector =
diff --git a/tests/automotive/mobly_tests/dialer/Android.bp b/tests/automotive/mobly_tests/dialer/Android.bp
index 4bcb6cb..ec15b67 100644
--- a/tests/automotive/mobly_tests/dialer/Android.bp
+++ b/tests/automotive/mobly_tests/dialer/Android.bp
@@ -93,3 +93,29 @@
         },
     },
 }
+
+python_test_host {
+    name: "BTAddressTest",
+    main: "dialer_test_import_address_details.py",
+    srcs: ["dialer_test_import_address_details.py"],
+    libs: [
+        "mobly",
+        "mbs_utils"
+    ],
+    test_suites: [
+        "catbox",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    data: [
+        // Package the snippet with the mobly test
+        ":AutomotiveSnippet",
+        ":PhoneSnippet",
+    ],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
\ No newline at end of file
diff --git a/tests/automotive/mobly_tests/dialer/dialer_test_import_address_details.py b/tests/automotive/mobly_tests/dialer/dialer_test_import_address_details.py
new file mode 100644
index 0000000..ecf3af0
--- /dev/null
+++ b/tests/automotive/mobly_tests/dialer/dialer_test_import_address_details.py
@@ -0,0 +1,125 @@
+"""
+  Copyright (C) 2023 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 Steps:
+1. Go to Dialer >Contacts and click on '>' icon in front of contact name to see the contact details
+2. Verify address information stored in phone contacts rendered in dialer app successfully
+
+"""
+
+import sys
+import logging
+import pprint
+
+from mobly import asserts
+from mobly import base_test
+from mobly import test_runner
+from mobly.controllers import android_device
+
+from mbs_utils import constants
+from mbs_utils import spectatio_utils
+from mbs_utils import bt_utils
+
+
+class ImportAddressDetailsTest(base_test.BaseTestClass):
+
+    VCF_ADDRESS_HEADER = "ADR"
+
+    def setup_class(self):
+        # Registering android_device controller module, and declaring that the test
+        # requires at least two Android devices.
+        self.ads = self.register_controller(android_device, min_number=2)
+        # # The device used to discover Bluetooth devices.
+        self.discoverer = android_device.get_device(
+            self.ads, label='auto')
+        # # Sets the tag that represents this device in logs.
+        self.discoverer.debug_tag = 'discoverer'
+        # # The device that is expected to be discovered
+        self.target = android_device.get_device(self.ads, label='phone')
+        self.target.debug_tag = 'target'
+        #
+        self.target.load_snippet('mbs', android_device.MBS_PACKAGE)
+        self.discoverer.load_snippet('mbs', android_device.MBS_PACKAGE)
+        #
+        self.call_utils = (spectatio_utils.CallUtils(self.discoverer))
+        #
+        self.bt_utils = (bt_utils.BTUtils(self.discoverer, self.target))
+
+    def get_first_address(self, vcf_path):
+        """ Reads the first address from the given vcf file'"""
+
+        with open(vcf_path, mode='r') as vcf_file:
+            for line in vcf_file:
+                if line.startswith(self.VCF_ADDRESS_HEADER):
+                    return line
+
+
+
+    def setup_test(self):
+        # Upload contacts to phone device
+        file_path = constants.PATH_TO_CONTACTS_VCF_FILE
+        self.call_utils.upload_vcf_contacts_to_device(self.target, file_path)
+
+        # Pair the devices
+        self.bt_utils.pair_primary_to_secondary()
+
+    def test_import_address_details(self):
+        # Open the dialer app, and then the contacts page
+        self.call_utils.open_phone_app()
+        self.call_utils.wait_with_log(constants.WAIT_TWO_SECONDS)
+        self.call_utils.open_contacts()
+        self.call_utils.wait_with_log(constants.WAIT_TWO_SECONDS)
+        self.call_utils.open_first_contact_details()
+        self.call_utils.wait_with_log(constants.WAIT_TWO_SECONDS)
+
+        # Import the first contact's address from the discoverer device.
+        display_address = self.call_utils.get_home_address_from_details()
+
+        # Import the list of contact addresses from the VCF file.
+        vcf_line = self.get_first_address(constants.PATH_TO_CONTACTS_VCF_FILE)
+
+        # Confirm that these two lists contain the same data.
+        asserts.assert_true(
+            self.compare_display_address_to_vcf_line(display_address, vcf_line),
+            ("Displayed address does not match address stored in VCF file: " +
+            "\n\tDisplayed address: %s" +
+            "\n\tVCF address: %s") % (display_address, vcf_line))
+
+
+    def teardown_test(self):
+        # Turn Bluetooth off on both devices after test finishes.
+        self.target.mbs.btDisable()
+        self.discoverer.mbs.btDisable()
+
+    def compare_display_address_to_vcf_line(self, display_address, vcf_address):
+        """Confirm that each portion of a display-able street address appears in the vcf line.
+            Comparison is done portion-by-portion because the VCF line contains metadata and delimiters,
+            meaning this comparison could hypothetically give a false positive if parts of the address are entirely composed
+            of other parts of the address (for example, a house number being identical to the zip code."""
+        parts = display_address.split()
+        for part in parts:
+            if not part in vcf_address:
+                logging.info("\tAddress mismatch: %s not found in %s" % (part, vcf_address))
+                return False
+        return True
+
+
+
+
+if __name__ == '__main__':
+    # Take test args
+    test_runner.main()
\ No newline at end of file
diff --git a/tests/automotive/mobly_tests/dialer/dialer_test_sort_contacts_by_last_name.py b/tests/automotive/mobly_tests/dialer/dialer_test_sort_contacts_by_last_name.py
index 7c1988c..2a7da8c 100644
--- a/tests/automotive/mobly_tests/dialer/dialer_test_sort_contacts_by_last_name.py
+++ b/tests/automotive/mobly_tests/dialer/dialer_test_sort_contacts_by_last_name.py
@@ -108,15 +108,10 @@
             "When sorting by last name, expected %s, found %s" % (top_contact_by_last_name,
             first_contact))
 
-
-
-
-
-
-def teardown_test(self):
-        # Turn Bluetooth off on both devices after test finishes.
-        self.target.mbs.btDisable()
-        self.discoverer.mbs.btDisable()
+    def teardown_test(self):
+            # Turn Bluetooth off on both devices after test finishes.
+            self.target.mbs.btDisable()
+            self.discoverer.mbs.btDisable()
 
 
 
diff --git a/tests/automotive/mobly_tests/mbs_utils/bt_utils.py b/tests/automotive/mobly_tests/mbs_utils/bt_utils.py
index 88b8d90..38e60a5 100644
--- a/tests/automotive/mobly_tests/mbs_utils/bt_utils.py
+++ b/tests/automotive/mobly_tests/mbs_utils/bt_utils.py
@@ -22,7 +22,7 @@
 
 # Number of seconds for the target to stay discoverable on Bluetooth.
 DISCOVERABLE_TIME = 60
-TIME_FOR_PROMPT_TO_LOAD = 3
+TIME_FOR_PROMPT_TO_LOAD = 2
 class BTUtils:
     """A utility that provides access to Bluetooth connectivity controls."""
 
@@ -74,10 +74,9 @@
                     logging.info('Device \'%s\' found. Pairing.' % target_name)
                     self.discoverer.mbs.btPairDevice(discovered_addrs[i])
                     self.target_adrr = discovered_addrs[i]
-                    logging.info('Allowing contact sharing on secondary device.')
-                    time.sleep(constants.DEFAULT_WAIT_TIME_FIVE_SECS)
-                    self.press_allow_on_device() ## Attempts multiple presses
+                    logging.info('Allowing time for contacts to sync.')
                     time.sleep(constants.SYNC_WAIT_TIME)
+                    self.press_allow_on_device() ## Attempts multiple presses
                     return
 
     def press_allow_on_device(self):
diff --git a/tests/automotive/mobly_tests/mbs_utils/contacts_test.vcf b/tests/automotive/mobly_tests/mbs_utils/contacts_test.vcf
index 88b813d..09ae844 100644
--- a/tests/automotive/mobly_tests/mbs_utils/contacts_test.vcf
+++ b/tests/automotive/mobly_tests/mbs_utils/contacts_test.vcf
@@ -1,9 +1,10 @@
 BEGIN:VCARD
 VERSION:2.1
-N:Goo;Anna;;;
+N:Boo;Anna;;;
 FN:Anna Goo
 TEL;CELL:1-844-825-5234
 TEL;WORK:
+ADR;TYPE#WORK;PREF#1;LABEL#"Normality\nTesttown\, XX 00000\nTestland":;;111 Test Street;Testtown;XX;00000;Testland
 END:VCARD
 BEGIN:VCARD
 VERSION:2.1
@@ -11,6 +12,7 @@
 FN:Boris Johnson
 TEL;CELL:56355
 TEL;WORK:
+ADR;TYPE#WORK;PREF#1;LABEL#"Normality\nTesttown\, XX 00000\nTestland":;;111 Test Street;Testtown;XX;00000;Testland
 END:VCARD
 BEGIN:VCARD
 VERSION:2.1
@@ -18,13 +20,15 @@
 FN:John Smith Jr
 TEL;CELL:611
 TEL;WORK:123
+ADR;TYPE#WORK;PREF#1;LABEL#"Normality\nTesttown\, XX 00000\nTestland":;;111 Test Street;Testtown;XX;00000;Testland
 END:VCARD
 BEGIN:VCARD
 VERSION:2.1
 N:Alder;Maha;;;
-FN:Maha Alder
+FN:Maha Halder
 TEL;CELL:611
 TEL;WORK:1-844-825-5234
+ADR;TYPE#WORK;PREF#1;LABEL#"Normality\nTesttown\, XX 00000\nTestland":;;111 Test Street;Testtown;XX;00000;Testland
 END:VCARD
 BEGIN:VCARD
 VERSION:2.1
@@ -32,4 +36,5 @@
 FN:Sarah Williams
 TEL;CELL:852
 TEL;WORK:
+ADR;TYPE#WORK;PREF#1;LABEL#"Normality\nTesttown\, XX 00000\nTestland":;;111 Test Street;Testtown;XX;00000;Testland
 END:VCARD
diff --git a/tests/automotive/mobly_tests/mbs_utils/spectatio_utils.py b/tests/automotive/mobly_tests/mbs_utils/spectatio_utils.py
index 2884c9d..27a4b9b 100644
--- a/tests/automotive/mobly_tests/mbs_utils/spectatio_utils.py
+++ b/tests/automotive/mobly_tests/mbs_utils/spectatio_utils.py
@@ -62,6 +62,10 @@
         """ Get dialing phone number"""
         return self.device.mbs.getDialedNumber()
 
+    def get_home_address_from_details(self):
+        """Return the home address of the contact whose details are currently being displayed"""
+        return self.device.mbs.getHomeAddress()
+
 
     def import_contacts_from_vcf_file(self, device_target):
         """ Importing contacts from VCF file"""
@@ -89,6 +93,12 @@
         logging.info('Opening phone app')
         self.device.mbs.openPhoneApp()
 
+    def open_first_contact_details(self):
+        """Open the contact details page for the first contact visible in the contact list.
+        Assumes we are on the contacts page. """
+        logging.info('Getting details for first contact on the page')
+        self.device.mbs.openFirstContactDetails()
+
     def press_enter_on_device(self, device_target):
         """Press ENTER on device"""
         logging.info('Press ENTER on device')
diff --git a/tests/automotive/snippets/phone/src/com/google/android/mobly/snippet/bundled/PhoneSnippet.java b/tests/automotive/snippets/phone/src/com/google/android/mobly/snippet/bundled/PhoneSnippet.java
index 1f66735..c881801 100644
--- a/tests/automotive/snippets/phone/src/com/google/android/mobly/snippet/bundled/PhoneSnippet.java
+++ b/tests/automotive/snippets/phone/src/com/google/android/mobly/snippet/bundled/PhoneSnippet.java
@@ -97,6 +97,11 @@
         return mDialerHelper.get().getDialInNumber();
     }
 
+    @Rpc(description = "Get the home address from an open contacts page.")
+    public String getHomeAddress() {
+        return mDialerHelper.get().getHomeAddress();
+    }
+
     @Rpc(description = "Get the contact name for dialed number when the call is in progress.")
     public String getDialedContactName() {
         return mDialerHelper.get().getDialedContactName();
@@ -209,6 +214,11 @@
         mDialerHelper.get().openDetailsPage(contact);
     }
 
+    @Rpc(description = "Open details page for the first contact.")
+    public void openFirstContactDetails() {
+        mDialerHelper.get().openFirstContactDetails();
+    }
+
     @Rpc(description = "Open Contacts List.")
     public void openContacts() {
         mDialerHelper.get().openContacts();