[Autofill Assistant] CUD validity for Shipping Address

This implements CollectUserData validity for shipping addresses based
on the new rules being sent from backend.

It keeps the "editor" validation in place. The reasoning is, that we
still want that minimum validity, in case the user opens the address
for editing.

This also changes the way Java gets errors by sending them from the UI
controller instead of Java asking for them.

Bug: b/180705720
Change-Id: Ib20403158a6c965b8265a647f1fdb6ddd2b7c9a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2919809
Reviewed-by: Luca Hunkeler <hluca@google.com>
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Cr-Commit-Position: refs/heads/master@{#887947}
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_address_full.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_address_full.xml
index 7a0febd..21fed24 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_address_full.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_address_full.xml
@@ -24,9 +24,6 @@
         android:id="@+id/incomplete_error"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:maxLines="1"
-        android:text="@string/autofill_assistant_payment_information_missing"
         android:textAppearance="@style/TextAppearance.ErrorCaption"
         android:visibility="gone"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_contact_full.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_contact_full.xml
index 18973b4..910f723 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_contact_full.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_contact_full.xml
@@ -18,7 +18,6 @@
         android:id="@+id/incomplete_error"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/autofill_assistant_payment_information_missing"
         android:textAppearance="@style/TextAppearance.ErrorCaption"
         android:visibility="gone"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
index 4dc22f94..d22b7fc 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
@@ -15,10 +15,10 @@
 import org.chromium.chrome.browser.autofill.settings.AddressEditor;
 import org.chromium.chrome.browser.autofill.settings.CardEditor;
 import org.chromium.chrome.browser.autofill_assistant.generic_ui.AssistantValue;
+import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.AddressModel;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.ContactModel;
 import org.chromium.chrome.browser.autofill_assistant.user_data.additional_sections.AssistantAdditionalSection.Delegate;
 import org.chromium.chrome.browser.autofill_assistant.user_data.additional_sections.AssistantAdditionalSectionContainer;
-import org.chromium.chrome.browser.payments.AutofillAddress;
 import org.chromium.chrome.browser.payments.AutofillPaymentInstrument;
 import org.chromium.chrome.browser.payments.ContactEditor;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -180,12 +180,9 @@
             view.mPaymentMethodSection.setCompletenessDelegate(collectUserDataDelegate != null
                             ? collectUserDataDelegate::isPaymentInstrumentComplete
                             : null);
-            view.mShippingAddressSection.setListener(collectUserDataDelegate != null
-                            ? collectUserDataDelegate::onShippingAddressChanged
-                            : null);
-            view.mShippingAddressSection.setCompletenessDelegate(collectUserDataDelegate != null
-                            ? collectUserDataDelegate::isShippingAddressComplete
-                            : null);
+            view.mShippingAddressSection.setListener(collectUserDataDelegate == null
+                            ? null
+                            : m -> collectUserDataDelegate.onShippingAddressChanged(m.mOption));
             view.mLoginSection.setListener(collectUserDataDelegate != null
                             ? collectUserDataDelegate::onLoginChoiceChanged
                             : null);
@@ -478,7 +475,7 @@
         // This prevents creating a loop.
         if (propertyKey == AssistantCollectUserDataModel.SELECTED_SHIPPING_ADDRESS) {
             if (model.get(AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS)) {
-                AutofillAddress shippingAddress =
+                AddressModel shippingAddress =
                         model.get(AssistantCollectUserDataModel.SELECTED_SHIPPING_ADDRESS);
                 if (shippingAddress != null) {
                     view.mShippingAddressSection.addOrUpdateItem(
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataDelegate.java
index 97b6741..ea8f37c3 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataDelegate.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataDelegate.java
@@ -55,12 +55,6 @@
     void onInputTextFocusChanged(boolean isFocused);
 
     /**
-     * Returns true if the shipping address is complete.
-     * TODO(b/154068342): Remove this method and send the error message from |Controller|.
-     */
-    boolean isShippingAddressComplete(@Nullable AutofillAddress address);
-
-    /**
      * Returns true if the payment instrument is complete.
      * TODO(b/154068342): Remove this method and send the error message from |Controller|.
      */
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
index c6b8069b..cf2b693 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
@@ -90,6 +90,17 @@
         }
     }
 
+    /** Model wrapper for an {@code AutofillAddress}. */
+    public static class AddressModel extends OptionModel<AutofillAddress> {
+        public AddressModel(AutofillAddress address, List<String> errors) {
+            super(address, errors);
+        }
+
+        public AddressModel(AutofillAddress address) {
+            super(address);
+        }
+    }
+
     public static final WritableObjectPropertyKey<AssistantCollectUserDataDelegate> DELEGATE =
             new WritableObjectPropertyKey<>();
 
@@ -100,7 +111,7 @@
     public static final WritableBooleanPropertyKey VISIBLE = new WritableBooleanPropertyKey();
 
     /** The chosen shipping address. */
-    public static final WritableObjectPropertyKey<AutofillAddress> SELECTED_SHIPPING_ADDRESS =
+    public static final WritableObjectPropertyKey<AddressModel> SELECTED_SHIPPING_ADDRESS =
             new WritableObjectPropertyKey<>();
 
     /** The chosen payment method (including billing address). */
@@ -150,8 +161,8 @@
     public static final WritableObjectPropertyKey<List<ContactModel>> AVAILABLE_CONTACTS =
             new WritableObjectPropertyKey<>();
 
-    public static final WritableObjectPropertyKey<List<AutofillAddress>>
-            AVAILABLE_SHIPPING_ADDRESSES = new WritableObjectPropertyKey<>();
+    public static final WritableObjectPropertyKey<List<AddressModel>> AVAILABLE_SHIPPING_ADDRESSES =
+            new WritableObjectPropertyKey<>();
 
     public static final WritableObjectPropertyKey<List<AutofillPaymentInstrument>>
             AVAILABLE_PAYMENT_INSTRUMENTS = new WritableObjectPropertyKey<>();
@@ -388,8 +399,11 @@
     }
 
     @CalledByNative
-    private void setSelectedShippingAddress(@Nullable AutofillAddress shippingAddress) {
-        set(SELECTED_SHIPPING_ADDRESS, shippingAddress);
+    private void setSelectedShippingAddress(
+            @Nullable AutofillAddress shippingAddress, String[] errors) {
+        set(SELECTED_SHIPPING_ADDRESS,
+                shippingAddress == null ? null
+                                        : new AddressModel(shippingAddress, Arrays.asList(errors)));
     }
 
     @CalledByNative
@@ -621,14 +635,14 @@
     }
 
     @CalledByNative
-    private static List<AutofillAddress> createAutofillAddressList() {
+    private static List<AddressModel> createShippingAddressList() {
         return new ArrayList<>();
     }
 
     @CalledByNative
-    private static void addAutofillAddress(
-            List<AutofillAddress> addresses, AutofillAddress address) {
-        addresses.add(address);
+    private static void addShippingAddress(
+            List<AddressModel> addresses, AutofillAddress address, String[] errors) {
+        addresses.add(new AddressModel(address, Arrays.asList(errors)));
     }
 
     @VisibleForTesting
@@ -643,11 +657,22 @@
     }
 
     @CalledByNative
-    private void setAvailableShippingAddresses(List<AutofillAddress> addresses) {
+    private void setAvailableShippingAddresses(List<AddressModel> addresses) {
         set(AVAILABLE_SHIPPING_ADDRESSES, addresses);
     }
 
     @CalledByNative
+    private static List<AutofillAddress> createBillingAddressList() {
+        return new ArrayList<>();
+    }
+
+    @CalledByNative
+    private static void addBillingAddress(
+            List<AutofillAddress> addresses, AutofillAddress address) {
+        addresses.add(address);
+    }
+
+    @CalledByNative
     private void setAvailableBillingAddresses(List<AutofillAddress> addresses) {
         set(AVAILABLE_BILLING_ADDRESSES, addresses);
     }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataNativeDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataNativeDelegate.java
index 082c92b..9495afc 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataNativeDelegate.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataNativeDelegate.java
@@ -170,18 +170,6 @@
     }
 
     @Override
-    public boolean isShippingAddressComplete(@Nullable AutofillAddress address) {
-        if (mNativeAssistantCollectUserDataDelegate != 0) {
-            return AssistantCollectUserDataNativeDelegateJni.get().isShippingAddressComplete(
-                    mNativeAssistantCollectUserDataDelegate,
-                    AssistantCollectUserDataNativeDelegate.this,
-                    address != null ? address.getProfile() : null);
-        }
-
-        return false;
-    }
-
-    @Override
     public boolean isPaymentInstrumentComplete(
             @Nullable AutofillPaymentInstrument paymentInstrument) {
         if (mNativeAssistantCollectUserDataDelegate != 0) {
@@ -238,9 +226,6 @@
                 AssistantCollectUserDataNativeDelegate caller, String key, AssistantValue value);
         void onInputTextFocusChanged(long nativeAssistantCollectUserDataDelegate,
                 AssistantCollectUserDataNativeDelegate caller, boolean isFocused);
-        boolean isShippingAddressComplete(long nativeAssistantCollectUserDataDelegate,
-                AssistantCollectUserDataNativeDelegate caller,
-                @Nullable PersonalDataManager.AutofillProfile address);
         boolean isPaymentInstrumentComplete(long nativeAssistantCollectUserDataDelegate,
                 AssistantCollectUserDataNativeDelegate caller,
                 @Nullable PersonalDataManager.CreditCard card,
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java
index 199d565..c1e51c92 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java
@@ -16,15 +16,15 @@
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.settings.AddressEditor;
+import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.AddressModel;
 import org.chromium.chrome.browser.payments.AutofillAddress;
 
 import java.util.List;
 
 /**
- * The payment method section of the Autofill Assistant payment request.
+ * The shipping address section of the Autofill Assistant payment request.
  */
-public class AssistantShippingAddressSection
-        extends AssistantCollectUserDataSection<AutofillAddress> {
+public class AssistantShippingAddressSection extends AssistantCollectUserDataSection<AddressModel> {
     private AddressEditor mEditor;
     private boolean mIgnoreProfileChangeNotifications;
 
@@ -42,76 +42,84 @@
     }
 
     @Override
-    protected void createOrEditItem(@Nullable AutofillAddress oldItem) {
+    protected void createOrEditItem(@Nullable AddressModel oldItem) {
         if (mEditor == null) {
             return;
         }
-        mEditor.edit(oldItem, newItem -> {
-            assert (newItem != null && newItem.isComplete());
+        mEditor.edit(oldItem == null ? null : oldItem.mOption, address -> {
+            assert (address != null && address.isComplete());
             mIgnoreProfileChangeNotifications = true;
-            addOrUpdateItem(newItem, /* select= */ true, /* notify= */ true);
+            addOrUpdateItem(new AddressModel(address), /* select= */ true, /* notify= */ true);
             mIgnoreProfileChangeNotifications = false;
         }, cancel -> {});
     }
 
     @Override
-    protected void updateFullView(View fullView, AutofillAddress address) {
-        if (address == null) {
+    protected void updateFullView(View fullView, @Nullable AddressModel model) {
+        if (model == null) {
             return;
         }
         TextView fullNameView = fullView.findViewById(R.id.full_name);
-        fullNameView.setText(address.getProfile().getFullName());
+        fullNameView.setText(model.mOption.getProfile().getFullName());
         hideIfEmpty(fullNameView);
 
         TextView fullAddressView = fullView.findViewById(R.id.full_address);
-        fullAddressView.setText(
-                PersonalDataManager.getInstance()
-                        .getShippingAddressLabelWithCountryForPaymentRequest(address.getProfile()));
+        fullAddressView.setText(PersonalDataManager.getInstance()
+                                        .getShippingAddressLabelWithCountryForPaymentRequest(
+                                                model.mOption.getProfile()));
         hideIfEmpty(fullAddressView);
 
-        TextView methodIncompleteView = fullView.findViewById(R.id.incomplete_error);
-        methodIncompleteView.setVisibility(isComplete(address) ? View.GONE : View.VISIBLE);
+        TextView errorView = fullView.findViewById(R.id.incomplete_error);
+        if (model.mErrors.isEmpty()) {
+            errorView.setText("");
+            errorView.setVisibility(View.GONE);
+        } else {
+            errorView.setText(TextUtils.join("\n", model.mErrors));
+            errorView.setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
-    protected void updateSummaryView(View summaryView, AutofillAddress address) {
-        if (address == null) {
+    protected void updateSummaryView(View summaryView, @Nullable AddressModel model) {
+        if (model == null) {
             return;
         }
         TextView fullNameView = summaryView.findViewById(R.id.full_name);
-        fullNameView.setText(address.getProfile().getFullName());
+        fullNameView.setText(model.mOption.getProfile().getFullName());
         hideIfEmpty(fullNameView);
 
         TextView shortAddressView = summaryView.findViewById(R.id.short_address);
         shortAddressView.setText(PersonalDataManager.getInstance()
                                          .getShippingAddressLabelWithoutCountryForPaymentRequest(
-                                                 address.getProfile()));
+                                                 model.mOption.getProfile()));
         hideIfEmpty(shortAddressView);
 
-        TextView methodIncompleteView = summaryView.findViewById(R.id.incomplete_error);
-        methodIncompleteView.setVisibility(isComplete(address) ? View.GONE : View.VISIBLE);
+        TextView errorView = summaryView.findViewById(R.id.incomplete_error);
+        errorView.setVisibility(model.mErrors.isEmpty() ? View.GONE : View.VISIBLE);
     }
 
     @Override
-    protected boolean canEditOption(AutofillAddress address) {
+    protected boolean canEditOption(AddressModel model) {
         return true;
     }
 
     @Override
-    protected @DrawableRes int getEditButtonDrawable(AutofillAddress address) {
+    protected @DrawableRes int getEditButtonDrawable(AddressModel model) {
         return R.drawable.ic_edit_24dp;
     }
 
     @Override
-    protected String getEditButtonContentDescription(AutofillAddress address) {
+    protected String getEditButtonContentDescription(AddressModel model) {
         return mContext.getString(R.string.payments_edit_address);
     }
 
     @Override
-    protected boolean areEqual(AutofillAddress optionA, AutofillAddress optionB) {
-        if (optionA == null || optionB == null) {
-            return optionA == optionB;
+    protected boolean areEqual(AddressModel modelA, AddressModel modelB) {
+        if (modelA == null || modelB == null) {
+            return modelA == modelB;
         }
+        AutofillAddress optionA = modelA.mOption;
+        AutofillAddress optionB = modelB.mOption;
         if (TextUtils.equals(optionA.getIdentifier(), optionB.getIdentifier())) {
             return true;
         }
@@ -127,7 +135,7 @@
      * The Chrome profiles have changed externally. This will rebuild the UI with the new/changed
      * set of addresses derived from the profiles, while keeping the selected item if possible.
      */
-    void onAddressesChanged(List<AutofillAddress> addresses) {
+    void onAddressesChanged(List<AddressModel> addresses) {
         if (mIgnoreProfileChangeNotifications) {
             return;
         }
@@ -147,13 +155,13 @@
     }
 
     @Override
-    protected void addOrUpdateItem(AutofillAddress address, boolean select, boolean notify) {
-        super.addOrUpdateItem(address, select, notify);
+    protected void addOrUpdateItem(AddressModel model, boolean select, boolean notify) {
+        super.addOrUpdateItem(model, select, notify);
 
         // Update autocomplete information in the editor.
         if (mEditor == null) {
             return;
         }
-        mEditor.addPhoneNumberIfValid(address.getProfile().getPhoneNumber());
+        mEditor.addPhoneNumberIfValid(model.mOption.getProfile().getPhoneNumber());
     }
 }
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
index f63b9478..a9eb47e 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataTestHelper.java
@@ -180,11 +180,6 @@
         public void onInputTextFocusChanged(boolean isFocused) {}
 
         @Override
-        public boolean isShippingAddressComplete(@Nullable AutofillAddress address) {
-            return address != null && address.isComplete();
-        }
-
-        @Override
         public boolean isPaymentInstrumentComplete(
                 @Nullable AutofillPaymentInstrument paymentInstrument) {
             return paymentInstrument != null && paymentInstrument.isComplete();
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java
index 79ba7e7..7e19251 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java
@@ -59,6 +59,7 @@
 import org.chromium.chrome.browser.autofill_assistant.generic_ui.AssistantValue;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel;
+import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.AddressModel;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel.ContactModel;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantContactField;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantDateChoiceOptions;
@@ -661,8 +662,9 @@
             AutofillAddress address = AssistantCollectUserDataModel.createAutofillAddress(
                     mTestRule.getActivity(), profile);
             model.set(AssistantCollectUserDataModel.AVAILABLE_SHIPPING_ADDRESSES,
-                    Collections.singletonList(address));
-            model.set(AssistantCollectUserDataModel.SELECTED_SHIPPING_ADDRESS, address);
+                    Collections.singletonList(new AddressModel(address)));
+            model.set(AssistantCollectUserDataModel.SELECTED_SHIPPING_ADDRESS,
+                    new AddressModel(address));
             AutofillPaymentInstrument paymentInstrument =
                     AssistantCollectUserDataModel.createAutofillPaymentInstrument(
                             mTestRule.getWebContents(), creditCard, profile);
@@ -744,7 +746,7 @@
             AutofillAddress address = AssistantCollectUserDataModel.createAutofillAddress(
                     mTestRule.getActivity(), profile);
             model.set(AssistantCollectUserDataModel.AVAILABLE_SHIPPING_ADDRESSES,
-                    Collections.singletonList(address));
+                    Collections.singletonList(new AddressModel(address)));
             AutofillPaymentInstrument paymentInstrument =
                     AssistantCollectUserDataModel.createAutofillPaymentInstrument(
                             mTestRule.getWebContents(), creditCard, profile);
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 45f28c0..abca658 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -986,12 +986,15 @@
      */
     @Test
     @MediumTest
-    public void testCreateAndEnterAddress() throws Exception {
+    public void testCreateAndEnterShippingAddress() throws Exception {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add((ActionProto) ActionProto.newBuilder()
-                         .setCollectUserData(CollectUserDataProto.newBuilder()
-                                                     .setShippingAddressName("shipping")
-                                                     .setRequestTermsAndConditions(false))
+                         .setCollectUserData(
+                                 CollectUserDataProto.newBuilder()
+                                         .setShippingAddressName("shipping")
+                                         .addRequiredShippingAddressDataPiece(
+                                                 buildRequiredDataPiece("Requires valid state", 34))
+                                         .setRequestTermsAndConditions(false))
                          .build());
         list.add((ActionProto) ActionProto.newBuilder()
                          .setUseAddress(
@@ -1026,17 +1029,39 @@
         onView(withContentDescription("Street address*"))
                 .perform(scrollTo(), typeText("123 Main St"));
         onView(withContentDescription("City*")).perform(scrollTo(), typeText("Mountain View"));
-        onView(withContentDescription("State*")).perform(scrollTo(), typeText("California"));
+        onView(withContentDescription("State*")).perform(scrollTo(), typeText("Invalid"));
         onView(withContentDescription("ZIP code*")).perform(scrollTo(), typeText("1234"));
         onView(withContentDescription("Phone*")).perform(scrollTo(), typeText("8008080808"));
         Espresso.closeSoftKeyboard();
         onView(withId(org.chromium.chrome.R.id.editor_dialog_done_button))
                 .perform(scrollTo(), click());
-        waitUntilViewMatchesCondition(withContentDescription("Continue"), isEnabled());
+        // First round: Invalid state.
         waitUntilViewMatchesCondition(
-                allOf(withParent(withId(R.id.address_summary)), withId(R.id.full_name)),
+                withContentDescription("Continue"), allOf(isDisplayed(), not(isEnabled())));
+        onView(allOf(withParent(withId(R.id.address_summary)), withId(R.id.incomplete_error)))
+                .check(matches(
+                        allOf(withText(mTestRule.getActivity().getString(
+                                      R.string.autofill_assistant_payment_information_missing)),
+                                isDisplayed())));
+        onView(withText("Shipping address")).perform(click());
+        waitUntilViewMatchesCondition(withId(R.id.address_full), isDisplayed());
+        onView(allOf(withParent(withId(R.id.address_full)), withId(R.id.incomplete_error)))
+                .check(matches(allOf(withText("Requires valid state"), isDisplayed())));
+        onView(withContentDescription("Edit address")).perform(click());
+        waitUntilViewMatchesCondition(
+                withContentDescription("Name*"), allOf(isDisplayed(), isEnabled()));
+        onView(withContentDescription("State*"))
+                .perform(scrollTo(), clearText(), typeText("California"));
+        Espresso.closeSoftKeyboard();
+        onView(withId(org.chromium.chrome.R.id.editor_dialog_done_button))
+                .perform(scrollTo(), click());
+        // Second round: Complete.
+        waitUntilViewMatchesCondition(
+                withContentDescription("Continue"), allOf(isDisplayed(), isEnabled()));
+        waitUntilViewMatchesCondition(
+                allOf(withParent(withId(R.id.address_full)), withId(R.id.full_name)),
                 allOf(withText("John Doe"), isCompletelyDisplayed()));
-        onView(withText("Continue")).perform(click());
+        onView(withContentDescription("Continue")).perform(click());
         waitUntilViewMatchesCondition(withText("Prompt"), isCompletelyDisplayed());
         assertThat(getElementValue(getWebContents(), "address_name"), is("John Doe"));
         assertThat(getElementValue(getWebContents(), "street"), is("123 Main St"));
diff --git a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
index 1ef62c7..d2c11b4 100644
--- a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
+++ b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
@@ -192,21 +192,6 @@
   return java_assistant_collect_user_data_delegate_;
 }
 
-bool AssistantCollectUserDataDelegate::IsShippingAddressComplete(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jcaller,
-    const base::android::JavaParamRef<jobject>& jaddress) {
-  if (!jaddress) {
-    return ui_controller_->IsShippingAddressComplete(nullptr);
-  }
-
-  autofill::AutofillProfile address;
-  autofill::PersonalDataManagerAndroid::PopulateNativeProfileFromJava(
-      jaddress, env, &address);
-
-  return ui_controller_->IsShippingAddressComplete(&address);
-}
-
 bool AssistantCollectUserDataDelegate::IsPaymentInstrumentComplete(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.h b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.h
index 522b5de..2a92a2a 100644
--- a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.h
+++ b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.h
@@ -95,11 +95,6 @@
       const base::android::JavaParamRef<jobject>& jcaller,
       jboolean jis_focused);
 
-  bool IsShippingAddressComplete(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jcaller,
-      const base::android::JavaParamRef<jobject>& jaddress);
-
   bool IsPaymentInstrumentComplete(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller,
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index efa4840b..a8ec539e 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -1199,15 +1199,6 @@
       base::TimeDelta::FromMilliseconds(50));
 }
 
-bool UiControllerAndroid::IsShippingAddressComplete(
-    autofill::AutofillProfile* address) {
-  auto* options = ui_delegate_->GetCollectUserDataOptions();
-  if (options == nullptr) {
-    return false;
-  }
-  return IsCompleteShippingAddress(address, *options);
-}
-
 bool UiControllerAndroid::IsPaymentInstrumentComplete(
     autofill::CreditCard* card,
     autofill::AutofillProfile* address) {
@@ -1437,6 +1428,20 @@
   const auto& selected_contact_errors = user_data::GetContactValidationErrors(
       selected_contact_profile, *collect_user_data_options);
 
+  const autofill::AutofillProfile* selected_shipping_address =
+      state->selected_address(collect_user_data_options->shipping_address_name);
+  auto jselected_shipping_address =
+      selected_shipping_address == nullptr
+          ? nullptr
+          : Java_AssistantCollectUserDataModel_createAutofillAddress(
+                env, jcontext,
+                autofill::PersonalDataManagerAndroid::
+                    CreateJavaProfileFromNative(env,
+                                                *selected_shipping_address));
+  const auto& selected_shipping_address_errors =
+      user_data::GetShippingAddressValidationErrors(selected_shipping_address,
+                                                    *collect_user_data_options);
+
   if (field_change == UserData::FieldChange::ALL ||
       field_change == UserData::FieldChange::AVAILABLE_PROFILES) {
     // Contact profiles.
@@ -1467,26 +1472,26 @@
         env, jmodel, jselected_contact,
         base::android::ToJavaArrayOfStrings(env, selected_contact_errors));
 
-    // Billing addresses profiles.
+    // Billing address profiles.
     auto jbillinglist =
-        Java_AssistantCollectUserDataModel_createAutofillAddressList(env);
+        Java_AssistantCollectUserDataModel_createBillingAddressList(env);
     for (const auto& profile : state->available_profiles_) {
       auto jaddress = Java_AssistantCollectUserDataModel_createAutofillAddress(
           env, jcontext,
           autofill::PersonalDataManagerAndroid::CreateJavaProfileFromNative(
               env, *profile));
       if (jaddress) {
-        Java_AssistantCollectUserDataModel_addAutofillAddress(env, jbillinglist,
-                                                              jaddress);
+        Java_AssistantCollectUserDataModel_addBillingAddress(env, jbillinglist,
+                                                             jaddress);
       }
     }
     Java_AssistantCollectUserDataModel_setAvailableBillingAddresses(
         env, jmodel, jbillinglist);
 
-    // Address profiles.
+    // Shipping address profiles.
     auto jshippinglist =
-        Java_AssistantCollectUserDataModel_createAutofillAddressList(env);
-    auto address_indices = SortAddressesByCompleteness(
+        Java_AssistantCollectUserDataModel_createShippingAddressList(env);
+    auto address_indices = user_data::SortShippingAddressesByCompleteness(
         *collect_user_data_options, state->available_profiles_);
     for (int index : address_indices) {
       auto jaddress = Java_AssistantCollectUserDataModel_createAutofillAddress(
@@ -1494,25 +1499,20 @@
           autofill::PersonalDataManagerAndroid::CreateJavaProfileFromNative(
               env, *state->available_profiles_[index]));
       if (jaddress) {
-        Java_AssistantCollectUserDataModel_addAutofillAddress(
-            env, jshippinglist, jaddress);
+        const auto& errors = user_data::GetShippingAddressValidationErrors(
+            state->available_profiles_[index].get(),
+            *collect_user_data_options);
+        Java_AssistantCollectUserDataModel_addShippingAddress(
+            env, jshippinglist, jaddress,
+            base::android::ToJavaArrayOfStrings(env, errors));
       }
     }
     Java_AssistantCollectUserDataModel_setAvailableShippingAddresses(
         env, jmodel, jshippinglist);
-
-    // Ignore changes to FieldChange::SHIPPING_ADDRESS, this is already coming
-    // from the view.
-    const autofill::AutofillProfile* shipping_address = state->selected_address(
-        collect_user_data_options->shipping_address_name);
     Java_AssistantCollectUserDataModel_setSelectedShippingAddress(
-        env, jmodel,
-        shipping_address == nullptr
-            ? nullptr
-            : Java_AssistantCollectUserDataModel_createAutofillAddress(
-                  env, jcontext,
-                  autofill::PersonalDataManagerAndroid::
-                      CreateJavaProfileFromNative(env, *shipping_address)));
+        env, jmodel, jselected_shipping_address,
+        base::android::ToJavaArrayOfStrings(env,
+                                            selected_shipping_address_errors));
   }
   if (field_change == UserData::FieldChange::CONTACT_PROFILE) {
     // The selection is already known in Java, but it has no errors. The PDM
@@ -1521,6 +1521,14 @@
         env, jmodel, jselected_contact,
         base::android::ToJavaArrayOfStrings(env, selected_contact_errors));
   }
+  if (field_change == UserData::FieldChange::SHIPPING_ADDRESS) {
+    // The selection is already known in Java, but it has no errors. The PDM
+    // off case does not set updated shipping addresses.
+    Java_AssistantCollectUserDataModel_setSelectedShippingAddress(
+        env, jmodel, jselected_shipping_address,
+        base::android::ToJavaArrayOfStrings(env,
+                                            selected_shipping_address_errors));
+  }
 
   if (field_change == UserData::FieldChange::ALL ||
       field_change == UserData::FieldChange::AVAILABLE_PAYMENT_INSTRUMENTS) {
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index afaed9d..3eda3ee 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -162,7 +162,6 @@
   void OnDateTimeRangeEndTimeSlotCleared();
   void OnKeyValueChanged(const std::string& key, const ValueProto& value);
   void OnInputTextFocusChanged(bool is_text_focused);
-  bool IsShippingAddressComplete(autofill::AutofillProfile* address);
   bool IsPaymentInstrumentComplete(autofill::CreditCard* card,
                                    autofill::AutofillProfile* address);
 
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index 8057bfb..5e1be68 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -762,11 +762,6 @@
             collect_user_data.supported_basic_card_networks().end(),
             std::back_inserter(
                 collect_user_data_options_->supported_basic_card_networks));
-
-  collect_user_data_options_->shipping_address_name =
-      collect_user_data.shipping_address_name();
-  collect_user_data_options_->request_shipping =
-      !collect_user_data.shipping_address_name().empty();
   collect_user_data_options_->request_payment_method =
       collect_user_data.request_payment_method();
   collect_user_data_options_->require_billing_postal_code =
@@ -785,7 +780,6 @@
     VLOG(1) << "Required payment method without address name";
     return false;
   }
-
   collect_user_data_options_->credit_card_expired_text =
       collect_user_data.credit_card_expired_text();
   // TODO(b/146195295): Remove fallback and enforce non-empty backend string.
@@ -794,6 +788,18 @@
         l10n_util::GetStringUTF8(
             IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED);
   }
+
+  collect_user_data_options_->shipping_address_name =
+      collect_user_data.shipping_address_name();
+  collect_user_data_options_->request_shipping =
+      !collect_user_data.shipping_address_name().empty();
+  if (collect_user_data_options_->request_shipping) {
+    collect_user_data_options_->required_shipping_address_data_pieces =
+        std::vector<RequiredDataPiece>(
+            collect_user_data.required_shipping_address_data_piece().begin(),
+            collect_user_data.required_shipping_address_data_piece().end());
+  }
+
   collect_user_data_options_->request_login_choice =
       collect_user_data.has_login_details();
   collect_user_data_options_->login_section_title.assign(
@@ -984,8 +990,9 @@
     if (collect_user_data_options_->request_shipping) {
       auto completeAddressIter = std::find_if(
           profiles.begin(), profiles.end(), [this](const auto* profile) {
-            return IsCompleteShippingAddress(
-                profile, *this->collect_user_data_options_.get());
+            return user_data::GetShippingAddressValidationErrors(
+                       profile, *this->collect_user_data_options_.get())
+                .empty();
           });
       if (completeAddressIter == profiles.end()) {
         return false;
@@ -1031,7 +1038,9 @@
       user_data.selected_address(options.shipping_address_name);
   return user_data::GetContactValidationErrors(selected_profile, options)
              .empty() &&
-         IsCompleteShippingAddress(shipping_address, options) &&
+         user_data::GetShippingAddressValidationErrors(shipping_address,
+                                                       options)
+             .empty() &&
          IsCompleteCreditCard(user_data.selected_card(), billing_address,
                               options) &&
          IsValidLoginChoice(user_data.login_choice_identifier_, options) &&
@@ -1317,7 +1326,7 @@
   if (!user_data->has_selected_address(
           collect_user_data_options_->shipping_address_name) &&
       collect_user_data_options_->request_shipping) {
-    int default_selection = GetDefaultAddressProfile(
+    int default_selection = user_data::GetDefaultShippingAddressProfile(
         *collect_user_data_options_, user_data->available_profiles_);
     if (default_selection != -1) {
       delegate_->GetUserModel()->SetSelectedAutofillProfile(
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index 99f65c1..f6422c5 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -1083,6 +1083,8 @@
   CollectUserDataOptions options;
   options.request_shipping = true;
   options.shipping_address_name = "shipping_address";
+  options.required_shipping_address_data_pieces.push_back(
+      MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
@@ -1091,9 +1093,9 @@
   user_model_.SetSelectedAutofillProfile(
       "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
       &user_data);
-  autofill::test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
-                                 "marion@me.xyz", "Fox", "123 Zoo St.",
-                                 "unit 5", "Hollywood", "CA",
+  autofill::test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", "",
+                                 "Fox", "123 Zoo St.", "unit 5", "Hollywood",
+                                 "CA",
                                  /* zipcode = */ "", "US", "16505678910");
   user_model_.SetSelectedAutofillProfile(
       "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
@@ -1101,6 +1103,15 @@
   EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
                                                          options));
 
+  // Complete for Assistant but not for AddressEditor.
+  profile.SetRawInfo(autofill::EMAIL_ADDRESS, u"marion@me.xyz");
+  user_model_.SetSelectedAutofillProfile(
+      "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
+      &user_data);
+  EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
+                                                         options));
+
+  // Complete.
   profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, u"91601");
   user_model_.SetSelectedAutofillProfile(
       "shipping_address", std::make_unique<autofill::AutofillProfile>(profile),
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 5fe6480f..f4ef6c3c 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -2350,8 +2350,10 @@
   // contact_details.contact_details_name}. NOTE: when clearing the billing
   // address, the selected credit card should also be cleared!
   repeated string clear_previous_profile_selection = 30;
+  // Defines how to evaluate validitiy of an address or credit card.
+  repeated RequiredDataPiece required_shipping_address_data_piece = 34;
 
-  reserved 7, 26, 34 to 36;
+  reserved 7, 26, 35 to 36;
 }
 
 // Stop Autofill Assistant.
diff --git a/components/autofill_assistant/browser/user_data.h b/components/autofill_assistant/browser/user_data.h
index 829df06f..0f21772 100644
--- a/components/autofill_assistant/browser/user_data.h
+++ b/components/autofill_assistant/browser/user_data.h
@@ -193,6 +193,7 @@
   std::string credit_card_expired_text;
 
   std::vector<RequiredDataPiece> required_contact_data_pieces;
+  std::vector<RequiredDataPiece> required_shipping_address_data_pieces;
 
   // If empty, terms and conditions should not be shown.
   std::string accept_terms_and_conditions_text;
diff --git a/components/autofill_assistant/browser/user_data_util.cc b/components/autofill_assistant/browser/user_data_util.cc
index b69fa8e9a..4c7cd70c 100644
--- a/components/autofill_assistant/browser/user_data_util.cc
+++ b/components/autofill_assistant/browser/user_data_util.cc
@@ -16,9 +16,11 @@
 #include "components/autofill_assistant/browser/field_formatter.h"
 #include "components/autofill_assistant/browser/url_utils.h"
 #include "components/autofill_assistant/browser/website_login_manager.h"
+#include "components/strings/grit/components_strings.h"
 #include "third_party/libaddressinput/chromium/addressinput_util.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
 #include "third_party/re2/src/re2/re2.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace autofill_assistant {
 namespace {
@@ -33,33 +35,6 @@
       profile.GetRawInfo(autofill::NAME_LAST));
 }
 
-int GetAddressCompletenessRating(const CollectUserDataOptions& options,
-                                 const autofill::AutofillProfile& profile) {
-  auto address_data = autofill::i18n::CreateAddressDataFromAutofillProfile(
-      profile, kDefaultLocale);
-  std::multimap<i18n::addressinput::AddressField,
-                i18n::addressinput::AddressProblem>
-      problems;
-  autofill::addressinput::ValidateRequiredFields(
-      *address_data, /* filter= */ nullptr, &problems);
-  return -problems.size();
-}
-
-// Helper function that compares instances of AutofillProfile by completeness
-// in regards to the current options. Full profiles should be ordered before
-// empty ones and fall back to compare the profile's name in case of equality.
-bool CompletenessCompareAddresses(const CollectUserDataOptions& options,
-                                  const autofill::AutofillProfile& a,
-                                  const autofill::AutofillProfile& b) {
-  int complete_fields_a = GetAddressCompletenessRating(options, a);
-  int complete_fields_b = GetAddressCompletenessRating(options, b);
-  if (complete_fields_a == complete_fields_b) {
-    return base::i18n::ToLower(GetProfileFullName(a))
-               .compare(base::i18n::ToLower(GetProfileFullName(b))) < 0;
-  }
-  return complete_fields_a > complete_fields_b;
-}
-
 int CountCompletePaymentInstrumentFields(const CollectUserDataOptions& options,
                                          const PaymentInstrument& instrument) {
   int complete_fields = 0;
@@ -220,11 +195,56 @@
           field_formatter::CreateAutofillMappings(b, kDefaultLocale),
           options.required_contact_data_pieces)
           .size();
-  if (incomplete_fields_a == incomplete_fields_b) {
-    return base::i18n::ToLower(GetProfileFullName(a))
-               .compare(base::i18n::ToLower(GetProfileFullName(b))) < 0;
+  if (incomplete_fields_a != incomplete_fields_b) {
+    return incomplete_fields_a <= incomplete_fields_b;
   }
-  return incomplete_fields_a <= incomplete_fields_b;
+
+  return base::i18n::ToLower(GetProfileFullName(a))
+             .compare(base::i18n::ToLower(GetProfileFullName(b))) < 0;
+}
+
+int GetAddressEditorCompletenessRating(
+    const autofill::AutofillProfile& profile) {
+  auto address_data = autofill::i18n::CreateAddressDataFromAutofillProfile(
+      profile, kDefaultLocale);
+  std::multimap<i18n::addressinput::AddressField,
+                i18n::addressinput::AddressProblem>
+      problems;
+  autofill::addressinput::ValidateRequiredFields(
+      *address_data, /* filter= */ nullptr, &problems);
+  return problems.size();
+}
+
+// Helper function that compares instances of AutofillProfile by completeness
+// in regards to the current options. Full profiles should be ordered before
+// empty ones and fall back to compare the profile's name in case of equality.
+bool CompletenessCompareShippingAddresses(const CollectUserDataOptions& options,
+                                          const autofill::AutofillProfile& a,
+                                          const autofill::AutofillProfile& b) {
+  // Compare by editor completeness first. This is done because the
+  // AddressEditor only allows storing addresses it considers complete.
+  int incomplete_fields_a = GetAddressEditorCompletenessRating(a);
+  int incomplete_fields_b = GetAddressEditorCompletenessRating(b);
+  if (incomplete_fields_a != incomplete_fields_b) {
+    return incomplete_fields_a <= incomplete_fields_b;
+  }
+
+  incomplete_fields_a =
+      GetValidationErrors(
+          field_formatter::CreateAutofillMappings(a, kDefaultLocale),
+          options.required_shipping_address_data_pieces)
+          .size();
+  incomplete_fields_b =
+      GetValidationErrors(
+          field_formatter::CreateAutofillMappings(b, kDefaultLocale),
+          options.required_shipping_address_data_pieces)
+          .size();
+  if (incomplete_fields_a != incomplete_fields_b) {
+    return incomplete_fields_a <= incomplete_fields_b;
+  }
+
+  return base::i18n::ToLower(GetProfileFullName(a))
+             .compare(base::i18n::ToLower(GetProfileFullName(b))) < 0;
 }
 
 }  // namespace
@@ -277,6 +297,59 @@
   return sorted_indices[0];
 }
 
+std::vector<std::string> GetShippingAddressValidationErrors(
+    const autofill::AutofillProfile* profile,
+    const CollectUserDataOptions& collect_user_data_options) {
+  std::vector<std::string> errors;
+  if (!collect_user_data_options.request_shipping) {
+    return errors;
+  }
+
+  if (!collect_user_data_options.required_shipping_address_data_pieces
+           .empty()) {
+    errors = GetValidationErrors(
+        profile
+            ? field_formatter::CreateAutofillMappings(*profile, kDefaultLocale)
+            : std::map<std::string, std::string>(),
+        collect_user_data_options.required_shipping_address_data_pieces);
+  }
+
+  // Require address editor completeness if Assistant validation succeeds. If
+  // Assistant validation fails, the editor has to be opened and requires
+  // completeness to save the change, do not append the (potentially duplicate)
+  // error in this case.
+  if (errors.empty() && (profile == nullptr ||
+                         GetAddressEditorCompletenessRating(*profile) != 0)) {
+    errors.push_back(l10n_util::GetStringUTF8(
+        IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING));
+  }
+  return errors;
+}
+
+std::vector<int> SortShippingAddressesByCompleteness(
+    const CollectUserDataOptions& collect_user_data_options,
+    const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles) {
+  std::vector<int> profile_indices(profiles.size());
+  std::iota(std::begin(profile_indices), std::end(profile_indices), 0);
+  std::sort(profile_indices.begin(), profile_indices.end(),
+            [&collect_user_data_options, &profiles](int i, int j) {
+              return CompletenessCompareShippingAddresses(
+                  collect_user_data_options, *profiles[i], *profiles[j]);
+            });
+  return profile_indices;
+}
+
+int GetDefaultShippingAddressProfile(
+    const CollectUserDataOptions& collect_user_data_options,
+    const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles) {
+  if (profiles.empty()) {
+    return -1;
+  }
+  auto sorted_indices =
+      SortShippingAddressesByCompleteness(collect_user_data_options, profiles);
+  return sorted_indices[0];
+}
+
 }  // namespace user_data
 
 std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
@@ -288,30 +361,6 @@
   return unique_profile;
 }
 
-std::vector<int> SortAddressesByCompleteness(
-    const CollectUserDataOptions& collect_user_data_options,
-    const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles) {
-  std::vector<int> profile_indices(profiles.size());
-  std::iota(std::begin(profile_indices), std::end(profile_indices), 0);
-  std::sort(profile_indices.begin(), profile_indices.end(),
-            [&collect_user_data_options, &profiles](int i, int j) {
-              return CompletenessCompareAddresses(collect_user_data_options,
-                                                  *profiles[i], *profiles[j]);
-            });
-  return profile_indices;
-}
-
-int GetDefaultAddressProfile(
-    const CollectUserDataOptions& collect_user_data_options,
-    const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles) {
-  if (profiles.empty()) {
-    return -1;
-  }
-  auto sorted_indices =
-      SortAddressesByCompleteness(collect_user_data_options, profiles);
-  return sorted_indices[0];
-}
-
 std::vector<int> SortPaymentInstrumentsByCompleteness(
     const CollectUserDataOptions& collect_user_data_options,
     const std::vector<std::unique_ptr<PaymentInstrument>>&
@@ -372,13 +421,6 @@
   return true;
 }
 
-bool IsCompleteShippingAddress(
-    const autofill::AutofillProfile* profile,
-    const CollectUserDataOptions& collect_user_data_options) {
-  return !collect_user_data_options.request_shipping ||
-         IsCompleteAddress(profile, /* require_postal_code = */ false);
-}
-
 bool IsCompleteCreditCard(
     const autofill::CreditCard* credit_card,
     const autofill::AutofillProfile* billing_profile,
diff --git a/components/autofill_assistant/browser/user_data_util.h b/components/autofill_assistant/browser/user_data_util.h
index 81e0024d..b408bf0 100644
--- a/components/autofill_assistant/browser/user_data_util.h
+++ b/components/autofill_assistant/browser/user_data_util.h
@@ -39,25 +39,29 @@
     const CollectUserDataOptions& collect_user_data_options,
     const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles);
 
-}  // namespace user_data
-
-std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
-    const autofill::AutofillProfile& profile);
+std::vector<std::string> GetShippingAddressValidationErrors(
+    const autofill::AutofillProfile* profile,
+    const CollectUserDataOptions& collect_user_data_options);
 
 // Sorts the given autofill profiles based on completeness, and returns a
 // vector of profile indices in sorted order. Full profiles will be ordered
 // before empty ones, and for equally complete profiles, this falls back to
 // sorting based on the profile names.
-std::vector<int> SortAddressesByCompleteness(
+std::vector<int> SortShippingAddressesByCompleteness(
     const CollectUserDataOptions& collect_user_data_options,
     const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles);
 
 // Get the default selection for the current list of profiles. Returns -1 if no
 // default selection is possible.
-int GetDefaultAddressProfile(
+int GetDefaultShippingAddressProfile(
     const CollectUserDataOptions& collect_user_data_options,
     const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles);
 
+}  // namespace user_data
+
+std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
+    const autofill::AutofillProfile& profile);
+
 // Sorts the given payment instruments by completeness, and returns a vector
 // of payment instrument indices in sorted order. Full payment instruments will
 // be ordered before empty ones, and for equally complete payment instruments,
@@ -80,10 +84,6 @@
     const autofill::AutofillProfile* a,
     const autofill::AutofillProfile* b);
 
-bool IsCompleteShippingAddress(
-    const autofill::AutofillProfile* profile,
-    const CollectUserDataOptions& collect_user_data_options);
-
 bool IsCompleteCreditCard(
     const autofill::CreditCard* credit_card,
     const autofill::AutofillProfile* billing_profile,
diff --git a/components/autofill_assistant/browser/user_data_util_unittest.cc b/components/autofill_assistant/browser/user_data_util_unittest.cc
index 559b4f3..8480cfd3 100644
--- a/components/autofill_assistant/browser/user_data_util_unittest.cc
+++ b/components/autofill_assistant/browser/user_data_util_unittest.cc
@@ -210,12 +210,12 @@
   CollectUserDataOptions options;
 
   std::vector<int> profile_indices =
-      autofill_assistant::SortAddressesByCompleteness(options, profiles);
+      user_data::SortShippingAddressesByCompleteness(options, profiles);
   EXPECT_THAT(profile_indices, SizeIs(profiles.size()));
   EXPECT_THAT(profile_indices, ElementsAre(1, 0));
 }
 
-TEST(UserDataUtilTest, SortsAddressesByCompleteness) {
+TEST(UserDataUtilTest, SortsAddressesByEditorCompleteness) {
   // Adding email address and phone number to demonstrate that they are not
   // checked for completeness.
   auto profile_no_street = std::make_unique<autofill::AutofillProfile>();
@@ -226,7 +226,7 @@
   auto profile_complete = std::make_unique<autofill::AutofillProfile>();
   autofill::test::SetProfileInfo(profile_complete.get(), "Berta", "", "West",
                                  "", "", "Brandschenkestrasse 110", "",
-                                 "Zurich", "", "8002", "UK", "");
+                                 "Zurich", "", "8002", "CH", "");
 
   // Specify profiles in reverse order to force sorting.
   std::vector<std::unique_ptr<autofill::AutofillProfile>> profiles;
@@ -236,7 +236,33 @@
   CollectUserDataOptions options;
 
   std::vector<int> profile_indices =
-      autofill_assistant::SortAddressesByCompleteness(options, profiles);
+      user_data::SortShippingAddressesByCompleteness(options, profiles);
+  EXPECT_THAT(profile_indices, SizeIs(profiles.size()));
+  EXPECT_THAT(profile_indices, ElementsAre(1, 0));
+}
+
+TEST(UserDataUtilTest, SortsAddressesByAssistantCompleteness) {
+  auto profile_no_email = std::make_unique<autofill::AutofillProfile>();
+  autofill::test::SetProfileInfo(profile_no_email.get(), "Adam", "", "West", "",
+                                 "", "Brandschenkestrasse 110", "", "Zurich",
+                                 "", "8002", "CH", "");
+
+  auto profile_complete = std::make_unique<autofill::AutofillProfile>();
+  autofill::test::SetProfileInfo(
+      profile_complete.get(), "Berta", "", "West", "berta.west@gmail.com", "",
+      "Brandschenkestrasse 110", "", "Zurich", "", "8002", "CH", "");
+
+  // Specify profiles in reverse order to force sorting.
+  std::vector<std::unique_ptr<autofill::AutofillProfile>> profiles;
+  profiles.emplace_back(std::move(profile_no_email));
+  profiles.emplace_back(std::move(profile_complete));
+
+  CollectUserDataOptions options;
+  options.required_shipping_address_data_pieces.push_back(
+      MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
+
+  std::vector<int> profile_indices =
+      user_data::SortShippingAddressesByCompleteness(options, profiles);
   EXPECT_THAT(profile_indices, SizeIs(profiles.size()));
   EXPECT_THAT(profile_indices, ElementsAre(1, 0));
 }
@@ -245,7 +271,8 @@
   std::vector<std::unique_ptr<autofill::AutofillProfile>> profiles;
   CollectUserDataOptions options;
 
-  EXPECT_THAT(GetDefaultAddressProfile(options, profiles), -1);
+  EXPECT_THAT(user_data::GetDefaultShippingAddressProfile(options, profiles),
+              -1);
 }
 
 TEST(UserDataUtilTest, GetDefaultAddressSelectionForCompleteProfiles) {
@@ -270,7 +297,8 @@
 
   CollectUserDataOptions options;
 
-  EXPECT_THAT(GetDefaultAddressProfile(options, profiles), 1);
+  EXPECT_THAT(user_data::GetDefaultShippingAddressProfile(options, profiles),
+              1);
 }
 
 TEST(UserDataUtilTest, SortsCreditCardsByCompleteness) {
@@ -625,25 +653,74 @@
   CollectUserDataOptions not_required_options;
   not_required_options.request_shipping = false;
 
-  EXPECT_TRUE(IsCompleteShippingAddress(nullptr, not_required_options));
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  nullptr, not_required_options),
+              IsEmpty());
 }
 
-TEST(UserDataUtilTest, CompleteShippingAddressRequired) {
+TEST(UserDataUtilTest, CompleteShippingAddressForAssistant) {
   autofill::AutofillProfile address;
   CollectUserDataOptions require_shipping_options;
   require_shipping_options.request_shipping = true;
+  require_shipping_options.required_shipping_address_data_pieces.push_back(
+      MakeRequiredDataPiece(
+          autofill::ServerFieldType::ADDRESS_HOME_STREET_ADDRESS));
+  require_shipping_options.required_shipping_address_data_pieces.push_back(
+      MakeRequiredDataPiece(autofill::ServerFieldType::ADDRESS_HOME_ZIP));
+  require_shipping_options.required_shipping_address_data_pieces.push_back(
+      MakeRequiredDataPiece(autofill::ServerFieldType::ADDRESS_HOME_COUNTRY));
 
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  nullptr, require_shipping_options),
+              ElementsAre("77", "35", "36"));
   autofill::test::SetProfileInfo(&address, "John", "", "Doe",
                                  "john.doe@gmail.com", "", /* address1= */ "",
                                  /* address2= */ "", /* city= */ "",
                                  /* state=  */ "", /* zip_code=  */ "",
-                                 /* country= */ "", "+41");
-  EXPECT_FALSE(IsCompleteShippingAddress(&address, require_shipping_options));
+                                 /* country= */ "", /* phone= */ "");
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  &address, require_shipping_options),
+              ElementsAre("77", "35", "36"));
+  autofill::test::SetProfileInfo(&address, "John", "", "Doe",
+                                 /* email= */ "", "", "Brandschenkestrasse 110",
+                                 "", "Zurich", "Zurich", /* zip_code= */ "",
+                                 "CH",
+                                 /* phone= */ "");
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  &address, require_shipping_options),
+              ElementsAre("35"));
   autofill::test::SetProfileInfo(&address, "John", "", "Doe",
                                  /* email= */ "", "", "Brandschenkestrasse 110",
                                  "", "Zurich", "Zurich", "8002", "CH",
                                  /* phone= */ "");
-  EXPECT_TRUE(IsCompleteShippingAddress(&address, require_shipping_options));
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  &address, require_shipping_options),
+              IsEmpty());
+}
+
+TEST(UserDataUtilTest, CompleteShippingAddressForEditor) {
+  autofill::AutofillProfile address;
+  CollectUserDataOptions require_shipping_options;
+  require_shipping_options.request_shipping = true;
+
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  nullptr, require_shipping_options),
+              ElementsAre(_));
+  autofill::test::SetProfileInfo(&address, "John", "", "Doe",
+                                 /* email= */ "", "", "Brandschenkestrasse 110",
+                                 "", "Zurich", "Zurich", /* zip_code= */ "",
+                                 "CH",
+                                 /* phone= */ "");
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  &address, require_shipping_options),
+              ElementsAre(_));
+  autofill::test::SetProfileInfo(&address, "John", "", "Doe",
+                                 /* email= */ "", "", "Brandschenkestrasse 110",
+                                 "", "Zurich", "Zurich", "8002", "CH",
+                                 /* phone= */ "");
+  EXPECT_THAT(user_data::GetShippingAddressValidationErrors(
+                  &address, require_shipping_options),
+              IsEmpty());
 }
 
 TEST(UserDataUtilTest, CompleteCreditCardNotRequired) {
diff --git a/components/autofill_assistant_strings.grdp b/components/autofill_assistant_strings.grdp
index 30c1712..aa52aff 100644
--- a/components/autofill_assistant_strings.grdp
+++ b/components/autofill_assistant_strings.grdp
@@ -3,6 +3,9 @@
   <message name="IDS_AUTOFILL_ASSISTANT_PAYMENT_INFO_CONFIRM" desc="Text on the payment request primary button to confirm payment information [CHAR_LIMIT=32]">
     Continue
   </message>
+  <message name="IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING" desc="Text label that is shown when a payment request entry (e.g., contact details or payment method) is incomplete.">
+    Information missing
+  </message>
   <message name="IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR" desc="Text label that is shown when autofill assistant cannot help anymore, because something went wrong.">
     Sorry, something went wrong.
   </message>
diff --git a/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING.png.sha1 b/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING.png.sha1
new file mode 100644
index 0000000..0c2f037
--- /dev/null
+++ b/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_PAYMENT_INFORMATION_MISSING.png.sha1
@@ -0,0 +1 @@
+a9e1c5e944e0445776057beb4d5193e39514e77a
\ No newline at end of file