| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.payments; | 5 package org.chromium.chrome.browser.payments; |
| 6 | 6 |
| 7 import android.app.ProgressDialog; |
| 7 import android.os.Handler; | 8 import android.os.Handler; |
| 8 import android.util.Pair; | 9 import android.util.Pair; |
| 9 | 10 |
| 10 import org.chromium.base.Callback; | 11 import org.chromium.base.Callback; |
| 11 import org.chromium.chrome.R; | 12 import org.chromium.chrome.R; |
| 12 import org.chromium.chrome.browser.autofill.PersonalDataManager; | 13 import org.chromium.chrome.browser.autofill.PersonalDataManager; |
| 13 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; | 14 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; |
| 15 import org.chromium.chrome.browser.autofill.PersonalDataManager.GetSubKeysReques
tDelegate; |
| 14 import org.chromium.chrome.browser.autofill.PhoneNumberUtil; | 16 import org.chromium.chrome.browser.autofill.PhoneNumberUtil; |
| 15 import org.chromium.chrome.browser.payments.ui.EditorFieldModel; | 17 import org.chromium.chrome.browser.payments.ui.EditorFieldModel; |
| 16 import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValid
ator; | 18 import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValid
ator; |
| 17 import org.chromium.chrome.browser.payments.ui.EditorModel; | 19 import org.chromium.chrome.browser.payments.ui.EditorModel; |
| 18 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge; | 20 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge; |
| 19 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.Ad
dressField; | 21 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.Ad
dressField; |
| 20 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.Ad
dressUiComponent; | 22 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.Ad
dressUiComponent; |
| 21 | 23 |
| 22 import java.util.HashMap; | 24 import java.util.HashMap; |
| 23 import java.util.HashSet; | 25 import java.util.HashSet; |
| 24 import java.util.List; | 26 import java.util.List; |
| 25 import java.util.Locale; | 27 import java.util.Locale; |
| 26 import java.util.Map; | 28 import java.util.Map; |
| 27 import java.util.Set; | 29 import java.util.Set; |
| 28 | 30 |
| 29 import javax.annotation.Nullable; | 31 import javax.annotation.Nullable; |
| 30 | 32 |
| 31 /** | 33 /** |
| 32 * An address editor. Can be used for either shipping or billing address editing
. | 34 * An address editor. Can be used for either shipping or billing address editing
. |
| 33 */ | 35 */ |
| 34 public class AddressEditor extends EditorBase<AutofillAddress> { | 36 public class AddressEditor |
| 37 extends EditorBase<AutofillAddress> implements GetSubKeysRequestDelegate
{ |
| 35 private final Handler mHandler = new Handler(); | 38 private final Handler mHandler = new Handler(); |
| 36 private final Map<Integer, EditorFieldModel> mAddressFields = new HashMap<>(
); | 39 private final Map<Integer, EditorFieldModel> mAddressFields = new HashMap<>(
); |
| 37 private final Set<CharSequence> mPhoneNumbers = new HashSet<>(); | 40 private final Set<CharSequence> mPhoneNumbers = new HashSet<>(); |
| 38 @Nullable private AutofillProfileBridge mAutofillProfileBridge; | 41 @Nullable |
| 39 @Nullable private EditorFieldModel mCountryField; | 42 private AutofillProfileBridge mAutofillProfileBridge; |
| 40 @Nullable private EditorFieldModel mPhoneField; | 43 @Nullable |
| 41 @Nullable private EditorFieldValidator mPhoneValidator; | 44 private EditorFieldModel mCountryField; |
| 42 @Nullable private List<AddressUiComponent> mAddressUiComponents; | 45 @Nullable |
| 46 private EditorFieldModel mPhoneField; |
| 47 @Nullable |
| 48 private EditorFieldValidator mPhoneValidator; |
| 49 @Nullable |
| 50 private List<AddressUiComponent> mAddressUiComponents; |
| 51 private boolean mAdminAreasLoaded; |
| 52 private String mRecentlySelectedCountry; |
| 53 private Runnable mCountryChangeCallback; |
| 54 private AutofillProfile mProfile; |
| 55 private EditorModel mEditor; |
| 56 private ProgressDialog mProgressDialog; |
| 43 | 57 |
| 44 /** | 58 /** |
| 45 * Adds the given phone number to the autocomplete set, if it's valid. | 59 * Adds the given phone number to the autocomplete set, if it's valid. |
| 46 * | 60 * |
| 47 * @param phoneNumber The phone number to possibly add. | 61 * @param phoneNumber The phone number to possibly add. |
| 48 */ | 62 */ |
| 49 public void addPhoneNumberIfValid(@Nullable CharSequence phoneNumber) { | 63 public void addPhoneNumberIfValid(@Nullable CharSequence phoneNumber) { |
| 50 if (getPhoneValidator().isValid(phoneNumber)) mPhoneNumbers.add(phoneNum
ber); | 64 if (getPhoneValidator().isValid(phoneNumber)) mPhoneNumbers.add(phoneNum
ber); |
| 51 } | 65 } |
| 52 | 66 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 65 public void edit( | 79 public void edit( |
| 66 @Nullable final AutofillAddress toEdit, final Callback<AutofillAddre
ss> callback) { | 80 @Nullable final AutofillAddress toEdit, final Callback<AutofillAddre
ss> callback) { |
| 67 super.edit(toEdit, callback); | 81 super.edit(toEdit, callback); |
| 68 | 82 |
| 69 if (mAutofillProfileBridge == null) mAutofillProfileBridge = new Autofil
lProfileBridge(); | 83 if (mAutofillProfileBridge == null) mAutofillProfileBridge = new Autofil
lProfileBridge(); |
| 70 | 84 |
| 71 // If |toEdit| is null, we're creating a new autofill profile with the c
ountry code of the | 85 // If |toEdit| is null, we're creating a new autofill profile with the c
ountry code of the |
| 72 // default locale on this device. | 86 // default locale on this device. |
| 73 boolean isNewAddress = toEdit == null; | 87 boolean isNewAddress = toEdit == null; |
| 74 | 88 |
| 75 // Ensure that |address| and |profile| are always not null. | 89 // Ensure that |address| and |mProfile| are always not null. |
| 76 final AutofillAddress address = | 90 final AutofillAddress address = |
| 77 isNewAddress ? new AutofillAddress(mContext, new AutofillProfile
()) : toEdit; | 91 isNewAddress ? new AutofillAddress(mContext, new AutofillProfile
()) : toEdit; |
| 78 final AutofillProfile profile = address.getProfile(); | 92 mProfile = address.getProfile(); |
| 79 | 93 |
| 80 // The title of the editor depends on whether we're adding a new address
or editing an | 94 // The title of the editor depends on whether we're adding a new address
or editing an |
| 81 // existing address. | 95 // existing address. |
| 82 final EditorModel editor = | 96 mEditor = |
| 83 new EditorModel(isNewAddress | 97 new EditorModel(isNewAddress ? mContext.getString(R.string.autof
ill_create_profile) |
| 84 ? mContext.getString(R.string.autofill_create_profile) | 98 : toEdit.getEditTitle()); |
| 85 : toEdit.getEditTitle()); | 99 |
| 100 // When edit is called, a new form is started, so the country on the |
| 101 // dropdown list is not changed. => mRecentlySelectedCountry should be n
ull. |
| 102 mRecentlySelectedCountry = null; |
| 86 | 103 |
| 87 // The country dropdown is always present on the editor. | 104 // The country dropdown is always present on the editor. |
| 88 if (mCountryField == null) { | 105 if (mCountryField == null) { |
| 89 mCountryField = EditorFieldModel.createDropdown( | 106 mCountryField = EditorFieldModel.createDropdown( |
| 90 mContext.getString(R.string.autofill_profile_editor_country)
, | 107 mContext.getString(R.string.autofill_profile_editor_country)
, |
| 91 AutofillProfileBridge.getSupportedCountries(), | 108 AutofillProfileBridge.getSupportedCountries(), |
| 92 null /* hint */); | 109 null /* hint */); |
| 93 } | 110 } |
| 94 | 111 |
| 95 // Changing the country will update which fields are in the model. The a
ctual fields are not | 112 // Changing the country will update which fields are in the model. The a
ctual fields are not |
| 96 // discarded, so their contents are preserved. | 113 // discarded, so their contents are preserved. |
| 97 mCountryField.setDropdownCallback(new Callback<Pair<String, Runnable>>()
{ | 114 mCountryField.setDropdownCallback(new Callback<Pair<String, Runnable>>()
{ |
| 98 @Override | 115 @Override |
| 116 /** |
| 117 * If the selected country on the country dropdown list is changed, |
| 118 * the first element of eventData is the recently selected dropdown
key, |
| 119 * the second element is the callback to invoke for when the dropdow
n |
| 120 * change has been processed. |
| 121 */ |
| 99 public void onResult(Pair<String, Runnable> eventData) { | 122 public void onResult(Pair<String, Runnable> eventData) { |
| 100 editor.removeAllFields(); | 123 mEditor.removeAllFields(); |
| 101 editor.addField(mCountryField); | 124 showProgressDialog(); |
| 102 addAddressTextFieldsToEditor(editor, eventData.first, | 125 mRecentlySelectedCountry = eventData.first; |
| 103 Locale.getDefault().getLanguage()); | 126 mCountryChangeCallback = eventData.second; |
| 104 editor.addField(mPhoneField); | 127 loadAdminAreasForCountry(mRecentlySelectedCountry); |
| 105 | |
| 106 // Notify EditorView that the fields in the model have changed.
EditorView should | |
| 107 // re-read the model and update the UI accordingly. | |
| 108 mHandler.post(eventData.second); | |
| 109 } | 128 } |
| 110 }); | 129 }); |
| 111 | 130 |
| 112 // Country dropdown is cached, so the selected item needs to be updated
for the new profile | 131 // Country dropdown is cached, so the selected item needs to be updated
for the new profile |
| 113 // that's being edited. This will not fire the dropdown callback. | 132 // that's being edited. This will not fire the dropdown callback. |
| 114 mCountryField.setValue(AutofillAddress.getCountryCode(profile)); | 133 mCountryField.setValue(AutofillAddress.getCountryCode(mProfile)); |
| 115 editor.addField(mCountryField); | |
| 116 | 134 |
| 117 // There's a finite number of fields for address editing. Changing the c
ountry will re-order | 135 // There's a finite number of fields for address editing. Changing the c
ountry will re-order |
| 118 // and relabel the fields. The meaning of each field remains the same. | 136 // and relabel the fields. The meaning of each field remains the same. |
| 119 if (mAddressFields.isEmpty()) { | 137 if (mAddressFields.isEmpty()) { |
| 120 // City, dependent locality, and organization don't have any special
formatting hints. | 138 // City, dependent locality, and organization don't have any special
formatting hints. |
| 121 mAddressFields.put(AddressField.LOCALITY, EditorFieldModel.createTex
tInput()); | 139 mAddressFields.put(AddressField.LOCALITY, EditorFieldModel.createTex
tInput()); |
| 122 mAddressFields.put(AddressField.DEPENDENT_LOCALITY, EditorFieldModel
.createTextInput()); | 140 mAddressFields.put(AddressField.DEPENDENT_LOCALITY, EditorFieldModel
.createTextInput()); |
| 123 mAddressFields.put(AddressField.ORGANIZATION, EditorFieldModel.creat
eTextInput()); | 141 mAddressFields.put(AddressField.ORGANIZATION, EditorFieldModel.creat
eTextInput()); |
| 124 | 142 |
| 125 // State should be formatted in all capitals. | |
| 126 mAddressFields.put(AddressField.ADMIN_AREA, EditorFieldModel.createT
extInput( | |
| 127 EditorFieldModel.INPUT_TYPE_HINT_REGION)); | |
| 128 | |
| 129 // Sorting code and postal code (a.k.a. ZIP code) should show both l
etters and digits on | 143 // Sorting code and postal code (a.k.a. ZIP code) should show both l
etters and digits on |
| 130 // the keyboard, if possible. | 144 // the keyboard, if possible. |
| 131 mAddressFields.put(AddressField.SORTING_CODE, EditorFieldModel.creat
eTextInput( | 145 mAddressFields.put(AddressField.SORTING_CODE, EditorFieldModel.creat
eTextInput( |
| 132 EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC)); | 146 EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC)); |
| 133 mAddressFields.put(AddressField.POSTAL_CODE, EditorFieldModel.create
TextInput( | 147 mAddressFields.put(AddressField.POSTAL_CODE, EditorFieldModel.create
TextInput( |
| 134 EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC)); | 148 EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC)); |
| 135 | 149 |
| 136 // Street line field can contain \n to indicate line breaks. | 150 // Street line field can contain \n to indicate line breaks. |
| 137 mAddressFields.put(AddressField.STREET_ADDRESS, EditorFieldModel.cre
ateTextInput( | 151 mAddressFields.put(AddressField.STREET_ADDRESS, EditorFieldModel.cre
ateTextInput( |
| 138 EditorFieldModel.INPUT_TYPE_HINT_STREET_LINES)); | 152 EditorFieldModel.INPUT_TYPE_HINT_STREET_LINES)); |
| 139 | 153 |
| 140 // Android has special formatting rules for names. | 154 // Android has special formatting rules for names. |
| 141 mAddressFields.put(AddressField.RECIPIENT, EditorFieldModel.createTe
xtInput( | 155 mAddressFields.put(AddressField.RECIPIENT, EditorFieldModel.createTe
xtInput( |
| 142 EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME)); | 156 EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME)); |
| 143 } | 157 } |
| 144 | 158 |
| 145 // Address fields are cached, so their values need to be updated for eve
ry new profile | |
| 146 // that's being edited. | |
| 147 for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySe
t()) { | |
| 148 entry.getValue().setValue(AutofillAddress.getProfileField(profile, e
ntry.getKey())); | |
| 149 } | |
| 150 | |
| 151 // Both country code and language code dictate which fields should be ad
ded to the editor. | |
| 152 // For example, "US" will not add dependent locality to the editor. A "J
P" address will | |
| 153 // start with a person's full name or a with a prefecture name, dependin
g on whether the | |
| 154 // language code is "ja-Latn" or "ja". | |
| 155 addAddressTextFieldsToEditor( | |
| 156 editor, mCountryField.getValue().toString(), profile.getLanguage
Code()); | |
| 157 | 159 |
| 158 // Phone number is present and required for all countries. | 160 // Phone number is present and required for all countries. |
| 159 if (mPhoneField == null) { | 161 if (mPhoneField == null) { |
| 160 mPhoneField = EditorFieldModel.createTextInput(EditorFieldModel.INPU
T_TYPE_HINT_PHONE, | 162 mPhoneField = EditorFieldModel.createTextInput(EditorFieldModel.INPU
T_TYPE_HINT_PHONE, |
| 161 mContext.getString(R.string.autofill_profile_editor_phone_nu
mber), | 163 mContext.getString(R.string.autofill_profile_editor_phone_nu
mber), |
| 162 mPhoneNumbers, getPhoneValidator(), null, | 164 mPhoneNumbers, getPhoneValidator(), null, |
| 163 mContext.getString(R.string.payments_field_required_validati
on_message), | 165 mContext.getString(R.string.payments_field_required_validati
on_message), |
| 164 mContext.getString(R.string.payments_phone_invalid_validatio
n_message), null); | 166 mContext.getString(R.string.payments_phone_invalid_validatio
n_message), null); |
| 165 } | 167 } |
| 166 | 168 |
| 167 // Phone number field is cached, so its value needs to be updated for ev
ery new profile | 169 // Phone number field is cached, so its value needs to be updated for ev
ery new profile |
| 168 // that's being edited. | 170 // that's being edited. |
| 169 mPhoneField.setValue(profile.getPhoneNumber()); | 171 mPhoneField.setValue(mProfile.getPhoneNumber()); |
| 170 editor.addField(mPhoneField); | |
| 171 | 172 |
| 172 // If the user clicks [Cancel], send |toEdit| address back to the caller
, which was the | 173 // If the user clicks [Cancel], send |toEdit| address back to the caller
, which was the |
| 173 // original state (could be null, a complete address, a partial address)
. | 174 // original state (could be null, a complete address, a partial address)
. |
| 174 editor.setCancelCallback(new Runnable() { | 175 mEditor.setCancelCallback(new Runnable() { |
| 175 @Override | 176 @Override |
| 176 public void run() { | 177 public void run() { |
| 178 // This makes sure that onSubKeysReceived returns early if it's |
| 179 // ever called when Cancel has already occurred. |
| 180 mAdminAreasLoaded = true; |
| 181 PersonalDataManager.getInstance().cancelPendingGetSubKeys(); |
| 177 callback.onResult(toEdit); | 182 callback.onResult(toEdit); |
| 178 } | 183 } |
| 179 }); | 184 }); |
| 180 | 185 |
| 181 // If the user clicks [Done], save changes on disk, mark the address "co
mplete," and send it | 186 // If the user clicks [Done], save changes on disk, mark the address "co
mplete," and send it |
| 182 // back to the caller. | 187 // back to the caller. |
| 183 editor.setDoneCallback(new Runnable() { | 188 mEditor.setDoneCallback(new Runnable() { |
| 184 @Override | 189 @Override |
| 185 public void run() { | 190 public void run() { |
| 186 commitChanges(profile); | 191 mAdminAreasLoaded = true; |
| 187 address.completeAddress(profile); | 192 PersonalDataManager.getInstance().cancelPendingGetSubKeys(); |
| 193 commitChanges(mProfile); |
| 194 address.completeAddress(mProfile); |
| 188 callback.onResult(address); | 195 callback.onResult(address); |
| 189 } | 196 } |
| 190 }); | 197 }); |
| 191 | 198 |
| 192 mEditorView.show(editor); | 199 loadAdminAreasForCountry(mProfile.getCountryCode()); |
| 200 } |
| 201 |
| 202 private void showProgressDialog() { |
| 203 mProgressDialog = new ProgressDialog(mContext); |
| 204 mProgressDialog.setMessage(mContext.getText(R.string.payments_loading_me
ssage)); |
| 205 mProgressDialog.show(); |
| 206 } |
| 207 |
| 208 private void dismissProgressDialog() { |
| 209 if (mProgressDialog != null && mProgressDialog.isShowing()) { |
| 210 mProgressDialog.dismiss(); |
| 211 } |
| 212 mProgressDialog = null; |
| 193 } | 213 } |
| 194 | 214 |
| 195 /** Saves the edited profile on disk. */ | 215 /** Saves the edited profile on disk. */ |
| 196 private void commitChanges(AutofillProfile profile) { | 216 private void commitChanges(AutofillProfile profile) { |
| 197 // Country code and phone number are always required and are always coll
ected from the | 217 // Country code and phone number are always required and are always coll
ected from the |
| 198 // editor model. | 218 // editor model. |
| 199 profile.setCountryCode(mCountryField.getValue().toString()); | 219 profile.setCountryCode(mCountryField.getValue().toString()); |
| 200 profile.setPhoneNumber(mPhoneField.getValue().toString()); | 220 profile.setPhoneNumber(mPhoneField.getValue().toString()); |
| 201 | 221 |
| 202 // Autofill profile bridge normalizes the language code for the autofill
profile. | 222 // Autofill profile bridge normalizes the language code for the autofill
profile. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 214 | 234 |
| 215 // Clear the fields that are hidden from the user interface, so | 235 // Clear the fields that are hidden from the user interface, so |
| 216 // AutofillAddress.toPaymentAddress() will send them to the renderer as
empty strings. | 236 // AutofillAddress.toPaymentAddress() will send them to the renderer as
empty strings. |
| 217 for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySe
t()) { | 237 for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySe
t()) { |
| 218 if (!visibleFields.contains(entry.getKey())) { | 238 if (!visibleFields.contains(entry.getKey())) { |
| 219 setProfileField(profile, entry.getKey(), ""); | 239 setProfileField(profile, entry.getKey(), ""); |
| 220 } | 240 } |
| 221 } | 241 } |
| 222 | 242 |
| 223 // Save the edited autofill profile locally. | 243 // Save the edited autofill profile locally. |
| 224 profile.setGUID(PersonalDataManager.getInstance().setProfileToLocal(prof
ile)); | 244 profile.setGUID(PersonalDataManager.getInstance().setProfileToLocal(mPro
file)); |
| 225 profile.setIsLocal(true); | 245 profile.setIsLocal(true); |
| 226 } | 246 } |
| 227 | 247 |
| 228 /** Writes the given value into the specified autofill profile field. */ | 248 /** Writes the given value into the specified autofill profile field. */ |
| 229 private static void setProfileField( | 249 private static void setProfileField( |
| 230 AutofillProfile profile, int field, @Nullable CharSequence value) { | 250 AutofillProfile profile, int field, @Nullable CharSequence value) { |
| 231 assert profile != null; | 251 assert profile != null; |
| 232 switch (field) { | 252 switch (field) { |
| 233 case AddressField.COUNTRY: | 253 case AddressField.COUNTRY: |
| 234 profile.setCountryCode(ensureNotNull(value)); | 254 profile.setCountryCode(ensureNotNull(value)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 259 return; | 279 return; |
| 260 } | 280 } |
| 261 | 281 |
| 262 assert false; | 282 assert false; |
| 263 } | 283 } |
| 264 | 284 |
| 265 private static String ensureNotNull(@Nullable CharSequence value) { | 285 private static String ensureNotNull(@Nullable CharSequence value) { |
| 266 return value == null ? "" : value.toString(); | 286 return value == null ? "" : value.toString(); |
| 267 } | 287 } |
| 268 | 288 |
| 289 private void setAddressFieldValuesFromCache() { |
| 290 // Address fields are cached, so their values need to be updated for eve
ry new profile |
| 291 // that's being edited. |
| 292 for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySe
t()) { |
| 293 entry.getValue().setValue(AutofillAddress.getProfileField(mProfile,
entry.getKey())); |
| 294 } |
| 295 } |
| 296 |
| 297 @Override |
| 298 public void onSubKeysReceived(String[] adminAreas) { |
| 299 if (mAdminAreasLoaded) return; |
| 300 mAdminAreasLoaded = true; |
| 301 |
| 302 // If Chrome can't get admin areas from the server or there is no admin
area on the server, |
| 303 // then use the text field. |
| 304 // Otherwise, use the dropdown list. |
| 305 if (adminAreas == null || adminAreas.length == 0) { |
| 306 mAddressFields.put(AddressField.ADMIN_AREA, EditorFieldModel.createT
extInput()); |
| 307 } else { |
| 308 mAddressFields.put(AddressField.ADMIN_AREA, EditorFieldModel.createD
ropdown()); |
| 309 } |
| 310 |
| 311 // Admin areas need to be fetched in two cases: |
| 312 // 1. Initial loading of the form. |
| 313 // 2. When the selected country is changed in the form. |
| 314 // mRecentlySelectedCountry is not null if and only if it's the second c
ase |
| 315 if (mRecentlySelectedCountry != null) { |
| 316 dismissProgressDialog(); |
| 317 // Both country code and language code dictate which fields should b
e added to the |
| 318 // editor. |
| 319 // For example, "US" will not add dependent locality to the editor.
A "JP" address will |
| 320 // start with a person's full name or a with a prefecture name, depe
nding on whether the |
| 321 // language code is "ja-Latn" or "ja". |
| 322 addAddressFieldsToEditor( |
| 323 mRecentlySelectedCountry, Locale.getDefault().getLanguage(),
adminAreas); |
| 324 // Notify EditorView that the fields in the model have changed. Edit
orView should |
| 325 // re-read the model and update the UI accordingly. |
| 326 mHandler.post(mCountryChangeCallback); |
| 327 } else { |
| 328 // This should be called when all required fields are put in mAddres
sField. |
| 329 setAddressFieldValuesFromCache(); |
| 330 addAddressFieldsToEditor( |
| 331 mProfile.getCountryCode(), mProfile.getLanguageCode(), admin
Areas); |
| 332 mEditorView.show(mEditor); |
| 333 } |
| 334 } |
| 335 |
| 336 /** Requests the list of admin areas. */ |
| 337 private void loadAdminAreasForCountry(String countryCode) { |
| 338 // Used to check if the callback is called (for time-out). |
| 339 mAdminAreasLoaded = false; |
| 340 |
| 341 // In each rule, admin area keys are saved under sub-keys of country. |
| 342 PersonalDataManager.getInstance().loadRulesForSubKeys(countryCode); |
| 343 PersonalDataManager.getInstance().getRegionSubKeys(countryCode, this); |
| 344 onAdminAreasLoading(); |
| 345 } |
| 346 |
| 347 /** Cancels the request for the list of admin areas. */ |
| 348 private void cancelAdminAreasRequest() { |
| 349 if (mAdminAreasLoaded) return; |
| 350 onSubKeysReceived(null); |
| 351 PersonalDataManager.getInstance().cancelPendingGetSubKeys(); |
| 352 } |
| 353 |
| 269 /** | 354 /** |
| 270 * Adds text fields to the editor model based on the country and language co
de of the profile | 355 * In case the the admin areas are not loaded yet, or the time out is set to
0 for testing, |
| 271 * that's being edited. | 356 * starts a timer to cancel the request. |
| 272 */ | 357 */ |
| 273 private void addAddressTextFieldsToEditor( | 358 public void onAdminAreasLoading() { |
| 274 EditorModel container, String countryCode, String languageCode) { | 359 if (mAdminAreasLoaded) return; |
| 275 mAddressUiComponents = mAutofillProfileBridge.getAddressUiComponents(cou
ntryCode, | 360 new Handler().postDelayed(new Runnable() { |
| 276 languageCode); | 361 @Override |
| 362 public void run() { |
| 363 cancelAdminAreasRequest(); |
| 364 } |
| 365 }, PersonalDataManager.getInstance().getRequestTimeoutMS()); |
| 366 } |
| 277 | 367 |
| 368 /** |
| 369 * Adds fields to the editor model based on the country and language code of |
| 370 * the profile that's being edited. |
| 371 */ |
| 372 private void addAddressFieldsToEditor( |
| 373 String countryCode, String languageCode, String[] adminAreas) { |
| 374 mAddressUiComponents = |
| 375 mAutofillProfileBridge.getAddressUiComponents(countryCode, langu
ageCode); |
| 376 // In terms of order, country must be the first field. |
| 377 mEditor.addField(mCountryField); |
| 278 for (int i = 0; i < mAddressUiComponents.size(); i++) { | 378 for (int i = 0; i < mAddressUiComponents.size(); i++) { |
| 279 AddressUiComponent component = mAddressUiComponents.get(i); | 379 AddressUiComponent component = mAddressUiComponents.get(i); |
| 280 | 380 |
| 281 // The country field is a dropdown, so there's no need to add a text
field for it. | |
| 282 if (component.id == AddressField.COUNTRY) continue; | |
| 283 | |
| 284 EditorFieldModel field = mAddressFields.get(component.id); | 381 EditorFieldModel field = mAddressFields.get(component.id); |
| 285 // Labels depend on country, e.g., state is called province in some
countries. These are | 382 // Labels depend on country, e.g., state is called province in some
countries. These are |
| 286 // already localized. | 383 // already localized. |
| 287 field.setLabel(component.label); | 384 field.setLabel(component.label); |
| 288 field.setIsFullLine(component.isFullLine); | 385 field.setIsFullLine(component.isFullLine); |
| 289 | 386 |
| 387 if (component.id == AddressField.ADMIN_AREA && field.isDropdownField
()) { |
| 388 field.setDropdownKeyValues( |
| 389 mAutofillProfileBridge.getAdminAreaDropdownList(adminAre
as)); |
| 390 } |
| 391 |
| 290 // Libaddressinput formats do not always require the full name (RECI
PIENT), but | 392 // Libaddressinput formats do not always require the full name (RECI
PIENT), but |
| 291 // PaymentRequest does. | 393 // PaymentRequest does. |
| 292 if (component.isRequired || component.id == AddressField.RECIPIENT)
{ | 394 if (component.isRequired || component.id == AddressField.RECIPIENT)
{ |
| 293 field.setRequiredErrorMessage(mContext.getString( | 395 field.setRequiredErrorMessage(mContext.getString( |
| 294 R.string.payments_field_required_validation_message)); | 396 R.string.payments_field_required_validation_message)); |
| 295 } else { | 397 } else { |
| 296 field.setRequiredErrorMessage(null); | 398 field.setRequiredErrorMessage(null); |
| 297 } | 399 } |
| 298 | 400 mEditor.addField(field); |
| 299 container.addField(field); | |
| 300 } | 401 } |
| 402 // Phone number must be the last field. |
| 403 mEditor.addField(mPhoneField); |
| 301 } | 404 } |
| 302 | 405 |
| 303 private EditorFieldValidator getPhoneValidator() { | 406 private EditorFieldValidator getPhoneValidator() { |
| 304 if (mPhoneValidator == null) { | 407 if (mPhoneValidator == null) { |
| 305 mPhoneValidator = new EditorFieldValidator() { | 408 mPhoneValidator = new EditorFieldValidator() { |
| 306 @Override | 409 @Override |
| 307 public boolean isValid(@Nullable CharSequence value) { | 410 public boolean isValid(@Nullable CharSequence value) { |
| 308 return value != null && PhoneNumberUtil.isValidNumber(value.
toString()); | 411 return value != null && PhoneNumberUtil.isValidNumber(value.
toString()); |
| 309 } | 412 } |
| 310 | 413 |
| 311 @Override | 414 @Override |
| 312 public boolean isLengthMaximum(@Nullable CharSequence value) { | 415 public boolean isLengthMaximum(@Nullable CharSequence value) { |
| 313 return false; | 416 return false; |
| 314 } | 417 } |
| 315 }; | 418 }; |
| 316 } | 419 } |
| 317 return mPhoneValidator; | 420 return mPhoneValidator; |
| 318 } | 421 } |
| 319 } | 422 } |
| OLD | NEW |