blob: 1bb1616ed91d3aa24da46c941d1ecf5091c6c302 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.autofill;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.text.format.DateUtils;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileKey;
import org.chromium.components.autofill.VirtualCardEnrollmentState;
import org.chromium.components.image_fetcher.ImageFetcher;
import org.chromium.components.image_fetcher.ImageFetcherConfig;
import org.chromium.components.image_fetcher.ImageFetcherFactory;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Android wrapper of the PersonalDataManager which provides access from the Java
* layer.
*
* Only usable from the UI thread as it's primary purpose is for supporting the Android
* preferences UI.
*
* See chrome/browser/autofill/personal_data_manager.h for more details.
*/
@JNINamespace("autofill")
public class PersonalDataManager {
private static final String TAG = "PersonalDataManager";
/**
* Observer of PersonalDataManager events.
*/
public interface PersonalDataManagerObserver {
/**
* Called when the data is changed.
*/
void onPersonalDataChanged();
}
/**
* Callback for subKeys request.
*/
public interface GetSubKeysRequestDelegate {
/**
* Called when the subkeys are received sucessfully.
* Here the subkeys are admin areas.
*
* @param subKeysCodes The subkeys' codes.
* @param subKeysNames The subkeys' names.
*/
@CalledByNative("GetSubKeysRequestDelegate")
void onSubKeysReceived(String[] subKeysCodes, String[] subKeysNames);
}
/**
* Callback for normalized addresses.
*/
public interface NormalizedAddressRequestDelegate {
/**
* Called when the address has been sucessfully normalized.
*
* @param profile The profile with the normalized address.
*/
@CalledByNative("NormalizedAddressRequestDelegate")
void onAddressNormalized(AutofillProfile profile);
/**
* Called when the address could not be normalized.
*
* @param profile The non normalized profile.
*/
@CalledByNative("NormalizedAddressRequestDelegate")
void onCouldNotNormalize(AutofillProfile profile);
}
@VisibleForTesting
static class ValueWithStatus {
static final ValueWithStatus EMPTY = new ValueWithStatus("", VerificationStatus.NO_STATUS);
private final String mValue;
private final @VerificationStatus int mStatus;
ValueWithStatus(String value, @VerificationStatus int status) {
mValue = value;
mStatus = status;
}
String getValue() {
return mValue;
}
@VerificationStatus
int getStatus() {
return mStatus;
}
}
/**
* Autofill address information.
* The creation and/or modification of an AutofillProfile is assumed to involve the user (e.g.
* data reviewed by the user in the {@link
* org.chromium.chrome.browser.autofill.settings.AddressEditor}), therefore all new values gain
* {@link VerificationStatus.USER_VERIFIED} status.
*/
public static class AutofillProfile {
private String mGUID;
private boolean mIsLocal;
private @Source int mSource;
private ValueWithStatus mHonorificPrefix;
private ValueWithStatus mFullName;
private ValueWithStatus mCompanyName;
private ValueWithStatus mStreetAddress;
private ValueWithStatus mRegion;
private ValueWithStatus mLocality;
private ValueWithStatus mDependentLocality;
private ValueWithStatus mPostalCode;
private ValueWithStatus mSortingCode;
private ValueWithStatus mCountryCode;
private ValueWithStatus mPhoneNumber;
private ValueWithStatus mEmailAddress;
private String mLabel;
private String mLanguageCode;
/**
* Builder for the {@link AutofillProfile}.
*/
public static final class Builder {
private String mGUID = "";
private boolean mIsLocal = true;
private @Source int mSource = Source.LOCAL_OR_SYNCABLE;
private ValueWithStatus mHonorificPrefix = ValueWithStatus.EMPTY;
private ValueWithStatus mFullName = ValueWithStatus.EMPTY;
private ValueWithStatus mCompanyName = ValueWithStatus.EMPTY;
private ValueWithStatus mStreetAddress = ValueWithStatus.EMPTY;
private ValueWithStatus mRegion = ValueWithStatus.EMPTY;
private ValueWithStatus mLocality = ValueWithStatus.EMPTY;
private ValueWithStatus mDependentLocality = ValueWithStatus.EMPTY;
private ValueWithStatus mPostalCode = ValueWithStatus.EMPTY;
private ValueWithStatus mSortingCode = ValueWithStatus.EMPTY;
private ValueWithStatus mCountryCode = ValueWithStatus.EMPTY;
private ValueWithStatus mPhoneNumber = ValueWithStatus.EMPTY;
private ValueWithStatus mEmailAddress = ValueWithStatus.EMPTY;
private String mLabel = "";
private String mLanguageCode = "";
public Builder setGUID(String guid) {
mGUID = guid;
return this;
}
public Builder setIsLocal(boolean isLocal) {
mIsLocal = isLocal;
return this;
}
public Builder setSource(@Source int source) {
mSource = source;
return this;
}
public Builder setHonorificPrefix(String honorificPrefix) {
mHonorificPrefix =
new ValueWithStatus(honorificPrefix, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setHonorificPrefix(
String honorificPrefix, @VerificationStatus int status) {
mHonorificPrefix = new ValueWithStatus(honorificPrefix, status);
return this;
}
public Builder setFullName(String fullName) {
mFullName = new ValueWithStatus(fullName, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setFullName(String fullName, @VerificationStatus int status) {
mFullName = new ValueWithStatus(fullName, status);
return this;
}
public Builder setCompanyName(String companyName) {
mCompanyName = new ValueWithStatus(companyName, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setCompanyName(String companyName, @VerificationStatus int status) {
mCompanyName = new ValueWithStatus(companyName, status);
return this;
}
public Builder setStreetAddress(String streetAddress) {
mStreetAddress =
new ValueWithStatus(streetAddress, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setStreetAddress(String streetAddress, @VerificationStatus int status) {
mStreetAddress = new ValueWithStatus(streetAddress, status);
return this;
}
public Builder setRegion(String region) {
mRegion = new ValueWithStatus(region, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setRegion(String region, @VerificationStatus int status) {
mRegion = new ValueWithStatus(region, status);
return this;
}
public Builder setLocality(String locality) {
mLocality = new ValueWithStatus(locality, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setLocality(String locality, @VerificationStatus int status) {
mLocality = new ValueWithStatus(locality, status);
return this;
}
public Builder setDependentLocality(String dependentLocality) {
mDependentLocality =
new ValueWithStatus(dependentLocality, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setDependentLocality(
String dependentLocality, @VerificationStatus int status) {
mDependentLocality = new ValueWithStatus(dependentLocality, status);
return this;
}
public Builder setPostalCode(String postalCode) {
mPostalCode = new ValueWithStatus(postalCode, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setPostalCode(String postalCode, @VerificationStatus int status) {
mPostalCode = new ValueWithStatus(postalCode, status);
return this;
}
public Builder setSortingCode(String sortingCode) {
mSortingCode = new ValueWithStatus(sortingCode, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setSortingCode(String sortingCode, @VerificationStatus int status) {
mSortingCode = new ValueWithStatus(sortingCode, status);
return this;
}
public Builder setCountryCode(String countryCode) {
mCountryCode = new ValueWithStatus(countryCode, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setCountryCode(String countryCode, @VerificationStatus int status) {
mCountryCode = new ValueWithStatus(countryCode, status);
return this;
}
public Builder setPhoneNumber(String phoneNumber) {
mPhoneNumber = new ValueWithStatus(phoneNumber, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setPhoneNumber(String phoneNumber, @VerificationStatus int status) {
mPhoneNumber = new ValueWithStatus(phoneNumber, status);
return this;
}
public Builder setEmailAddress(String emailAddress) {
mEmailAddress = new ValueWithStatus(emailAddress, VerificationStatus.USER_VERIFIED);
return this;
}
public Builder setEmailAddress(String emailAddress, @VerificationStatus int status) {
mEmailAddress = new ValueWithStatus(emailAddress, status);
return this;
}
public Builder setLabel(String label) {
mLabel = label;
return this;
}
public Builder setLanguageCode(String languageCode) {
mLanguageCode = languageCode;
return this;
}
public AutofillProfile build() {
return new AutofillProfile(mGUID, mIsLocal, mSource, mHonorificPrefix, mFullName,
mCompanyName, mStreetAddress, mRegion, mLocality, mDependentLocality,
mPostalCode, mSortingCode, mCountryCode, mPhoneNumber, mEmailAddress,
mLanguageCode);
}
}
public static Builder builder() {
return new Builder();
}
@CalledByNative("AutofillProfile")
private static AutofillProfile create(String guid, boolean isLocal, @Source int source,
String honorificPrefix, @VerificationStatus int honorificPrefixStatus,
String fullName, @VerificationStatus int fullNameStatus, String companyName,
@VerificationStatus int companyNameStatus, String streetAddress,
@VerificationStatus int streetAddressStatus, String region,
@VerificationStatus int regionStatus, String locality,
@VerificationStatus int localityStatus, String dependentLocality,
@VerificationStatus int dependentLocalityStatus, String postalCode,
@VerificationStatus int postalCodeStatus, String sortingCode,
@VerificationStatus int sortingCodeStatus, String countryCode,
@VerificationStatus int countryCodeStatus, String phoneNumber,
@VerificationStatus int phoneNumberStatus, String emailAddress,
@VerificationStatus int emailAddressStatus, String languageCode) {
return new AutofillProfile(guid, isLocal, source,
new ValueWithStatus(honorificPrefix, honorificPrefixStatus),
new ValueWithStatus(fullName, fullNameStatus),
new ValueWithStatus(companyName, companyNameStatus),
new ValueWithStatus(streetAddress, streetAddressStatus),
new ValueWithStatus(region, regionStatus),
new ValueWithStatus(locality, localityStatus),
new ValueWithStatus(dependentLocality, dependentLocalityStatus),
new ValueWithStatus(postalCode, postalCodeStatus),
new ValueWithStatus(sortingCode, sortingCodeStatus),
new ValueWithStatus(countryCode, countryCodeStatus),
new ValueWithStatus(phoneNumber, phoneNumberStatus),
new ValueWithStatus(emailAddress, emailAddressStatus), languageCode);
}
// TODO(crbug/1408117): remove duplicate constructors when the source is unnecessary.
private AutofillProfile(String guid, boolean isLocal, @Source int source,
ValueWithStatus honorificPrefix, ValueWithStatus fullName,
ValueWithStatus companyName, ValueWithStatus streetAddress, ValueWithStatus region,
ValueWithStatus locality, ValueWithStatus dependentLocality,
ValueWithStatus postalCode, ValueWithStatus sortingCode,
ValueWithStatus countryCode, ValueWithStatus phoneNumber,
ValueWithStatus emailAddress, String languageCode) {
mGUID = guid;
mIsLocal = isLocal;
mSource = source;
mHonorificPrefix = honorificPrefix;
mFullName = fullName;
mCompanyName = companyName;
mStreetAddress = streetAddress;
mRegion = region;
mLocality = locality;
mDependentLocality = dependentLocality;
mPostalCode = postalCode;
mSortingCode = sortingCode;
mCountryCode = countryCode;
mPhoneNumber = phoneNumber;
mEmailAddress = emailAddress;
mLanguageCode = languageCode;
}
/* Builds an AutofillProfile that is an exact copy of the one passed as parameter. */
public AutofillProfile(AutofillProfile profile) {
mGUID = profile.getGUID();
mIsLocal = profile.getIsLocal();
mSource = profile.getSource();
mHonorificPrefix = new ValueWithStatus(
profile.getHonorificPrefix(), profile.getHonorificPrefixStatus());
mFullName = new ValueWithStatus(profile.getFullName(), profile.getFullNameStatus());
mCompanyName =
new ValueWithStatus(profile.getCompanyName(), profile.getCompanyNameStatus());
mStreetAddress = new ValueWithStatus(
profile.getStreetAddress(), profile.getStreetAddressStatus());
mRegion = new ValueWithStatus(profile.getRegion(), profile.getRegionStatus());
mLocality = new ValueWithStatus(profile.getLocality(), profile.getLocalityStatus());
mDependentLocality = new ValueWithStatus(
profile.getDependentLocality(), profile.getDependentLocalityStatus());
mPostalCode =
new ValueWithStatus(profile.getPostalCode(), profile.getPostalCodeStatus());
mSortingCode =
new ValueWithStatus(profile.getSortingCode(), profile.getSortingCodeStatus());
mCountryCode =
new ValueWithStatus(profile.getCountryCode(), profile.getCountryCodeStatus());
mPhoneNumber =
new ValueWithStatus(profile.getPhoneNumber(), profile.getPhoneNumberStatus());
mEmailAddress =
new ValueWithStatus(profile.getEmailAddress(), profile.getEmailAddressStatus());
mLanguageCode = profile.getLanguageCode();
mLabel = profile.getLabel();
}
@CalledByNative("AutofillProfile")
public String getGUID() {
return mGUID;
}
@CalledByNative("AutofillProfile")
public @Source int getSource() {
return mSource;
}
@CalledByNative("AutofillProfile")
public String getHonorificPrefix() {
return mHonorificPrefix.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getHonorificPrefixStatus() {
return mHonorificPrefix.getStatus();
}
@CalledByNative("AutofillProfile")
public String getFullName() {
return mFullName.getValue();
}
@CalledByNative("AutofillProfile")
@VisibleForTesting
@VerificationStatus
int getFullNameStatus() {
return mFullName.getStatus();
}
@CalledByNative("AutofillProfile")
public String getCompanyName() {
return mCompanyName.getValue();
}
@CalledByNative("AutofillProfile")
@VerificationStatus
int getCompanyNameStatus() {
return mCompanyName.getStatus();
}
@CalledByNative("AutofillProfile")
public String getStreetAddress() {
return mStreetAddress.getValue();
}
@CalledByNative("AutofillProfile")
@VisibleForTesting
@VerificationStatus
int getStreetAddressStatus() {
return mStreetAddress.getStatus();
}
@CalledByNative("AutofillProfile")
public String getRegion() {
return mRegion.getValue();
}
@CalledByNative("AutofillProfile")
@VisibleForTesting
@VerificationStatus
int getRegionStatus() {
return mRegion.getStatus();
}
@CalledByNative("AutofillProfile")
public String getLocality() {
return mLocality.getValue();
}
@CalledByNative("AutofillProfile")
@VisibleForTesting
@VerificationStatus
int getLocalityStatus() {
return mLocality.getStatus();
}
@CalledByNative("AutofillProfile")
public String getDependentLocality() {
return mDependentLocality.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getDependentLocalityStatus() {
return mDependentLocality.getStatus();
}
public String getLabel() {
return mLabel;
}
@CalledByNative("AutofillProfile")
public String getPostalCode() {
return mPostalCode.getValue();
}
@CalledByNative("AutofillProfile")
@VisibleForTesting
@VerificationStatus
int getPostalCodeStatus() {
return mPostalCode.getStatus();
}
@CalledByNative("AutofillProfile")
public String getSortingCode() {
return mSortingCode.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getSortingCodeStatus() {
return mSortingCode.getStatus();
}
@CalledByNative("AutofillProfile")
public String getCountryCode() {
return mCountryCode.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getCountryCodeStatus() {
return mCountryCode.getStatus();
}
@CalledByNative("AutofillProfile")
public String getPhoneNumber() {
return mPhoneNumber.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getPhoneNumberStatus() {
return mPhoneNumber.getStatus();
}
@CalledByNative("AutofillProfile")
public String getEmailAddress() {
return mEmailAddress.getValue();
}
@CalledByNative("AutofillProfile")
private @VerificationStatus int getEmailAddressStatus() {
return mEmailAddress.getStatus();
}
@CalledByNative("AutofillProfile")
public String getLanguageCode() {
return mLanguageCode;
}
public boolean getIsLocal() {
return mIsLocal;
}
public void setGUID(String guid) {
mGUID = guid;
}
public void setLabel(String label) {
mLabel = label;
}
public void setSource(@Source int source) {
mSource = source;
}
public void setHonorificPrefix(String honorificPrefix) {
mHonorificPrefix =
new ValueWithStatus(honorificPrefix, VerificationStatus.USER_VERIFIED);
}
public void setFullName(String fullName) {
mFullName = new ValueWithStatus(fullName, VerificationStatus.USER_VERIFIED);
}
public void setCompanyName(String companyName) {
mCompanyName = new ValueWithStatus(companyName, VerificationStatus.USER_VERIFIED);
}
public void setStreetAddress(String streetAddress) {
mStreetAddress = new ValueWithStatus(streetAddress, VerificationStatus.USER_VERIFIED);
}
public void setRegion(String region) {
mRegion = new ValueWithStatus(region, VerificationStatus.USER_VERIFIED);
}
public void setLocality(String locality) {
mLocality = new ValueWithStatus(locality, VerificationStatus.USER_VERIFIED);
}
public void setDependentLocality(String dependentLocality) {
mDependentLocality =
new ValueWithStatus(dependentLocality, VerificationStatus.USER_VERIFIED);
}
public void setPostalCode(String postalCode) {
mPostalCode = new ValueWithStatus(postalCode, VerificationStatus.USER_VERIFIED);
}
public void setSortingCode(String sortingCode) {
mSortingCode = new ValueWithStatus(sortingCode, VerificationStatus.USER_VERIFIED);
}
public void setCountryCode(String countryCode) {
mCountryCode = new ValueWithStatus(countryCode, VerificationStatus.USER_VERIFIED);
}
public void setPhoneNumber(String phoneNumber) {
mPhoneNumber = new ValueWithStatus(phoneNumber, VerificationStatus.USER_VERIFIED);
}
public void setEmailAddress(String emailAddress) {
mEmailAddress = new ValueWithStatus(emailAddress, VerificationStatus.USER_VERIFIED);
}
public void setLanguageCode(String languageCode) {
mLanguageCode = languageCode;
}
public void setIsLocal(boolean isLocal) {
mIsLocal = isLocal;
}
/** Used by ArrayAdapter in credit card settings. */
@Override
public String toString() {
return mLabel;
}
}
/**
* Autofill credit card information.
*/
public static class CreditCard {
// Note that while some of these fields are numbers, they're predominantly read,
// marshaled and compared as strings. To save conversions, we sometimes use strings.
private String mGUID;
private String mOrigin;
private boolean mIsLocal;
private boolean mIsCached;
private boolean mIsVirtual;
private String mName;
private String mNumber;
private String mNetworkAndLastFourDigits;
private String mMonth;
private String mYear;
private String mBasicCardIssuerNetwork;
private int mIssuerIconDrawableId;
private String mBillingAddressId;
private final String mServerId;
private final long mInstrumentId;
// The label set for the card. This could be one of Card Network + LastFour, Nickname +
// LastFour or a Google specific string for Google-issued cards. This is used for displaying
// the card in PaymentMethods in Settings.
private String mCardLabel;
private String mNickname;
private GURL mCardArtUrl;
private final @VirtualCardEnrollmentState int mVirtualCardEnrollmentState;
private final String mProductDescription;
private final String mCardNameForAutofillDisplay;
private final String mObfuscatedLastFourDigits;
@CalledByNative("CreditCard")
public static CreditCard create(String guid, String origin, boolean isLocal,
boolean isCached, boolean isVirtual, String name, String number,
String networkAndLastFourDigits, String month, String year,
String basicCardIssuerNetwork, int iconId, String billingAddressId, String serverId,
long instrumentId, String cardLabel, String nickname, GURL cardArtUrl,
@VirtualCardEnrollmentState int virtualCardEnrollmentState,
String productDescription, String cardNameForAutofillDisplay,
String obfuscatedLastFourDigits) {
return new CreditCard(guid, origin, isLocal, isCached, isVirtual, name, number,
networkAndLastFourDigits, month, year, basicCardIssuerNetwork, iconId,
billingAddressId, serverId, instrumentId, cardLabel, nickname, cardArtUrl,
virtualCardEnrollmentState, productDescription, cardNameForAutofillDisplay,
obfuscatedLastFourDigits);
}
public CreditCard(String guid, String origin, boolean isLocal, boolean isCached,
String name, String number, String networkAndLastFourDigits, String month,
String year, String basicCardIssuerNetwork, int issuerIconDrawableId,
String billingAddressId, String serverId) {
this(guid, origin, isLocal, isCached, /* isVirtual= */ false, name, number,
networkAndLastFourDigits, month, year, basicCardIssuerNetwork,
issuerIconDrawableId, billingAddressId, serverId,
/* instrumentId= */ 0, /* cardLabel= */ networkAndLastFourDigits,
/* nickname= */ "",
/* cardArtUrl= */ null,
/* virtualCardEnrollmentState= */ VirtualCardEnrollmentState.UNSPECIFIED,
/* productDescription= */ "", /* cardNameForAutofillDisplay= */ "",
/* obfuscatedLastFourDigits= */ "");
}
public CreditCard(String guid, String origin, boolean isLocal, boolean isCached,
boolean isVirtual, String name, String number, String networkAndLastFourDigits,
String month, String year, String basicCardIssuerNetwork, int issuerIconDrawableId,
String billingAddressId, String serverId, long instrumentId, String cardLabel,
String nickname, GURL cardArtUrl,
@VirtualCardEnrollmentState int virtualCardEnrollmentState,
String productDescription, String cardNameForAutofillDisplay,
String obfuscatedLastFourDigits) {
mGUID = guid;
mOrigin = origin;
mIsLocal = isLocal;
mIsCached = isCached;
mIsVirtual = isVirtual;
mName = name;
mNumber = number;
mNetworkAndLastFourDigits = networkAndLastFourDigits;
mMonth = month;
mYear = year;
mBasicCardIssuerNetwork = basicCardIssuerNetwork;
mIssuerIconDrawableId = issuerIconDrawableId;
mBillingAddressId = billingAddressId;
mServerId = serverId;
mInstrumentId = instrumentId;
mCardLabel = cardLabel;
mNickname = nickname;
mCardArtUrl = cardArtUrl;
mVirtualCardEnrollmentState = virtualCardEnrollmentState;
mProductDescription = productDescription;
mCardNameForAutofillDisplay = cardNameForAutofillDisplay;
mObfuscatedLastFourDigits = obfuscatedLastFourDigits;
}
public CreditCard() {
this("" /* guid */, AutofillEditorBase.SETTINGS_ORIGIN /*origin */, true /* isLocal */,
false /* isCached */, "" /* name */, "" /* number */,
"" /* networkAndLastFourDigits */, "" /* month */, "" /* year */,
"" /* basicCardIssuerNetwork */, 0 /* issuerIconDrawableId */,
"" /* billingAddressId */, "" /* serverId */);
}
@CalledByNative("CreditCard")
public String getGUID() {
return mGUID;
}
@CalledByNative("CreditCard")
public String getOrigin() {
return mOrigin;
}
@CalledByNative("CreditCard")
public String getName() {
return mName;
}
@CalledByNative("CreditCard")
public String getNumber() {
return mNumber;
}
public String getNetworkAndLastFourDigits() {
return mNetworkAndLastFourDigits;
}
@CalledByNative("CreditCard")
public String getMonth() {
return mMonth;
}
@CalledByNative("CreditCard")
public String getYear() {
return mYear;
}
public String getFormattedExpirationDate(Context context) {
String twoDigityear = getYear().substring(2);
return getMonth()
+ context.getResources().getString(R.string.autofill_expiration_date_separator)
+ twoDigityear;
}
@CalledByNative("CreditCard")
public boolean getIsLocal() {
return mIsLocal;
}
@CalledByNative("CreditCard")
public boolean getIsCached() {
return mIsCached;
}
@CalledByNative("CreditCard")
public boolean getIsVirtual() {
return mIsVirtual;
}
@CalledByNative("CreditCard")
public String getBasicCardIssuerNetwork() {
return mBasicCardIssuerNetwork;
}
public int getIssuerIconDrawableId() {
return mIssuerIconDrawableId;
}
@CalledByNative("CreditCard")
public String getBillingAddressId() {
return mBillingAddressId;
}
@CalledByNative("CreditCard")
public String getServerId() {
return mServerId;
}
@CalledByNative("CreditCard")
public long getInstrumentId() {
return mInstrumentId;
}
public String getCardLabel() {
return mCardLabel;
}
@CalledByNative("CreditCard")
public String getNickname() {
return mNickname;
}
@CalledByNative("CreditCard")
public GURL getCardArtUrl() {
return mCardArtUrl;
}
@CalledByNative("CreditCard")
public @VirtualCardEnrollmentState int getVirtualCardEnrollmentState() {
return mVirtualCardEnrollmentState;
}
@CalledByNative("CreditCard")
public String getProductDescription() {
return mProductDescription;
}
public String getCardNameForAutofillDisplay() {
return mCardNameForAutofillDisplay;
}
public String getObfuscatedLastFourDigits() {
return mObfuscatedLastFourDigits;
}
public void setGUID(String guid) {
mGUID = guid;
}
public void setOrigin(String origin) {
mOrigin = origin;
}
public void setName(String name) {
mName = name;
}
public void setNumber(String number) {
mNumber = number;
}
public void setNetworkAndLastFourDigits(String networkAndLastFourDigits) {
mNetworkAndLastFourDigits = networkAndLastFourDigits;
}
public void setMonth(String month) {
mMonth = month;
}
public void setYear(String year) {
mYear = year;
}
public void setBasicCardIssuerNetwork(String network) {
mBasicCardIssuerNetwork = network;
}
public void setIssuerIconDrawableId(int id) {
mIssuerIconDrawableId = id;
}
public void setBillingAddressId(String id) {
mBillingAddressId = id;
}
public void setCardLabel(String cardLabel) {
mCardLabel = cardLabel;
}
public void setNickname(String nickname) {
mNickname = nickname;
}
public void setCardArtUrl(GURL cardArtUrl) {
mCardArtUrl = cardArtUrl;
}
public boolean hasValidCreditCardExpirationDate() {
if (mMonth.isEmpty() || mYear.isEmpty()) return false;
Calendar expiryDate = Calendar.getInstance();
// The mMonth value is 1 based but the month in calendar is 0 based.
expiryDate.set(Calendar.MONTH, Integer.parseInt(mMonth) - 1);
expiryDate.set(Calendar.YEAR, Integer.parseInt(mYear));
// Add 1 minute to the expiry instance to ensure that the card is still valid on its
// exact expiration date.
expiryDate.add(Calendar.MINUTE, 1);
return Calendar.getInstance().before(expiryDate);
}
}
private static PersonalDataManager sManager;
// Suppress FindBugs warning, since |sManager| is only used on the UI thread.
public static PersonalDataManager getInstance() {
ThreadUtils.assertOnUiThread();
if (sManager == null) {
sManager = new PersonalDataManager();
}
return sManager;
}
private static int sRequestTimeoutSeconds = 5;
private final long mPersonalDataManagerAndroid;
private final List<PersonalDataManagerObserver> mDataObservers =
new ArrayList<PersonalDataManagerObserver>();
private final Map<String, Bitmap> mCreditCardArtImages = new HashMap<>();
private ImageFetcher mImageFetcher = ImageFetcherFactory.createImageFetcher(
ImageFetcherConfig.DISK_CACHE_ONLY, ProfileKey.getLastUsedRegularProfileKey());
private PersonalDataManager() {
// Note that this technically leaks the native object, however, PersonalDataManager
// is a singleton that lives forever and there's no clean shutdown of Chrome on Android
mPersonalDataManagerAndroid = PersonalDataManagerJni.get().init(PersonalDataManager.this);
}
/**
* Called from native when template URL service is done loading.
*/
@CalledByNative
private void personalDataChanged() {
ThreadUtils.assertOnUiThread();
for (PersonalDataManagerObserver observer : mDataObservers) {
observer.onPersonalDataChanged();
}
fetchCreditCardArtImages();
}
/**
* Registers a PersonalDataManagerObserver on the native side.
*/
public boolean registerDataObserver(PersonalDataManagerObserver observer) {
ThreadUtils.assertOnUiThread();
assert !mDataObservers.contains(observer);
mDataObservers.add(observer);
return PersonalDataManagerJni.get().isDataLoaded(
mPersonalDataManagerAndroid, PersonalDataManager.this);
}
/**
* Unregisters the provided observer.
*/
public void unregisterDataObserver(PersonalDataManagerObserver observer) {
ThreadUtils.assertOnUiThread();
assert (mDataObservers.size() > 0);
assert (mDataObservers.contains(observer));
mDataObservers.remove(observer);
}
/**
* TODO(crbug.com/616102): Reduce the number of Java to Native calls when getting profiles.
*
* Gets the profiles to show in the settings page. Returns all the profiles without any
* processing.
*
* @return The list of profiles to show in the settings.
*/
public List<AutofillProfile> getProfilesForSettings() {
ThreadUtils.assertOnUiThread();
return getProfilesWithLabels(PersonalDataManagerJni.get().getProfileLabelsForSettings(
mPersonalDataManagerAndroid, PersonalDataManager.this),
PersonalDataManagerJni.get().getProfileGUIDsForSettings(
mPersonalDataManagerAndroid, PersonalDataManager.this));
}
/**
* TODO(crbug.com/616102): Reduce the number of Java to Native calls when getting profiles
*
* Gets the profiles to suggest when filling a form or completing a transaction. The profiles
* will have been processed to be more relevant to the user.
*
* @param includeNameInLabel Whether to include the name in the profile's label.
* @return The list of profiles to suggest to the user.
*/
public ArrayList<AutofillProfile> getProfilesToSuggest(boolean includeNameInLabel) {
ThreadUtils.assertOnUiThread();
return getProfilesWithLabels(
PersonalDataManagerJni.get().getProfileLabelsToSuggest(mPersonalDataManagerAndroid,
PersonalDataManager.this, includeNameInLabel,
true /* includeOrganizationInLabel */, true /* includeCountryInLabel */),
PersonalDataManagerJni.get().getProfileGUIDsToSuggest(
mPersonalDataManagerAndroid, PersonalDataManager.this));
}
/**
* TODO(crbug.com/616102): Reduce the number of Java to Native calls when getting profiles.
*
* Gets the profiles to suggest when associating a billing address to a credit card. The
* profiles will have been processed to be more relevant to the user.
*
* @param includeOrganizationInLabel Whether the organization name should be included in the
* label.
*
* @return The list of billing addresses to suggest to the user.
*/
public ArrayList<AutofillProfile> getBillingAddressesToSuggest(
boolean includeOrganizationInLabel) {
ThreadUtils.assertOnUiThread();
return getProfilesWithLabels(
PersonalDataManagerJni.get().getProfileLabelsToSuggest(mPersonalDataManagerAndroid,
PersonalDataManager.this, true /* includeNameInLabel */,
includeOrganizationInLabel, false /* includeCountryInLabel */),
PersonalDataManagerJni.get().getProfileGUIDsToSuggest(
mPersonalDataManagerAndroid, PersonalDataManager.this));
}
private ArrayList<AutofillProfile> getProfilesWithLabels(
String[] profileLabels, String[] profileGUIDs) {
ArrayList<AutofillProfile> profiles = new ArrayList<AutofillProfile>(profileGUIDs.length);
for (int i = 0; i < profileGUIDs.length; i++) {
AutofillProfile profile = PersonalDataManagerJni.get().getProfileByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, profileGUIDs[i]);
profile.setLabel(profileLabels[i]);
profiles.add(profile);
}
return profiles;
}
public AutofillProfile getProfile(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getProfileByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
public void deleteProfile(String guid) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().removeByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
public String setProfile(AutofillProfile profile) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().setProfile(
mPersonalDataManagerAndroid, PersonalDataManager.this, profile);
}
public String setProfileToLocal(AutofillProfile profile) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().setProfileToLocal(
mPersonalDataManagerAndroid, PersonalDataManager.this, profile);
}
/**
* Gets the credit cards to show in the settings page. Returns all the cards without any
* processing.
*/
public List<CreditCard> getCreditCardsForSettings() {
ThreadUtils.assertOnUiThread();
return getCreditCards(PersonalDataManagerJni.get().getCreditCardGUIDsForSettings(
mPersonalDataManagerAndroid, PersonalDataManager.this));
}
/**
* Gets the credit cards to suggest when filling a form or completing a transaction. The cards
* will have been processed to be more relevant to the user.
*/
public ArrayList<CreditCard> getCreditCardsToSuggest() {
ThreadUtils.assertOnUiThread();
return getCreditCards(PersonalDataManagerJni.get().getCreditCardGUIDsToSuggest(
mPersonalDataManagerAndroid, PersonalDataManager.this));
}
private ArrayList<CreditCard> getCreditCards(String[] creditCardGUIDs) {
ArrayList<CreditCard> cards = new ArrayList<CreditCard>(creditCardGUIDs.length);
for (int i = 0; i < creditCardGUIDs.length; i++) {
cards.add(PersonalDataManagerJni.get().getCreditCardByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, creditCardGUIDs[i]));
}
return cards;
}
public CreditCard getCreditCard(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getCreditCardByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
public CreditCard getCreditCardForNumber(String cardNumber) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getCreditCardForNumber(
mPersonalDataManagerAndroid, PersonalDataManager.this, cardNumber);
}
public String setCreditCard(CreditCard card) {
ThreadUtils.assertOnUiThread();
assert card.getIsLocal();
return PersonalDataManagerJni.get().setCreditCard(
mPersonalDataManagerAndroid, PersonalDataManager.this, card);
}
public void updateServerCardBillingAddress(CreditCard card) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().updateServerCardBillingAddress(
mPersonalDataManagerAndroid, PersonalDataManager.this, card);
}
public String getBasicCardIssuerNetwork(String cardNumber, boolean emptyIfInvalid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getBasicCardIssuerNetwork(
mPersonalDataManagerAndroid, PersonalDataManager.this, cardNumber, emptyIfInvalid);
}
@VisibleForTesting
public void addServerCreditCardForTest(CreditCard card) {
ThreadUtils.assertOnUiThread();
assert !card.getIsLocal();
PersonalDataManagerJni.get().addServerCreditCardForTest(
mPersonalDataManagerAndroid, PersonalDataManager.this, card);
}
@VisibleForTesting
public void addServerCreditCardForTestWithAdditionalFields(
CreditCard card, String nickname, int cardIssuer) {
ThreadUtils.assertOnUiThread();
assert !card.getIsLocal();
PersonalDataManagerJni.get().addServerCreditCardForTestWithAdditionalFields(
mPersonalDataManagerAndroid, PersonalDataManager.this, card, nickname, cardIssuer);
}
public void deleteCreditCard(String guid) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().removeByGUID(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
public void clearUnmaskedCache(String guid) {
PersonalDataManagerJni.get().clearUnmaskedCache(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
public String getShippingAddressLabelWithCountryForPaymentRequest(AutofillProfile profile) {
return PersonalDataManagerJni.get().getShippingAddressLabelWithCountryForPaymentRequest(
mPersonalDataManagerAndroid, PersonalDataManager.this, profile);
}
public String getShippingAddressLabelWithoutCountryForPaymentRequest(AutofillProfile profile) {
return PersonalDataManagerJni.get().getShippingAddressLabelWithoutCountryForPaymentRequest(
mPersonalDataManagerAndroid, PersonalDataManager.this, profile);
}
public String getBillingAddressLabelForPaymentRequest(AutofillProfile profile) {
return PersonalDataManagerJni.get().getBillingAddressLabelForPaymentRequest(
mPersonalDataManagerAndroid, PersonalDataManager.this, profile);
}
/**
* Records the use of the profile associated with the specified {@code guid}. Effectively
* increments the use count of the profile and sets its use date to the current time. Also logs
* usage metrics.
*
* @param guid The GUID of the profile.
*/
public void recordAndLogProfileUse(String guid) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().recordAndLogProfileUse(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
@VisibleForTesting
protected void setProfileUseStatsForTesting(String guid, int count, long date) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().setProfileUseStatsForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid, count, date);
}
@VisibleForTesting
int getProfileUseCountForTesting(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getProfileUseCountForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
@VisibleForTesting
long getProfileUseDateForTesting(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getProfileUseDateForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
/**
* Records the use of the credit card associated with the specified {@code guid}. Effectively
* increments the use count of the credit card and set its use date to the current time. Also
* logs usage metrics.
*
* @param guid The GUID of the credit card.
*/
public void recordAndLogCreditCardUse(String guid) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().recordAndLogCreditCardUse(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
@VisibleForTesting
protected void setCreditCardUseStatsForTesting(String guid, int count, long date) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().setCreditCardUseStatsForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid, count, date);
}
@VisibleForTesting
int getCreditCardUseCountForTesting(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getCreditCardUseCountForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
@VisibleForTesting
long getCreditCardUseDateForTesting(String guid) {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getCreditCardUseDateForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this, guid);
}
@VisibleForTesting
long getCurrentDateForTesting() {
ThreadUtils.assertOnUiThread();
return PersonalDataManagerJni.get().getCurrentDateForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this);
}
@VisibleForTesting
protected void clearServerDataForTesting() {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().clearServerDataForTesting(
mPersonalDataManagerAndroid, PersonalDataManager.this);
}
@VisibleForTesting
public static void setInstanceForTesting(PersonalDataManager manager) {
sManager = manager;
}
/**
* Determines whether the logged in user (if any) is eligible to store
* Autofill address profiles to their account.
*/
public boolean isEligibleForAddressAccountStorage() {
return PersonalDataManagerJni.get().isEligibleForAddressAccountStorage(
mPersonalDataManagerAndroid, PersonalDataManager.this);
}
/**
* Users based in unsupported countries and profiles with a country value set
* to an unsupported country are not eligible for account storage. This
* function determines if the `country_code` is eligible.
*/
public boolean isCountryEligibleForAccountStorage(String countryCode) {
return PersonalDataManagerJni.get().isCountryEligibleForAccountStorage(
mPersonalDataManagerAndroid, PersonalDataManager.this, countryCode);
}
/**
* Starts loading the address validation rules for the specified {@code regionCode}.
*
* @param regionCode The code of the region for which to load the rules.
*/
public void loadRulesForAddressNormalization(String regionCode) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().loadRulesForAddressNormalization(
mPersonalDataManagerAndroid, PersonalDataManager.this, regionCode);
}
/**
* Starts loading the sub-key request rules for the specified {@code regionCode}.
*
* @param regionCode The code of the region for which to load the rules.
*/
public void loadRulesForSubKeys(String regionCode) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().loadRulesForSubKeys(
mPersonalDataManagerAndroid, PersonalDataManager.this, regionCode);
}
/**
* Starts requesting the subkeys for the specified {@code regionCode}, if the rules
* associated with the {@code regionCode} are done loading. Otherwise sets up the callback to
* start loading the subkeys when the rules are loaded. The received subkeys will be sent
* to the {@code delegate}. If the subkeys are not received in the specified
* {@code sRequestTimeoutSeconds}, the {@code delegate} will be notified.
*
* @param regionCode The code of the region for which to load the subkeys.
* @param delegate The object requesting the subkeys.
*/
public void getRegionSubKeys(String regionCode, GetSubKeysRequestDelegate delegate) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().startRegionSubKeysRequest(mPersonalDataManagerAndroid,
PersonalDataManager.this, regionCode, sRequestTimeoutSeconds, delegate);
}
/** Cancels the pending subkeys request. */
public void cancelPendingGetSubKeys() {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().cancelPendingGetSubKeys(mPersonalDataManagerAndroid);
}
/**
* Normalizes the address of the profile associated with the {@code guid} if the rules
* associated with the profile's region are done loading. Otherwise sets up the callback to
* start normalizing the address when the rules are loaded. The normalized profile will be sent
* to the {@code delegate}. If the profile is not normalized in the specified
* {@code sRequestTimeoutSeconds}, the {@code delegate} will be notified.
*
* @param profile The profile to normalize.
* @param delegate The object requesting the normalization.
*/
public void normalizeAddress(
AutofillProfile profile, NormalizedAddressRequestDelegate delegate) {
ThreadUtils.assertOnUiThread();
PersonalDataManagerJni.get().startAddressNormalization(mPersonalDataManagerAndroid,
PersonalDataManager.this, profile, sRequestTimeoutSeconds, delegate);
}
/**
* Checks whether the Autofill PersonalDataManager has profiles.
*
* @return True If there are profiles.
*/
public boolean hasProfiles() {
return PersonalDataManagerJni.get().hasProfiles(mPersonalDataManagerAndroid);
}
/**
* Checks whether the Autofill PersonalDataManager has credit cards.
*
* @return True If there are credit cards.
*/
public boolean hasCreditCards() {
return PersonalDataManagerJni.get().hasCreditCards(mPersonalDataManagerAndroid);
}
/**
* @return Whether FIDO authentication is available.
*/
public boolean isFidoAuthenticationAvailable() {
return isAutofillCreditCardEnabled()
&& PersonalDataManagerJni.get().isFidoAuthenticationAvailable(
mPersonalDataManagerAndroid);
}
/**
* @return Whether the Autofill feature for Profiles (addresses) is enabled.
*/
public static boolean isAutofillProfileEnabled() {
return getPrefService().getBoolean(Pref.AUTOFILL_PROFILE_ENABLED);
}
/**
* @return Whether the Autofill feature for Credit Cards is enabled.
*/
public static boolean isAutofillCreditCardEnabled() {
return getPrefService().getBoolean(Pref.AUTOFILL_CREDIT_CARD_ENABLED);
}
/**
* Enables or disables the Autofill feature for Profiles.
* @param enable True to disable profile Autofill, false otherwise.
*/
public static void setAutofillProfileEnabled(boolean enable) {
getPrefService().setBoolean(Pref.AUTOFILL_PROFILE_ENABLED, enable);
}
/**
* Enables or disables the Autofill feature for Credit Cards.
* @param enable True to disable credit card Autofill, false otherwise.
*/
public static void setAutofillCreditCardEnabled(boolean enable) {
getPrefService().setBoolean(Pref.AUTOFILL_CREDIT_CARD_ENABLED, enable);
}
/**
* @return Whether the Autofill feature for FIDO authentication is enabled.
*/
public static boolean isAutofillCreditCardFidoAuthEnabled() {
return getPrefService().getBoolean(Pref.AUTOFILL_CREDIT_CARD_FIDO_AUTH_ENABLED);
}
/**
* Enables or disables the Autofill feature for FIDO authentication.
* We are trying to align this pref with the server's source of truth, but any mismatches
* between this pref and the server should imply the user's intention to opt in/out.
* @param enable True to enable credit card FIDO authentication, false otherwise.
*/
public static void setAutofillCreditCardFidoAuthEnabled(boolean enable) {
getPrefService().setBoolean(Pref.AUTOFILL_CREDIT_CARD_FIDO_AUTH_ENABLED, enable);
}
/**
* @return Whether the Autofill feature for payment methods mandatory reauth is enabled.
*/
public static boolean isPaymentMethodsMandatoryReauthEnabled() {
return getPrefService().getBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH);
}
/**
* Enables or disables the Autofill feature for payment methods mandatory reauth.
* @param enable True to enable payment methods mandatory reauth, false otherwise.
*/
public static void setAutofillPaymentMethodsMandatoryReauth(boolean enable) {
getPrefService().setBoolean(Pref.AUTOFILL_PAYMENT_METHODS_MANDATORY_REAUTH, enable);
}
/**
* @return Whether the Autofill feature is managed.
*/
public static boolean isAutofillManaged() {
return PersonalDataManagerJni.get().isAutofillManaged();
}
/**
* @return Whether the Autofill feature for Profiles (addresses) is managed.
*/
public static boolean isAutofillProfileManaged() {
return PersonalDataManagerJni.get().isAutofillProfileManaged();
}
/**
* @return Whether the Autofill feature for Credit Cards is managed.
*/
public static boolean isAutofillCreditCardManaged() {
return PersonalDataManagerJni.get().isAutofillCreditCardManaged();
}
/**
* @return Whether the Payments integration feature is enabled.
*/
public static boolean isPaymentsIntegrationEnabled() {
return PersonalDataManagerJni.get().isPaymentsIntegrationEnabled();
}
/**
* Enables or disables the Payments integration.
* @param enable True to enable Payments data import.
*/
public static void setPaymentsIntegrationEnabled(boolean enable) {
PersonalDataManagerJni.get().setPaymentsIntegrationEnabled(enable);
}
@VisibleForTesting
public static void setRequestTimeoutForTesting(int timeout) {
sRequestTimeoutSeconds = timeout;
}
@VisibleForTesting
public void setSyncServiceForTesting() {
PersonalDataManagerJni.get().setSyncServiceForTesting(mPersonalDataManagerAndroid);
}
/**
* @return The sub-key request timeout in milliseconds.
*/
public static long getRequestTimeoutMS() {
return DateUtils.SECOND_IN_MILLIS * sRequestTimeoutSeconds;
}
private static PrefService getPrefService() {
return UserPrefs.get(Profile.getLastUsedRegularProfile());
}
// TODO (crbug.com/1384128): Add icon dimensions to card art URL.
private void fetchCreditCardArtImages() {
for (CreditCard card : getCreditCardsToSuggest()) {
// Fetch the image using the ImageFetcher only if it is not present in the cache.
if (card.getCardArtUrl() != null && card.getCardArtUrl().isValid()
&& !mCreditCardArtImages.containsKey(card.getCardArtUrl().getSpec())) {
fetchImage(card.getCardArtUrl(),
bitmap -> mCreditCardArtImages.put(card.getCardArtUrl().getSpec(), bitmap));
}
}
}
/**
* Return the card art image for the given `customImageUrl`.
* @param context required to get resources.
* @param customImageUrl URL of the image. If the image is available, it is returned, otherwise
* it is fetched from this URL.
* @param widthId Resource id of the width spec.
* @param heightId Resource id of the height spec.
* @param cornerRadiusId Resource id of the corner radius spec.
* @return Bitmap if found in the local cache, else return null.
*/
public Bitmap getCustomImageForAutofillSuggestionIfAvailable(
Context context, GURL customImageUrl, int widthId, int heightId, int cornerRadiusId) {
Resources res = context.getResources();
int width = res.getDimensionPixelSize(widthId);
int height = res.getDimensionPixelSize(heightId);
float cornerRadius = res.getDimension(cornerRadiusId);
// TODO(crbug.com/1313616): The Capital One icon for virtual cards is available in a single
// size via a static URL. Cache this image at different sizes so it can be used by different
// surfaces.
GURL urlToCache =
AutofillUiUtils.getCreditCardIconUrlWithParams(customImageUrl, width, height);
GURL urlToFetch = customImageUrl.getSpec().equals(AutofillUiUtils.CAPITAL_ONE_ICON_URL)
? customImageUrl
: urlToCache;
if (mCreditCardArtImages.containsKey(urlToCache.getSpec())) {
return mCreditCardArtImages.get(urlToCache.getSpec());
}
// Schedule the fetching of image and return null so that the UI thread does not have to
// wait and can show the default network icon.
fetchImage(urlToFetch, bitmap -> {
// TODO (crbug.com/1410418): Log image fetching failure metrics.
// If the image fetching was unsuccessful, silently return.
if (bitmap == null) return;
// When adding new sizes for card icons, check if the corner radius needs to be added as
// a suffix for caching (crbug.com/1431283).
mCreditCardArtImages.put(urlToCache.getSpec(),
AutofillUiUtils.resizeAndAddRoundedCornersAndGreyBorder(bitmap, width, height,
cornerRadius,
ChromeFeatureList.isEnabled(
ChromeFeatureList
.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES)));
});
return null;
}
@VisibleForTesting
public void setImageFetcherForTesting(ImageFetcher imageFetcher) {
this.mImageFetcher = imageFetcher;
}
private void fetchImage(GURL customImageUrl, Callback<Bitmap> callback) {
if (!customImageUrl.isValid()) {
Log.w(TAG, "Tried to fetch an invalid url %s", customImageUrl.getSpec());
return;
}
ImageFetcher.Params params = ImageFetcher.Params.create(
customImageUrl.getSpec(), ImageFetcher.AUTOFILL_CARD_ART_UMA_CLIENT_NAME);
mImageFetcher.fetchImage(params, bitmap -> callback.onResult(bitmap));
}
@NativeMethods
interface Natives {
long init(PersonalDataManager caller);
boolean isDataLoaded(long nativePersonalDataManagerAndroid, PersonalDataManager caller);
String[] getProfileGUIDsForSettings(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
String[] getProfileGUIDsToSuggest(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
String[] getProfileLabelsForSettings(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
String[] getProfileLabelsToSuggest(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, boolean includeNameInLabel,
boolean includeOrganizationInLabel, boolean includeCountryInLabel);
AutofillProfile getProfileByGUID(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
boolean isEligibleForAddressAccountStorage(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
boolean isCountryEligibleForAccountStorage(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String countryCode);
String setProfile(long nativePersonalDataManagerAndroid, PersonalDataManager caller,
AutofillProfile profile);
String setProfileToLocal(long nativePersonalDataManagerAndroid, PersonalDataManager caller,
AutofillProfile profile);
String getShippingAddressLabelWithCountryForPaymentRequest(
long nativePersonalDataManagerAndroid, PersonalDataManager caller,
AutofillProfile profile);
String getShippingAddressLabelWithoutCountryForPaymentRequest(
long nativePersonalDataManagerAndroid, PersonalDataManager caller,
AutofillProfile profile);
String getBillingAddressLabelForPaymentRequest(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, AutofillProfile profile);
String[] getCreditCardGUIDsForSettings(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
String[] getCreditCardGUIDsToSuggest(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
CreditCard getCreditCardByGUID(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
CreditCard getCreditCardForNumber(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String cardNumber);
String setCreditCard(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, CreditCard card);
void updateServerCardBillingAddress(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, CreditCard card);
String getBasicCardIssuerNetwork(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String cardNumber, boolean emptyIfInvalid);
void addServerCreditCardForTest(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, CreditCard card);
void addServerCreditCardForTestWithAdditionalFields(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, CreditCard card, String nickname, int cardIssuer);
void removeByGUID(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
void recordAndLogProfileUse(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
void setProfileUseStatsForTesting(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String guid, int count, long date);
int getProfileUseCountForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
long getProfileUseDateForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
void recordAndLogCreditCardUse(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
void setCreditCardUseStatsForTesting(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String guid, int count, long date);
int getCreditCardUseCountForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
long getCreditCardUseDateForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
long getCurrentDateForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
void clearServerDataForTesting(
long nativePersonalDataManagerAndroid, PersonalDataManager caller);
void clearUnmaskedCache(
long nativePersonalDataManagerAndroid, PersonalDataManager caller, String guid);
void loadRulesForAddressNormalization(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String regionCode);
void loadRulesForSubKeys(long nativePersonalDataManagerAndroid, PersonalDataManager caller,
String regionCode);
void startAddressNormalization(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, AutofillProfile profile, int timeoutSeconds,
NormalizedAddressRequestDelegate delegate);
void startRegionSubKeysRequest(long nativePersonalDataManagerAndroid,
PersonalDataManager caller, String regionCode, int timeoutSeconds,
GetSubKeysRequestDelegate delegate);
boolean hasProfiles(long nativePersonalDataManagerAndroid);
boolean hasCreditCards(long nativePersonalDataManagerAndroid);
boolean isFidoAuthenticationAvailable(long nativePersonalDataManagerAndroid);
boolean isAutofillManaged();
boolean isAutofillProfileManaged();
boolean isAutofillCreditCardManaged();
boolean isPaymentsIntegrationEnabled();
void setPaymentsIntegrationEnabled(boolean enable);
String toCountryCode(String countryName);
void cancelPendingGetSubKeys(long nativePersonalDataManagerAndroid);
void setSyncServiceForTesting(long nativePersonalDataManagerAndroid);
}
}