0

Add @NullMarked to //components/payments

Patch 1 contains the automated changes made by the annotator.
Patch 2 and 4 and 5 contains the manual changes made by me.

Bug: 389129271
Change-Id: I172b42479e35ae6ee4c38a80c6bf6243492fcc38
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6299969
Reviewed-by: Peter Wen <wnwen@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Commit-Queue: Peter Wen <wnwen@chromium.org>
Commit-Queue: Martin Kong <martinkong@google.com>
Owners-Override: Andrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1424750}
This commit is contained in:
Martin Kong
2025-02-25 13:13:55 -08:00
committed by Chromium LUCI CQ
parent de7e4cb4fa
commit ea5943b112
47 changed files with 318 additions and 198 deletions
components/payments/content/android
url/android/java/src/org/chromium/url

@ -9,13 +9,14 @@ import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits; import org.chromium.base.task.TaskTraits;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.payments.intent.IsReadyToPayServiceHelper; import org.chromium.components.payments.intent.IsReadyToPayServiceHelper;
import org.chromium.components.payments.intent.WebPaymentIntentHelper; import org.chromium.components.payments.intent.WebPaymentIntentHelper;
import org.chromium.components.payments.intent.WebPaymentIntentHelperType; import org.chromium.components.payments.intent.WebPaymentIntentHelperType;
@ -40,31 +41,32 @@ import java.util.Set;
* The point of interaction with a locally installed 3rd party native Android payment app. * The point of interaction with a locally installed 3rd party native Android payment app.
* https://web.dev/articles/android-payment-apps-developers-guide * https://web.dev/articles/android-payment-apps-developers-guide
*/ */
@NullMarked
public class AndroidPaymentApp extends PaymentApp public class AndroidPaymentApp extends PaymentApp
implements IsReadyToPayServiceHelper.ResultHandler, WindowAndroid.IntentCallback { implements IsReadyToPayServiceHelper.ResultHandler, WindowAndroid.IntentCallback {
private final Handler mHandler; private final Handler mHandler;
private final AndroidIntentLauncher mLauncher; private final AndroidIntentLauncher mLauncher;
@Nullable private final DialogController mDialogController; private final @Nullable DialogController mDialogController;
private final Set<String> mMethodNames; private final Set<String> mMethodNames;
private final boolean mIsIncognito; private final boolean mIsIncognito;
private final String mPackageName; private final String mPackageName;
private final String mPayActivityName; private final String mPayActivityName;
@Nullable private final String mIsReadyToPayServiceName; private final @Nullable String mIsReadyToPayServiceName;
@Nullable private final String mPaymentDetailsUpdateServiceName; private final @Nullable String mPaymentDetailsUpdateServiceName;
private final SupportedDelegations mSupportedDelegations; private final SupportedDelegations mSupportedDelegations;
private final boolean mShowReadyToPayDebugInfo; private final boolean mShowReadyToPayDebugInfo;
private final boolean mRemoveDeprecatedFields; private final boolean mRemoveDeprecatedFields;
private IsReadyToPayCallback mIsReadyToPayCallback; private @Nullable IsReadyToPayCallback mIsReadyToPayCallback;
private InstrumentDetailsCallback mInstrumentDetailsCallback; private @Nullable InstrumentDetailsCallback mInstrumentDetailsCallback;
private IsReadyToPayServiceHelper mIsReadyToPayServiceHelper; private @Nullable IsReadyToPayServiceHelper mIsReadyToPayServiceHelper;
private PaymentDetailsUpdateConnection mPaymentDetailsUpdateConnection; private @Nullable PaymentDetailsUpdateConnection mPaymentDetailsUpdateConnection;
@Nullable private String mApplicationIdentifierToHide; private @Nullable String mApplicationIdentifierToHide;
private boolean mBypassIsReadyToPayServiceInTest; private boolean mBypassIsReadyToPayServiceInTest;
private boolean mIsPreferred; private boolean mIsPreferred;
// Set inside launchPaymentApp and used to validate the received response. // Set inside launchPaymentApp and used to validate the received response.
@Nullable private WebPaymentIntentHelperType.PaymentOptions mPaymentOptions; private WebPaymentIntentHelperType.@Nullable PaymentOptions mPaymentOptions;
/** /**
* Builds the point of interaction with a locally installed 3rd party native Android payment * Builds the point of interaction with a locally installed 3rd party native Android payment
@ -179,7 +181,7 @@ public class AndroidPaymentApp extends PaymentApp
Map<String, PaymentMethodData> methodDataMap, Map<String, PaymentMethodData> methodDataMap,
String origin, String origin,
String iframeOrigin, String iframeOrigin,
@Nullable byte[][] certificateChain, byte @Nullable [][] certificateChain,
Map<String, PaymentDetailsModifier> modifiers, Map<String, PaymentDetailsModifier> modifiers,
IsReadyToPayCallback callback) { IsReadyToPayCallback callback) {
ThreadUtils.assertOnUiThread(); ThreadUtils.assertOnUiThread();
@ -243,8 +245,7 @@ public class AndroidPaymentApp extends PaymentApp
} }
@Override @Override
@Nullable public @Nullable String getApplicationIdentifierToHide() {
public String getApplicationIdentifierToHide() {
return mApplicationIdentifierToHide; return mApplicationIdentifierToHide;
} }
@ -259,7 +260,7 @@ public class AndroidPaymentApp extends PaymentApp
final String merchantName, final String merchantName,
String origin, String origin,
String iframeOrigin, String iframeOrigin,
final byte[][] certificateChain, final byte @Nullable [][] certificateChain,
final Map<String, PaymentMethodData> methodDataMap, final Map<String, PaymentMethodData> methodDataMap,
final PaymentItem total, final PaymentItem total,
final List<PaymentItem> displayItems, final List<PaymentItem> displayItems,
@ -348,7 +349,7 @@ public class AndroidPaymentApp extends PaymentApp
String merchantName, String merchantName,
String origin, String origin,
String iframeOrigin, String iframeOrigin,
byte[][] certificateChain, byte @Nullable [][] certificateChain,
Map<String, PaymentMethodData> methodDataMap, Map<String, PaymentMethodData> methodDataMap,
PaymentItem total, PaymentItem total,
List<PaymentItem> displayItems, List<PaymentItem> displayItems,

@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import org.chromium.build.annotations.NullMarked;
import org.chromium.components.payments.intent.WebPaymentIntentHelper; import org.chromium.components.payments.intent.WebPaymentIntentHelper;
import java.util.HashMap; import java.util.HashMap;
@ -17,6 +18,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** Looks up installed third party Android payment apps. */ /** Looks up installed third party Android payment apps. */
@NullMarked
public class AndroidPaymentAppFactory implements PaymentAppFactoryInterface { public class AndroidPaymentAppFactory implements PaymentAppFactoryInterface {
// PaymentAppFactoryInterface implementation. // PaymentAppFactoryInterface implementation.
@Override @Override

@ -4,17 +4,21 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import static org.chromium.build.NullUtil.assumeNonNull;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.build.annotations.Contract;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.payments.PaymentManifestVerifier.ManifestVerifyCallback; import org.chromium.components.payments.PaymentManifestVerifier.ManifestVerifyCallback;
import org.chromium.components.payments.intent.WebPaymentIntentHelper; import org.chromium.components.payments.intent.WebPaymentIntentHelper;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
@ -35,6 +39,7 @@ import java.util.Set;
* payment method names are exceptions: these are common payment method names that do not have a * payment method names are exceptions: these are common payment method names that do not have a
* manifest and can be used by any payment app. * manifest and can be used by any payment app.
*/ */
@NullMarked
public class AndroidPaymentAppFinder implements ManifestVerifyCallback { public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
private static final String TAG = "PaymentAppFinder"; private static final String TAG = "PaymentAppFinder";
@ -67,10 +72,10 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
public static final String META_DATA_NAME_OF_SUPPORTED_DELEGATIONS = public static final String META_DATA_NAME_OF_SUPPORTED_DELEGATIONS =
"org.chromium.payment_supported_delegations"; "org.chromium.payment_supported_delegations";
private static PackageManagerDelegate sPackageManagerDelegateForTest; private static @Nullable PackageManagerDelegate sPackageManagerDelegateForTest;
private static PaymentManifestDownloader sDownloaderForTest; private static @Nullable PaymentManifestDownloader sDownloaderForTest;
private static boolean sBypassIsReadyToPayServiceInTest; private static boolean sBypassIsReadyToPayServiceInTest;
private static AndroidIntentLauncher sAndroidIntentLauncherForTest; private static @Nullable AndroidIntentLauncher sAndroidIntentLauncherForTest;
private final Set<GURL> mUrlPaymentMethods = new HashSet<>(); private final Set<GURL> mUrlPaymentMethods = new HashSet<>();
private final PaymentManifestDownloader mDownloader; private final PaymentManifestDownloader mDownloader;
@ -285,7 +290,8 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
|| urlMethod.equals(defaultUrlMethod); || urlMethod.equals(defaultUrlMethod);
} }
private ResolveInfo findAppWithPackageName(List<ResolveInfo> apps, String packageName) { private @Nullable ResolveInfo findAppWithPackageName(
List<ResolveInfo> apps, String packageName) {
assert packageName != null; assert packageName != null;
for (int i = 0; i < apps.size(); i++) { for (int i = 0; i < apps.size(); i++) {
ResolveInfo app = apps.get(i); ResolveInfo app = apps.get(i);
@ -555,8 +561,8 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
* @param metaDataName The name of the string array meta data to be retrieved. * @param metaDataName The name of the string array meta data to be retrieved.
* @return The string array. * @return The string array.
*/ */
@Nullable private String @Nullable [] getStringArrayMetaData(
private String[] getStringArrayMetaData(ActivityInfo activityInfo, String metaDataName) { ActivityInfo activityInfo, String metaDataName) {
if (activityInfo.metaData == null) return null; if (activityInfo.metaData == null) return null;
int resId = activityInfo.metaData.getInt(metaDataName); int resId = activityInfo.metaData.getInt(metaDataName);
@ -694,7 +700,8 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
* @param resolveInfo The payment app that's allowed to use the method name. * @param resolveInfo The payment app that's allowed to use the method name.
* @param methodName The method name that can be used by the app. * @param methodName The method name that can be used by the app.
*/ */
private void onValidPaymentAppForPaymentMethodName(ResolveInfo resolveInfo, String methodName) { private void onValidPaymentAppForPaymentMethodName(
ResolveInfo resolveInfo, String methodName) {
if (mFactoryDelegate.getParams().hasClosed()) return; if (mFactoryDelegate.getParams().hasClosed()) return;
String packageName = resolveInfo.activityInfo.packageName; String packageName = resolveInfo.activityInfo.packageName;
@ -729,7 +736,7 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
app = app =
new AndroidPaymentApp( new AndroidPaymentApp(
sAndroidIntentLauncherForTest == null sAndroidIntentLauncherForTest == null
? mFactoryDelegate.getAndroidIntentLauncher() ? assumeNonNull(mFactoryDelegate.getAndroidIntentLauncher())
: sAndroidIntentLauncherForTest, : sAndroidIntentLauncherForTest,
mFactoryDelegate.getDialogController(), mFactoryDelegate.getDialogController(),
packageName, packageName,
@ -779,14 +786,14 @@ public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
* @param url The URL to stringify. * @param url The URL to stringify.
* @return The URL string without a trailing slash, or null if the input parameter is null. * @return The URL string without a trailing slash, or null if the input parameter is null.
*/ */
@Nullable @Contract("!null -> !null")
private static String urlToStringWithoutTrailingSlash(@Nullable GURL url) { private static @Nullable String urlToStringWithoutTrailingSlash(@Nullable GURL url) {
if (url == null) return null; if (url == null) return null;
return removeTrailingSlash(url.getSpec()); return removeTrailingSlash(url.getSpec());
} }
@Nullable @Contract("!null -> !null")
private static String removeTrailingSlash(@Nullable String string) { private static @Nullable String removeTrailingSlash(@Nullable String string) {
if (string == null) return null; if (string == null) return null;
return string.endsWith("/") ? string.substring(0, string.length() - 1) : string; return string.endsWith("/") ? string.substring(0, string.length() - 1) : string;
} }

@ -4,8 +4,8 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import androidx.annotation.Nullable; import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentComplete; import org.chromium.payments.mojom.PaymentComplete;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
@ -24,6 +24,7 @@ import java.util.Map;
* The browser part of the PaymentRequest implementation. The browser here can be either the * The browser part of the PaymentRequest implementation. The browser here can be either the
* Android Chrome browser or the WebLayer "browser". * Android Chrome browser or the WebLayer "browser".
*/ */
@NullMarked
public interface BrowserPaymentRequest { public interface BrowserPaymentRequest {
/** /**
* The client of the interface calls this when it has received the payment details update * The client of the interface calls this when it has received the payment details update
@ -98,10 +99,9 @@ public interface BrowserPaymentRequest {
* implementer may consider other factors before deciding whether to show or skip. * implementer may consider other factors before deciding whether to show or skip.
* @return The error of the showing if any; null if success. * @return The error of the showing if any; null if success.
*/ */
@Nullable @Nullable String showOrSkipAppSelector(
String showOrSkipAppSelector(
boolean isShowWaitingForUpdatedDetails, boolean isShowWaitingForUpdatedDetails,
PaymentItem total, @Nullable PaymentItem total,
boolean shouldSkipAppSelector); boolean shouldSkipAppSelector);
/** /**
@ -128,8 +128,7 @@ public interface BrowserPaymentRequest {
* *
* @return The error if it fails; null otherwise. * @return The error if it fails; null otherwise.
*/ */
@Nullable default @Nullable String onShowCalledAndAppsQueriedAndDetailsFinalized() {
default String onShowCalledAndAppsQueriedAndDetailsFinalized() {
return null; return null;
} }
@ -166,7 +165,7 @@ public interface BrowserPaymentRequest {
* @param ukmSourceId The ukm source id assigned to the payment app. * @param ukmSourceId The ukm source id assigned to the payment app.
* @return The created WebContents. * @return The created WebContents.
*/ */
default WebContents openPaymentHandlerWindow(GURL url, long ukmSourceId) { default @Nullable WebContents openPaymentHandlerWindow(GURL url, long ukmSourceId) {
return null; return null;
} }
@ -178,8 +177,7 @@ public interface BrowserPaymentRequest {
* their payment apps. * their payment apps.
* @return The error if it fails; null otherwise. * @return The error if it fails; null otherwise.
*/ */
@Nullable default @Nullable String continueShowWithUpdatedDetails(
default String continueShowWithUpdatedDetails(
PaymentDetails details, boolean isFinishedQueryingPaymentApps) { PaymentDetails details, boolean isFinishedQueryingPaymentApps) {
return null; return null;
} }
@ -225,8 +223,7 @@ public interface BrowserPaymentRequest {
* Can return null when ANDROID_PAYMENT_INTENTS_OMIT_DEPRECATED_PARAMETERS is enabled or * Can return null when ANDROID_PAYMENT_INTENTS_OMIT_DEPRECATED_PARAMETERS is enabled or
* when the page is localhost or is a file. * when the page is localhost or is a file.
*/ */
@Nullable byte @Nullable [][] getCertificateChain();
byte[][] getCertificateChain();
/** /**
* @return The launcher for Android intent-based payment app. * @return The launcher for Android intent-based payment app.

@ -4,12 +4,11 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import androidx.annotation.NonNull;
import org.jni_zero.CalledByNative; import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.url.GURL; import org.chromium.url.GURL;
/** /**
@ -24,6 +23,7 @@ import org.chromium.url.GURL;
* bridge.destroy(); * bridge.destroy();
*/ */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class CSPCheckerBridge { public class CSPCheckerBridge {
// Performs the CSP checks. // Performs the CSP checks.
private final CSPChecker mImpl; private final CSPChecker mImpl;
@ -35,7 +35,7 @@ public class CSPCheckerBridge {
* Initializes the CSP checker bridge. * Initializes the CSP checker bridge.
* @param cspChecker The object that will perform the CSP checks. * @param cspChecker The object that will perform the CSP checks.
*/ */
public CSPCheckerBridge(@NonNull CSPChecker cspChecker) { public CSPCheckerBridge(CSPChecker cspChecker) {
mImpl = cspChecker; mImpl = cspChecker;
mNativeBridge = CSPCheckerBridgeJni.get().createNativeCSPChecker(this); mNativeBridge = CSPCheckerBridgeJni.get().createNativeCSPChecker(this);
} }

@ -9,10 +9,13 @@ import androidx.annotation.VisibleForTesting;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import java.util.Set; import java.util.Set;
/** Error messages for web payment. */ /** Error messages for web payment. */
@JNINamespace("payments::android") @JNINamespace("payments::android")
@NullMarked
public class ErrorMessageUtil { public class ErrorMessageUtil {
/** /**
* Returns the "payment method not supported" message. * Returns the "payment method not supported" message.

@ -9,6 +9,7 @@ import org.jni_zero.JNINamespace;
import org.jni_zero.JniType; import org.jni_zero.JniType;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentMethodData;
@ -17,6 +18,7 @@ import java.util.Set;
/** Checks whether hasEnrolledInstrument() can be queried. */ /** Checks whether hasEnrolledInstrument() can be queried. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class HasEnrolledInstrumentQuery { public class HasEnrolledInstrumentQuery {
/** /**
* Checks whether the given hasEnrolledInstrument() query is allowed. * Checks whether the given hasEnrolledInstrument() query is allowed.

@ -4,6 +4,8 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.mojo.system.MojoException; import org.chromium.mojo.system.MojoException;
import org.chromium.payments.mojom.CanMakePaymentQueryResult; import org.chromium.payments.mojom.CanMakePaymentQueryResult;
import org.chromium.payments.mojom.HasEnrolledInstrumentQueryResult; import org.chromium.payments.mojom.HasEnrolledInstrumentQueryResult;
@ -19,8 +21,9 @@ import org.chromium.payments.mojom.PaymentValidationErrors;
* An implementation of PaymentRequest that immediately rejects all connections. * An implementation of PaymentRequest that immediately rejects all connections.
* Necessary because Mojo does not handle null returned from createImpl(). * Necessary because Mojo does not handle null returned from createImpl().
*/ */
@NullMarked
public final class InvalidPaymentRequest implements PaymentRequest { public final class InvalidPaymentRequest implements PaymentRequest {
private PaymentRequestClient mClient; private @Nullable PaymentRequestClient mClient;
@Override @Override
public void init( public void init(

@ -8,12 +8,12 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.os.Handler; import android.os.Handler;
import androidx.annotation.Nullable;
import org.jni_zero.CalledByNative; import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
import org.chromium.payments.mojom.PaymentItem; import org.chromium.payments.mojom.PaymentItem;
import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentMethodData;
@ -31,6 +31,7 @@ import java.util.Set;
/** Wrapper around a C++ payment app. */ /** Wrapper around a C++ payment app. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class JniPaymentApp extends PaymentApp { public class JniPaymentApp extends PaymentApp {
private final Handler mHandler = new Handler(); private final Handler mHandler = new Handler();
private final @PaymentAppType int mPaymentAppType; private final @PaymentAppType int mPaymentAppType;
@ -38,8 +39,8 @@ public class JniPaymentApp extends PaymentApp {
// The Java object owns the C++ payment app and frees it in dismissInstrument(). // The Java object owns the C++ payment app and frees it in dismissInstrument().
private long mNativeObject; private long mNativeObject;
private AbortCallback mAbortCallback; private @Nullable AbortCallback mAbortCallback;
private InstrumentDetailsCallback mInvokeCallback; private @Nullable InstrumentDetailsCallback mInvokeCallback;
@CalledByNative @CalledByNative
private JniPaymentApp( private JniPaymentApp(
@ -170,7 +171,7 @@ public class JniPaymentApp extends PaymentApp {
String merchantName, String merchantName,
String origin, String origin,
String iframeOrigin, String iframeOrigin,
@Nullable byte[][] certificateChain, byte @Nullable [][] certificateChain,
Map<String, PaymentMethodData> methodDataMap, Map<String, PaymentMethodData> methodDataMap,
PaymentItem total, PaymentItem total,
List<PaymentItem> displayItems, List<PaymentItem> displayItems,
@ -204,14 +205,12 @@ public class JniPaymentApp extends PaymentApp {
} }
@Override @Override
@Nullable public @Nullable String getApplicationIdentifierToHide() {
public String getApplicationIdentifierToHide() {
return JniPaymentAppJni.get().getApplicationIdentifierToHide(mNativeObject); return JniPaymentAppJni.get().getApplicationIdentifierToHide(mNativeObject);
} }
@Override @Override
@Nullable public @Nullable Set<String> getApplicationIdentifiersThatHideThisApp() {
public Set<String> getApplicationIdentifiersThatHideThisApp() {
return new HashSet<>( return new HashSet<>(
Arrays.asList( Arrays.asList(
JniPaymentAppJni.get() JniPaymentAppJni.get()
@ -261,7 +260,7 @@ public class JniPaymentApp extends PaymentApp {
String[] getInstrumentMethodNames(long nativeJniPaymentApp); String[] getInstrumentMethodNames(long nativeJniPaymentApp);
boolean isValidForPaymentMethodData( boolean isValidForPaymentMethodData(
long nativeJniPaymentApp, String method, ByteBuffer dataByteBuffer); long nativeJniPaymentApp, String method, @Nullable ByteBuffer dataByteBuffer);
boolean handlesShippingAddress(long nativeJniPaymentApp); boolean handlesShippingAddress(long nativeJniPaymentApp);

@ -7,12 +7,14 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import java.util.List; import java.util.List;
/** A class used to record journey metrics for the Payment Request feature. */ /** A class used to record journey metrics for the Payment Request feature. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class JourneyLogger { public class JourneyLogger {
/** Pointer to the native implementation. */ /** Pointer to the native implementation. */
private long mJourneyLoggerAndroid; private long mJourneyLoggerAndroid;

@ -4,6 +4,8 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.mojo.system.MojoException; import org.chromium.mojo.system.MojoException;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentMethodData;
@ -16,9 +18,10 @@ import org.chromium.payments.mojom.PaymentValidationErrors;
* Guards against invalid mojo parameters and enforces correct call sequence from mojo IPC in the * Guards against invalid mojo parameters and enforces correct call sequence from mojo IPC in the
* untrusted renderer, so PaymentRequestService does not have to. * untrusted renderer, so PaymentRequestService does not have to.
*/ */
@NullMarked
public class MojoPaymentRequestGateKeeper implements PaymentRequest { public class MojoPaymentRequestGateKeeper implements PaymentRequest {
private final Delegate mDelegate; private final Delegate mDelegate;
private PaymentRequestService mPaymentRequestService; private @Nullable PaymentRequestService mPaymentRequestService;
/** The delegate of the class. */ /** The delegate of the class. */
public interface Delegate { public interface Delegate {

@ -7,10 +7,12 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.url.GURL; import org.chromium.url.GURL;
/** Helper for origin security. */ /** Helper for origin security. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class OriginSecurityChecker { public class OriginSecurityChecker {
/** /**
* Returns true for a valid URL from a secure origin, e.g., http://localhost, * Returns true for a valid URL from a secure origin, e.g., http://localhost,

@ -21,7 +21,9 @@ public final class PaymentAddressTypeConverter {
* @param address The org.chromium.payments.mojom.PaymentAddress to be converted. * @param address The org.chromium.payments.mojom.PaymentAddress to be converted.
* @return The converted address with type org.chromium.components.payments.Address. * @return The converted address with type org.chromium.components.payments.Address.
*/ */
public static @Nullable Address convertPaymentAddressFromMojo(PaymentAddress address) { @Contract("!null -> !null")
public static @Nullable Address convertPaymentAddressFromMojo(
@Nullable PaymentAddress address) {
if (address == null) return null; if (address == null) return null;
return new Address( return new Address(
address.country, address.country,
@ -41,7 +43,8 @@ public final class PaymentAddressTypeConverter {
* @return The converted address with type org.chromium.payments.mojom.PaymentAddress. * @return The converted address with type org.chromium.payments.mojom.PaymentAddress.
*/ */
@Contract("!null -> !null") @Contract("!null -> !null")
public static @Nullable PaymentAddress convertAddressToMojoPaymentAddress(Address address) { public static @Nullable PaymentAddress convertAddressToMojoPaymentAddress(
@Nullable Address address) {
if (address == null) return null; if (address == null) return null;
PaymentAddress result = new PaymentAddress(); PaymentAddress result = new PaymentAddress();
result.country = address.country; result.country = address.country;

@ -59,7 +59,7 @@ public abstract class PaymentApp extends EditableOption {
void onInstrumentAbortResult(boolean abortSucceeded); void onInstrumentAbortResult(boolean abortSucceeded);
} }
protected PaymentApp(String id, String label, String sublabel, Drawable icon) { protected PaymentApp(String id, String label, @Nullable String sublabel, Drawable icon) {
super(id, maybeElide(removeLineTerminators(label)), sublabel, icon); super(id, maybeElide(removeLineTerminators(label)), sublabel, icon);
} }

@ -28,16 +28,16 @@ public interface PaymentAppFactoryParams extends PaymentRequestParams {
* @return The scheme, host, and port of the last committed URL of the top-level context as * @return The scheme, host, and port of the last committed URL of the top-level context as
* formatted by UrlFormatter.formatUrlForSecurityDisplay(). * formatted by UrlFormatter.formatUrlForSecurityDisplay().
*/ */
default @Nullable String getTopLevelOrigin() { default String getTopLevelOrigin() {
return null; throw new UnsupportedOperationException();
} }
/** /**
* @return The scheme, host, and port of the last committed URL of the iframe that invoked the * @return The scheme, host, and port of the last committed URL of the iframe that invoked the
* PaymentRequest API as formatted by UrlFormatter.formatUrlForSecurityDisplay(). * PaymentRequest API as formatted by UrlFormatter.formatUrlForSecurityDisplay().
*/ */
default @Nullable String getPaymentRequestOrigin() { default String getPaymentRequestOrigin() {
return null; throw new UnsupportedOperationException();
} }
/** /**
@ -45,8 +45,8 @@ public interface PaymentAppFactoryParams extends PaymentRequestParams {
* security features like 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'. Should not be * security features like 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'. Should not be
* null. * null.
*/ */
default @Nullable Origin getPaymentRequestSecurityOrigin() { default Origin getPaymentRequestSecurityOrigin() {
return null; throw new UnsupportedOperationException();
} }
/** /**
@ -64,14 +64,18 @@ public interface PaymentAppFactoryParams extends PaymentRequestParams {
return false; return false;
} }
/** @return The listener for payment method, shipping address, and shipping option change events. */ /**
* @return The listener for payment method, shipping address, and shipping option change events.
*/
default @Nullable PaymentRequestUpdateEventListener getPaymentRequestUpdateEventListener() { default @Nullable PaymentRequestUpdateEventListener getPaymentRequestUpdateEventListener() {
return null; return null;
} }
/** @return The Payment Request information received from the merchant. */ /**
default @Nullable PaymentRequestSpec getSpec() { * @return The Payment Request information received from the merchant.
return null; */
default PaymentRequestSpec getSpec() {
throw new UnsupportedOperationException();
} }
/** /**

@ -9,11 +9,14 @@ import org.jni_zero.NativeMethods;
import org.chromium.base.ResettersForTesting; import org.chromium.base.ResettersForTesting;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.url_formatter.SchemeDisplay; import org.chromium.components.url_formatter.SchemeDisplay;
import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.RenderFrameHost; import org.chromium.content_public.browser.RenderFrameHost;
/** Native bridge for finding payment apps. */ /** Native bridge for finding payment apps. */
@NullMarked
public class PaymentAppServiceBridge implements PaymentAppFactoryInterface { public class PaymentAppServiceBridge implements PaymentAppFactoryInterface {
private static boolean sCanMakePaymentForTesting; private static boolean sCanMakePaymentForTesting;
@ -152,7 +155,7 @@ public class PaymentAppServiceBridge implements PaymentAppFactoryInterface {
RenderFrameHost initiatorRenderFrameHost, RenderFrameHost initiatorRenderFrameHost,
String topOrigin, String topOrigin,
PaymentRequestSpec spec, PaymentRequestSpec spec,
String twaPackageName, @Nullable String twaPackageName,
boolean mayCrawlForInstallablePaymentApps, boolean mayCrawlForInstallablePaymentApps,
boolean isOffTheRecord, boolean isOffTheRecord,
long nativeCSPCheckerAndroid, long nativeCSPCheckerAndroid,

@ -4,6 +4,7 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
import org.chromium.payments.mojom.PaymentHandlerMethodData; import org.chromium.payments.mojom.PaymentHandlerMethodData;
import org.chromium.payments.mojom.PaymentHandlerModifier; import org.chromium.payments.mojom.PaymentHandlerModifier;
@ -16,6 +17,7 @@ import java.util.ArrayList;
* Redacts and converts the payment details update from the merchant into a data structure to be * Redacts and converts the payment details update from the merchant into a data structure to be
* sent to the invoked payment handler. * sent to the invoked payment handler.
*/ */
@NullMarked
public class PaymentDetailsConverter { public class PaymentDetailsConverter {
/** /**
* To be implemented by the object that can check whether the invoked payment instrument is * To be implemented by the object that can check whether the invoked payment instrument is
@ -47,7 +49,9 @@ public class PaymentDetailsConverter {
* @return The data structure that can be sent to the invoked payment handler. * @return The data structure that can be sent to the invoked payment handler.
*/ */
public static PaymentRequestDetailsUpdate convertToPaymentRequestDetailsUpdate( public static PaymentRequestDetailsUpdate convertToPaymentRequestDetailsUpdate(
PaymentDetails details, MethodChecker methodChecker, PaymentApp invokedPaymentApp) { PaymentDetails details,
MethodChecker methodChecker,
PaymentApp invokedPaymentApp) {
// Keep in sync with components/payments/content/payment_details_converter.cc. // Keep in sync with components/payments/content/payment_details_converter.cc.
assert details != null; assert details != null;
assert methodChecker != null; assert methodChecker != null;

@ -7,10 +7,12 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** The navigation throttle of the payment handler pages. */ /** The navigation throttle of the payment handler pages. */
@JNINamespace("payments::android") @JNINamespace("payments::android")
@NullMarked
public class PaymentHandlerNavigationThrottle { public class PaymentHandlerNavigationThrottle {
/** /**
* Marks the given WebContents as a payment handler WebContents. This will allow the callers of * Marks the given WebContents as a payment handler WebContents. This will allow the callers of

@ -9,6 +9,8 @@ import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.url.GURL; import org.chromium.url.GURL;
import org.chromium.url.Origin; import org.chromium.url.Origin;
@ -18,6 +20,7 @@ import org.chromium.url.Origin;
* components/payments/core/payment_manifest_downloader.h * components/payments/core/payment_manifest_downloader.h
*/ */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class PaymentManifestDownloader { public class PaymentManifestDownloader {
/** Interface for the callback to invoke when finished downloading. */ /** Interface for the callback to invoke when finished downloading. */
public interface ManifestDownloadCallback { public interface ManifestDownloadCallback {
@ -54,7 +57,7 @@ public class PaymentManifestDownloader {
} }
private long mNativeObject; private long mNativeObject;
private CSPCheckerBridge mCSPCheckerBridge; private @Nullable CSPCheckerBridge mCSPCheckerBridge;
/** /**
* Initializes the native downloader. * Initializes the native downloader.

@ -9,11 +9,13 @@ import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.url.GURL; import org.chromium.url.GURL;
/** Parses payment manifests in a utility process. */ /** Parses payment manifests in a utility process. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class PaymentManifestParser { public class PaymentManifestParser {
/** Interface for the callback to invoke when finished parsing. */ /** Interface for the callback to invoke when finished parsing. */
public interface ManifestParseCallback { public interface ManifestParseCallback {

@ -4,13 +4,15 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import static org.chromium.build.NullUtil.assumeNonNull;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.Signature; import android.content.pm.Signature;
import androidx.annotation.Nullable;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.payments.PaymentManifestDownloader.ManifestDownloadCallback; import org.chromium.components.payments.PaymentManifestDownloader.ManifestDownloadCallback;
import org.chromium.components.payments.PaymentManifestParser.ManifestParseCallback; import org.chromium.components.payments.PaymentManifestParser.ManifestParseCallback;
import org.chromium.url.GURL; import org.chromium.url.GURL;
@ -35,6 +37,7 @@ import java.util.Set;
* Spec: * Spec:
* https://docs.google.com/document/d/1izV4uC-tiRJG3JLooqY3YRLU22tYOsLTNq0P_InPJeE/edit#heading=h.cjp3jlnl47h5 * https://docs.google.com/document/d/1izV4uC-tiRJG3JLooqY3YRLU22tYOsLTNq0P_InPJeE/edit#heading=h.cjp3jlnl47h5
*/ */
@NullMarked
public class PaymentManifestVerifier public class PaymentManifestVerifier
implements ManifestDownloadCallback, implements ManifestDownloadCallback,
ManifestParseCallback, ManifestParseCallback,
@ -84,6 +87,7 @@ public class PaymentManifestVerifier
/** Identifying information about an installed native Android payment app. */ /** Identifying information about an installed native Android payment app. */
private static class AppInfo { private static class AppInfo {
/** Identifies a native Android payment app. */ /** Identifies a native Android payment app. */
@SuppressWarnings("NullAway.Init") // This is set to a non-null value immediately after init
public ResolveInfo resolveInfo; public ResolveInfo resolveInfo;
/** The version code for the native Android payment app, e.g., 123. */ /** The version code for the native Android payment app, e.g., 123. */
@ -93,7 +97,7 @@ public class PaymentManifestVerifier
* The SHA256 certificate fingerprints for the native Android payment app, .e.g, * The SHA256 certificate fingerprints for the native Android payment app, .e.g,
* ["308201dd30820146020101300d06092a864886f70d010105050030"]. * ["308201dd30820146020101300d06092a864886f70d010105050030"].
*/ */
public Set<String> sha256CertFingerprints; public @Nullable Set<String> sha256CertFingerprints;
} }
private static final String TAG = "PaymentManifest"; private static final String TAG = "PaymentManifest";
@ -130,10 +134,10 @@ public class PaymentManifestVerifier
private final PaymentManifestParser mParser; private final PaymentManifestParser mParser;
private final PackageManagerDelegate mPackageManagerDelegate; private final PackageManagerDelegate mPackageManagerDelegate;
private final ManifestVerifyCallback mCallback; private final ManifestVerifyCallback mCallback;
private final MessageDigest mMessageDigest; private final @Nullable MessageDigest mMessageDigest;
/** The origin of the payment method manifest after all redirects have been followed. */ /** The origin of the payment method manifest after all redirects have been followed. */
private Origin mPaymentMethodManifestOrigin; private @Nullable Origin mPaymentMethodManifestOrigin;
/** /**
* The number of web app manifests that have not yet been retrieved from cache or downloaded * The number of web app manifests that have not yet been retrieved from cache or downloaded
@ -237,6 +241,8 @@ public class PaymentManifestVerifier
appInfo.version = packageInfo.versionCode; appInfo.version = packageInfo.versionCode;
appInfo.sha256CertFingerprints = new HashSet<>(); appInfo.sha256CertFingerprints = new HashSet<>();
Signature[] signatures = packageInfo.signatures; Signature[] signatures = packageInfo.signatures;
assumeNonNull(signatures);
assumeNonNull(mMessageDigest);
for (int i = 0; i < signatures.length; i++) { for (int i = 0; i < signatures.length; i++) {
mMessageDigest.update(signatures[i].toByteArray()); mMessageDigest.update(signatures[i].toByteArray());
@ -263,8 +269,6 @@ public class PaymentManifestVerifier
* @return A string representation of the input bytes, e.g., "0123456789abcdef". * @return A string representation of the input bytes, e.g., "0123456789abcdef".
*/ */
private static String byteArrayToString(byte[] input) { private static String byteArrayToString(byte[] input) {
if (input == null) return null;
StringBuilder builder = new StringBuilder(input.length * 2); StringBuilder builder = new StringBuilder(input.length * 2);
Formatter formatter = new Formatter(builder); Formatter formatter = new Formatter(builder);
for (byte b : input) { for (byte b : input) {
@ -344,7 +348,8 @@ public class PaymentManifestVerifier
Set<String> validAppPackageNames = verifyAppWithWebAppManifest(manifest); Set<String> validAppPackageNames = verifyAppWithWebAppManifest(manifest);
for (String validAppPackageName : validAppPackageNames) { for (String validAppPackageName : validAppPackageNames) {
mCallback.onValidDefaultPaymentApp( mCallback.onValidDefaultPaymentApp(
mMethodName, mDefaultApplications.get(validAppPackageName).resolveInfo); mMethodName,
assumeNonNull(mDefaultApplications.get(validAppPackageName)).resolveInfo);
} }
mPendingWebAppManifestsCount--; mPendingWebAppManifestsCount--;
@ -400,6 +405,7 @@ public class PaymentManifestVerifier
for (int i = 0; i < webAppManifestUris.length; i++) { for (int i = 0; i < webAppManifestUris.length; i++) {
if (mAtLeastOneManifestFailedToDownloadOrParse) return; if (mAtLeastOneManifestFailedToDownloadOrParse) return;
assert webAppManifestUris[i] != null; assert webAppManifestUris[i] != null;
assumeNonNull(mPaymentMethodManifestOrigin);
mDownloader.downloadWebAppManifest( mDownloader.downloadWebAppManifest(
mPaymentMethodManifestOrigin, webAppManifestUris[i], this); mPaymentMethodManifestOrigin, webAppManifestUris[i], this);
} }
@ -428,7 +434,8 @@ public class PaymentManifestVerifier
Set<String> validAppPackageNames = verifyAppWithWebAppManifest(manifest); Set<String> validAppPackageNames = verifyAppWithWebAppManifest(manifest);
for (String validAppPackageName : validAppPackageNames) { for (String validAppPackageName : validAppPackageNames) {
mCallback.onValidDefaultPaymentApp( mCallback.onValidDefaultPaymentApp(
mMethodName, mDefaultApplications.get(validAppPackageName).resolveInfo); mMethodName,
assumeNonNull(mDefaultApplications.get(validAppPackageName)).resolveInfo);
} }
} }

@ -8,10 +8,12 @@ import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** Java wrapper of the payment manifest web data service. */ /** Java wrapper of the payment manifest web data service. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class PaymentManifestWebDataService { public class PaymentManifestWebDataService {
/** Interface for the callback to invoke when getting data from the web data service. */ /** Interface for the callback to invoke when getting data from the web data service. */
public interface PaymentManifestWebDataServiceCallback { public interface PaymentManifestWebDataServiceCallback {

@ -4,9 +4,11 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.payments.mojom.PaymentErrorReason; import org.chromium.payments.mojom.PaymentErrorReason;
/** The error of payment UIs not being shown. */ /** The error of payment UIs not being shown. */
@NullMarked
public class PaymentNotShownError { public class PaymentNotShownError {
private final String mErrorMessage; private final String mErrorMessage;
private final int mReason; private final int mReason;

@ -4,11 +4,12 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import androidx.annotation.Nullable; import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.payments.mojom.PaymentOptions; import org.chromium.payments.mojom.PaymentOptions;
/** A collection of utility methods for PaymentOptions. */ /** A collection of utility methods for PaymentOptions. */
@NullMarked
public class PaymentOptionsUtils { public class PaymentOptionsUtils {
/** /**
* @param options Any PaymentOption, can be null. * @param options Any PaymentOption, can be null.

@ -6,6 +6,7 @@ package org.chromium.components.payments;
import org.chromium.build.annotations.MockedInTests; import org.chromium.build.annotations.MockedInTests;
import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
import org.chromium.payments.mojom.PaymentItem; import org.chromium.payments.mojom.PaymentItem;
import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentMethodData;
@ -43,5 +44,5 @@ public interface PaymentRequestParams {
* @return The raw total amount being charged - the total property of the PaymentDetails of * @return The raw total amount being charged - the total property of the PaymentDetails of
* payment request. * payment request.
*/ */
PaymentItem getRawTotal(); @Nullable PaymentItem getRawTotal();
} }

@ -4,10 +4,11 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import static org.chromium.build.NullUtil.assumeNonNull;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap; import androidx.collection.ArrayMap;
@ -17,6 +18,8 @@ import org.chromium.base.Log;
import org.chromium.base.ResettersForTesting; import org.chromium.base.ResettersForTesting;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.url_formatter.SchemeDisplay; import org.chromium.components.url_formatter.SchemeDisplay;
import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.components.url_formatter.UrlFormatter;
@ -65,6 +68,7 @@ import java.util.Set;
* class need to close them with {@link PaymentRequestService#close()}, after which no usage is * class need to close them with {@link PaymentRequestService#close()}, after which no usage is
* allowed. * allowed.
*/ */
@NullMarked
public class PaymentRequestService public class PaymentRequestService
implements PaymentAppFactoryDelegate, implements PaymentAppFactoryDelegate,
PaymentAppFactoryParams, PaymentAppFactoryParams,
@ -80,29 +84,37 @@ public class PaymentRequestService
* Hold the currently showing PaymentRequest. Used to prevent showing more than one * Hold the currently showing PaymentRequest. Used to prevent showing more than one
* PaymentRequest UI per browser process. * PaymentRequest UI per browser process.
*/ */
private static PaymentRequestService sShowingPaymentRequest; private static @Nullable PaymentRequestService sShowingPaymentRequest;
private static PaymentRequestServiceObserverForTest sObserverForTest; private static @Nullable PaymentRequestServiceObserverForTest sObserverForTest;
private static NativeObserverForTest sNativeObserverForTest; private static @Nullable NativeObserverForTest sNativeObserverForTest;
private static boolean sIsLocalHasEnrolledInstrumentQueryQuotaEnforcedForTest; private static boolean sIsLocalHasEnrolledInstrumentQueryQuotaEnforcedForTest;
private final Runnable mOnClosedListener; private final Runnable mOnClosedListener;
private final RenderFrameHost mRenderFrameHost; private final RenderFrameHost mRenderFrameHost;
private final Delegate mDelegate; private final Delegate mDelegate;
private final List<PaymentApp> mPendingApps = new ArrayList<>(); private final List<PaymentApp> mPendingApps = new ArrayList<>();
@Nullable private final Supplier<PaymentAppServiceBridge> mPaymentAppServiceBridgeSupplier; private final @Nullable Supplier<PaymentAppServiceBridge> mPaymentAppServiceBridgeSupplier;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private WebContents mWebContents; private WebContents mWebContents;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private JourneyLogger mJourneyLogger; private JourneyLogger mJourneyLogger;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private String mTopLevelOrigin; private String mTopLevelOrigin;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private String mPaymentRequestOrigin; private String mPaymentRequestOrigin;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private Origin mPaymentRequestSecurityOrigin; private Origin mPaymentRequestSecurityOrigin;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private String mMerchantName; private String mMerchantName;
private boolean mIsOffTheRecord; private boolean mIsOffTheRecord;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private PaymentOptions mPaymentOptions; private PaymentOptions mPaymentOptions;
private boolean mRequestShipping; private boolean mRequestShipping;
private boolean mRequestPayerName; private boolean mRequestPayerName;
private boolean mRequestPayerPhone; private boolean mRequestPayerPhone;
private boolean mRequestPayerEmail; private boolean mRequestPayerEmail;
private int mShippingType; private int mShippingType;
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private PaymentRequestSpec mSpec; private PaymentRequestSpec mSpec;
private boolean mHasClosed; private boolean mHasClosed;
private boolean mIsFinishedQueryingPaymentApps; private boolean mIsFinishedQueryingPaymentApps;
@ -110,21 +122,22 @@ public class PaymentRequestService
private boolean mIsShowWaitingForUpdatedDetails; private boolean mIsShowWaitingForUpdatedDetails;
/** If not empty, use this error message for rejecting PaymentRequest.show(). */ /** If not empty, use this error message for rejecting PaymentRequest.show(). */
private String mRejectShowErrorMessage; private @Nullable String mRejectShowErrorMessage;
/** Internal reason for why PaymentRequest.show() should be rejected. */ /** Internal reason for why PaymentRequest.show() should be rejected. */
private @AppCreationFailureReason int mRejectShowErrorReason = AppCreationFailureReason.UNKNOWN; private @AppCreationFailureReason int mRejectShowErrorReason = AppCreationFailureReason.UNKNOWN;
// mClient is null only when it has closed. // mClient is null only when it has closed.
@Nullable private PaymentRequestClient mClient; private @Nullable PaymentRequestClient mClient;
// mBrowserPaymentRequest is null when it has closed or is uninitiated. // mBrowserPaymentRequest is null when it has closed or is uninitiated.
@Nullable private BrowserPaymentRequest mBrowserPaymentRequest; private @Nullable BrowserPaymentRequest mBrowserPaymentRequest;
/** The helper to create and fill the response to send to the merchant. */ /** The helper to create and fill the response to send to the merchant. */
@Nullable private PaymentResponseHelperInterface mPaymentResponseHelper; private @Nullable PaymentResponseHelperInterface mPaymentResponseHelper;
/** A mapping of the payment method names to the corresponding payment method specific data. */ /** A mapping of the payment method names to the corresponding payment method specific data. */
@SuppressWarnings("NullAway.Init") // When init() fails this can have null value
private HashMap<String, PaymentMethodData> mQueryForQuota; private HashMap<String, PaymentMethodData> mQueryForQuota;
/** /**
@ -142,7 +155,7 @@ public class PaymentRequestService
private boolean mIsCanMakePaymentResponsePending; private boolean mIsCanMakePaymentResponsePending;
private boolean mIsHasEnrolledInstrumentResponsePending; private boolean mIsHasEnrolledInstrumentResponsePending;
@Nullable private PaymentApp mInvokedPaymentApp; private @Nullable PaymentApp mInvokedPaymentApp;
/** True if a show() call is rejected for lack of a user activation. */ /** True if a show() call is rejected for lack of a user activation. */
private boolean mRejectShowForUserActivation; private boolean mRejectShowForUserActivation;
@ -162,7 +175,7 @@ public class PaymentRequestService
void onHasEnrolledInstrumentReturned(); void onHasEnrolledInstrumentReturned();
void onAppListReady(@Nullable List<PaymentApp> paymentApps, PaymentItem total); void onAppListReady(@Nullable List<PaymentApp> paymentApps, @Nullable PaymentItem total);
void onShippingSectionVisibilityChange(boolean isShippingSectionVisible); void onShippingSectionVisibilityChange(boolean isShippingSectionVisible);
@ -223,8 +236,7 @@ public class PaymentRequestService
* returns the package name for Trusted Web Activity. Otherwise returns an empty string * returns the package name for Trusted Web Activity. Otherwise returns an empty string
* or null. * or null.
*/ */
@Nullable @Nullable String getTwaPackageName();
String getTwaPackageName();
/** /**
* Gets the WebContents from a RenderFrameHost if the WebContents has not been destroyed; * Gets the WebContents from a RenderFrameHost if the WebContents has not been destroyed;
@ -234,8 +246,7 @@ public class PaymentRequestService
* WebContents contains. * WebContents contains.
* @return The WebContents. * @return The WebContents.
*/ */
@Nullable default @Nullable WebContents getLiveWebContents(RenderFrameHost renderFrameHost) {
default WebContents getLiveWebContents(RenderFrameHost renderFrameHost) {
return PaymentRequestServiceUtil.getLiveWebContents(renderFrameHost); return PaymentRequestServiceUtil.getLiveWebContents(renderFrameHost);
} }
@ -318,8 +329,7 @@ public class PaymentRequestService
* *
* @return The instance, can be null for testing. * @return The instance, can be null for testing.
*/ */
@Nullable default @Nullable PaymentAppFactoryInterface createAndroidPaymentAppFactory() {
default PaymentAppFactoryInterface createAndroidPaymentAppFactory() {
return new AndroidPaymentAppFactory(); return new AndroidPaymentAppFactory();
} }
@ -327,8 +337,7 @@ public class PaymentRequestService
* @return The context of the current activity, can be null when WebContents has been * @return The context of the current activity, can be null when WebContents has been
* destroyed, the activity is gone, the window is closed, etc. * destroyed, the activity is gone, the window is closed, etc.
*/ */
@Nullable default @Nullable Context getContext(RenderFrameHost renderFrameHost) {
default Context getContext(RenderFrameHost renderFrameHost) {
WindowAndroid window = getWindowAndroid(renderFrameHost); WindowAndroid window = getWindowAndroid(renderFrameHost);
if (window == null) return null; if (window == null) return null;
return window.getContext().get(); return window.getContext().get();
@ -338,8 +347,7 @@ public class PaymentRequestService
* @return The WindowAndroid of the current activity, can be null when WebContents has been * @return The WindowAndroid of the current activity, can be null when WebContents has been
* destroyed, the activity is gone, etc. * destroyed, the activity is gone, etc.
*/ */
@Nullable default @Nullable WindowAndroid getWindowAndroid(RenderFrameHost renderFrameHost) {
default WindowAndroid getWindowAndroid(RenderFrameHost renderFrameHost) {
WebContents webContents = PaymentRequestServiceUtil.getLiveWebContents(renderFrameHost); WebContents webContents = PaymentRequestServiceUtil.getLiveWebContents(renderFrameHost);
if (webContents == null) return null; if (webContents == null) return null;
return webContents.getTopLevelNativeWindow(); return webContents.getTopLevelNativeWindow();
@ -435,7 +443,7 @@ public class PaymentRequestService
* @return Whether the initialization is successful. * @return Whether the initialization is successful.
*/ */
public boolean init( public boolean init(
@Nullable PaymentMethodData[] rawMethodData, PaymentMethodData @Nullable [] rawMethodData,
@Nullable PaymentDetails details, @Nullable PaymentDetails details,
@Nullable PaymentOptions options) { @Nullable PaymentOptions options) {
if (mRenderFrameHost.getLastCommittedOrigin() == null if (mRenderFrameHost.getLastCommittedOrigin() == null
@ -448,11 +456,12 @@ public class PaymentRequestService
mPaymentRequestOrigin = mPaymentRequestOrigin =
mDelegate.formatUrlForSecurityDisplay(mRenderFrameHost.getLastCommittedURL()); mDelegate.formatUrlForSecurityDisplay(mRenderFrameHost.getLastCommittedURL());
mWebContents = mDelegate.getLiveWebContents(mRenderFrameHost); WebContents webContents = mDelegate.getLiveWebContents(mRenderFrameHost);
if (mWebContents == null || mWebContents.isDestroyed()) { if (webContents == null || webContents.isDestroyed()) {
abortForInvalidDataFromRenderer(ErrorStrings.NO_WEB_CONTENTS); abortForInvalidDataFromRenderer(ErrorStrings.NO_WEB_CONTENTS);
return false; return false;
} }
mWebContents = webContents;
// TODO(crbug.com/41475385): replace UrlFormatter with GURL operations. // TODO(crbug.com/41475385): replace UrlFormatter with GURL operations.
mTopLevelOrigin = mDelegate.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl()); mTopLevelOrigin = mDelegate.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl());
@ -585,6 +594,7 @@ public class PaymentRequestService
return false; return false;
} }
PaymentMethodData spcMethodData = methodData.get(MethodStrings.SECURE_PAYMENT_CONFIRMATION); PaymentMethodData spcMethodData = methodData.get(MethodStrings.SECURE_PAYMENT_CONFIRMATION);
assumeNonNull(spcMethodData);
if (spcMethodData.securePaymentConfirmation == null) return false; if (spcMethodData.securePaymentConfirmation == null) return false;
// TODO(crbug.com/40231121): Update checks to match desktop browser-side logic. // TODO(crbug.com/40231121): Update checks to match desktop browser-side logic.
@ -637,12 +647,12 @@ public class PaymentRequestService
* @return The WebContents of the payment handler that's just opened when the opening is * @return The WebContents of the payment handler that's just opened when the opening is
* successful; null if failed. * successful; null if failed.
*/ */
@Nullable public static @Nullable WebContents openPaymentHandlerWindow(GURL url) {
public static WebContents openPaymentHandlerWindow(GURL url) {
if (sShowingPaymentRequest == null) return null; if (sShowingPaymentRequest == null) return null;
PaymentApp invokedPaymentApp = sShowingPaymentRequest.mInvokedPaymentApp; PaymentApp invokedPaymentApp = sShowingPaymentRequest.mInvokedPaymentApp;
assert invokedPaymentApp != null; assert invokedPaymentApp != null;
assert invokedPaymentApp.getPaymentAppType() == PaymentAppType.SERVICE_WORKER_APP; assert invokedPaymentApp.getPaymentAppType() == PaymentAppType.SERVICE_WORKER_APP;
assumeNonNull(sShowingPaymentRequest.mBrowserPaymentRequest);
return sShowingPaymentRequest.mBrowserPaymentRequest.openPaymentHandlerWindow( return sShowingPaymentRequest.mBrowserPaymentRequest.openPaymentHandlerWindow(
url, invokedPaymentApp.getUkmSourceId()); url, invokedPaymentApp.getUkmSourceId());
} }
@ -698,8 +708,7 @@ public class PaymentRequestService
/** /**
* @return Get the native=side observer, for testing purpose only. * @return Get the native=side observer, for testing purpose only.
*/ */
@Nullable public static @Nullable NativeObserverForTest getNativeObserverForTest() {
public static NativeObserverForTest getNativeObserverForTest() {
return sNativeObserverForTest; return sNativeObserverForTest;
} }
@ -739,12 +748,14 @@ public class PaymentRequestService
// Implements PaymentResponseHelper.PaymentResponseResultCallback: // Implements PaymentResponseHelper.PaymentResponseResultCallback:
@Override @Override
public void onPaymentResponseReady(PaymentResponse response) { public void onPaymentResponseReady(PaymentResponse response) {
assumeNonNull(mBrowserPaymentRequest);
if (!mBrowserPaymentRequest.patchPaymentResponseIfNeeded(response)) { if (!mBrowserPaymentRequest.patchPaymentResponseIfNeeded(response)) {
disconnectFromClientWithDebugMessage( disconnectFromClientWithDebugMessage(
ErrorStrings.PAYMENT_APP_INVALID_RESPONSE, PaymentErrorReason.NOT_SUPPORTED); ErrorStrings.PAYMENT_APP_INVALID_RESPONSE, PaymentErrorReason.NOT_SUPPORTED);
// Intentionally do not early-return. // Intentionally do not early-return.
} }
if (response.methodName.equals(MethodStrings.SECURE_PAYMENT_CONFIRMATION)) { if (response.methodName.equals(MethodStrings.SECURE_PAYMENT_CONFIRMATION)) {
assumeNonNull(mInvokedPaymentApp);
assert mInvokedPaymentApp.getInstrumentMethodNames().contains(response.methodName); assert mInvokedPaymentApp.getInstrumentMethodNames().contains(response.methodName);
response = mInvokedPaymentApp.setAppSpecificResponseFields(response); response = mInvokedPaymentApp.setAppSpecificResponseFields(response);
} }
@ -825,13 +836,13 @@ public class PaymentRequestService
? mSpec.getRawShippingOptions() ? mSpec.getRawShippingOptions()
: Collections.unmodifiableList(new ArrayList<>()); : Collections.unmodifiableList(new ArrayList<>());
paymentApp.invokePaymentApp( paymentApp.invokePaymentApp(
mSpec.getId(), assumeNonNull(mSpec.getId()),
mMerchantName, mMerchantName,
mTopLevelOrigin, mTopLevelOrigin,
mPaymentRequestOrigin, mPaymentRequestOrigin,
getCertificateChain(), getCertificateChain(),
Collections.unmodifiableMap(methodData), Collections.unmodifiableMap(methodData),
mSpec.getRawTotal(), assumeNonNull(mSpec.getRawTotal()),
mSpec.getRawLineItems(), mSpec.getRawLineItems(),
Collections.unmodifiableMap(modifiers), Collections.unmodifiableMap(modifiers),
paymentOptions, paymentOptions,
@ -912,8 +923,7 @@ public class PaymentRequestService
} }
} }
@Nullable private @Nullable PaymentNotShownError onShowCalledAndAppsQueried() {
private PaymentNotShownError onShowCalledAndAppsQueried() {
assert mIsShowCalled; assert mIsShowCalled;
assert mIsFinishedQueryingPaymentApps; assert mIsFinishedQueryingPaymentApps;
assert mBrowserPaymentRequest != null; assert mBrowserPaymentRequest != null;
@ -989,10 +999,10 @@ public class PaymentRequestService
* *
* @return The error if the payment cannot be made; null otherwise. * @return The error if the payment cannot be made; null otherwise.
*/ */
@Nullable private @Nullable PaymentNotShownError ensureHasSupportedPaymentMethods() {
private PaymentNotShownError ensureHasSupportedPaymentMethods() {
assert mIsShowCalled; assert mIsShowCalled;
assert mIsFinishedQueryingPaymentApps; assert mIsFinishedQueryingPaymentApps;
assumeNonNull(mBrowserPaymentRequest);
if (!mCanMakePayment || !mBrowserPaymentRequest.hasAvailableApps()) { if (!mCanMakePayment || !mBrowserPaymentRequest.hasAvailableApps()) {
// All factories have responded, but none of them have apps. It's possible to add credit // All factories have responded, but none of them have apps. It's possible to add credit
// cards, but the merchant does not support them either. The payment request must be // cards, but the merchant does not support them either. The payment request must be
@ -1166,12 +1176,14 @@ public class PaymentRequestService
// Implements PaymentAppFactoryDelegate: // Implements PaymentAppFactoryDelegate:
@Override @Override
public DialogController getDialogController() { public DialogController getDialogController() {
assumeNonNull(mBrowserPaymentRequest);
return mBrowserPaymentRequest.getDialogController(); return mBrowserPaymentRequest.getDialogController();
} }
// Implements PaymentAppFactoryDelegate: // Implements PaymentAppFactoryDelegate:
@Override @Override
public AndroidIntentLauncher getAndroidIntentLauncher() { public AndroidIntentLauncher getAndroidIntentLauncher() {
assumeNonNull(mBrowserPaymentRequest);
return mBrowserPaymentRequest.getAndroidIntentLauncher(); return mBrowserPaymentRequest.getAndroidIntentLauncher();
} }
@ -1180,8 +1192,7 @@ public class PaymentRequestService
* @return The validated method data, a mapping of method names to its PaymentMethodData(s); * @return The validated method data, a mapping of method names to its PaymentMethodData(s);
* when the given method data is invalid, returns null. * when the given method data is invalid, returns null.
*/ */
@Nullable private static @Nullable Map<String, PaymentMethodData> getValidatedMethodData(
private static Map<String, PaymentMethodData> getValidatedMethodData(
PaymentMethodData[] methodDataList) { PaymentMethodData[] methodDataList) {
// Payment methodData are required. // Payment methodData are required.
assert methodDataList != null; assert methodDataList != null;
@ -1228,6 +1239,7 @@ public class PaymentRequestService
if (!hadUserActivation) { if (!hadUserActivation) {
PaymentRequestWebContentsData paymentRequestWebContentsData = PaymentRequestWebContentsData paymentRequestWebContentsData =
PaymentRequestWebContentsData.from(mWebContents); PaymentRequestWebContentsData.from(mWebContents);
assumeNonNull(paymentRequestWebContentsData);
if (paymentRequestWebContentsData.hadActivationlessShow()) { if (paymentRequestWebContentsData.hadActivationlessShow()) {
// Reject the call to show(), because only one activationless show is allowed per // Reject the call to show(), because only one activationless show is allowed per
// page. // page.
@ -1326,13 +1338,14 @@ public class PaymentRequestService
} }
private boolean isPaymentDetailsUpdateValid(PaymentDetails details) { private boolean isPaymentDetailsUpdateValid(PaymentDetails details) {
assumeNonNull(mBrowserPaymentRequest);
// ID cannot be updated. Updating the total is optional. // ID cannot be updated. Updating the total is optional.
return details.id == null return details.id == null
&& mDelegate.validatePaymentDetails(details) && mDelegate.validatePaymentDetails(details)
&& mBrowserPaymentRequest.parseAndValidateDetailsFurtherIfNeeded(details); && mBrowserPaymentRequest.parseAndValidateDetailsFurtherIfNeeded(details);
} }
private String continueShowWithUpdatedDetails(@Nullable PaymentDetails details) { private @Nullable String continueShowWithUpdatedDetails(@Nullable PaymentDetails details) {
assert mIsShowWaitingForUpdatedDetails; assert mIsShowWaitingForUpdatedDetails;
assert mBrowserPaymentRequest != null; assert mBrowserPaymentRequest != null;
// mSpec.updateWith() can be used only when mSpec has not been destroyed. // mSpec.updateWith() can be used only when mSpec has not been destroyed.
@ -1406,6 +1419,7 @@ public class PaymentRequestService
// After a payment app has been invoked, all of the merchant's calls to update the price // After a payment app has been invoked, all of the merchant's calls to update the price
// via updateWith() should be forwarded to the invoked app, so it can reflect the // via updateWith() should be forwarded to the invoked app, so it can reflect the
// updated price in its UI. // updated price in its UI.
assumeNonNull(mInvokedPaymentApp);
mInvokedPaymentApp.updateWith( mInvokedPaymentApp.updateWith(
PaymentDetailsConverter.convertToPaymentRequestDetailsUpdate( PaymentDetailsConverter.convertToPaymentRequestDetailsUpdate(
details, /* methodChecker= */ this, mInvokedPaymentApp)); details, /* methodChecker= */ this, mInvokedPaymentApp));
@ -1601,8 +1615,7 @@ public class PaymentRequestService
/** /**
* @return An observer for the payment request service, if any; otherwise, null. * @return An observer for the payment request service, if any; otherwise, null.
*/ */
@Nullable public static @Nullable PaymentRequestServiceObserverForTest getObserverForTest() {
public static PaymentRequestServiceObserverForTest getObserverForTest() {
return sObserverForTest; return sObserverForTest;
} }
@ -1685,7 +1698,7 @@ public class PaymentRequestService
// PaymentAppFactoryParams implementation. // PaymentAppFactoryParams implementation.
@Override @Override
public String getId() { public @Nullable String getId() {
assert !mHasClosed; assert !mHasClosed;
assert !mSpec.isDestroyed(); assert !mSpec.isDestroyed();
return mSpec.getId(); return mSpec.getId();
@ -1711,8 +1724,8 @@ public class PaymentRequestService
// PaymentAppFactoryParams implementation. // PaymentAppFactoryParams implementation.
@Override @Override
@Nullable public byte @Nullable [][] getCertificateChain() {
public byte[][] getCertificateChain() { assumeNonNull(mBrowserPaymentRequest);
return mBrowserPaymentRequest.getCertificateChain(); return mBrowserPaymentRequest.getCertificateChain();
} }
@ -1726,7 +1739,7 @@ public class PaymentRequestService
// PaymentAppFactoryParams implementation. // PaymentAppFactoryParams implementation.
@Override @Override
public PaymentItem getRawTotal() { public @Nullable PaymentItem getRawTotal() {
assert !mHasClosed; assert !mHasClosed;
assert !mSpec.isDestroyed(); assert !mSpec.isDestroyed();
return mSpec.getRawTotal(); return mSpec.getRawTotal();
@ -1758,8 +1771,7 @@ public class PaymentRequestService
// PaymentAppFactoryParams implementation. // PaymentAppFactoryParams implementation.
@Override @Override
@Nullable public @Nullable String getTwaPackageName() {
public String getTwaPackageName() {
return mDelegate.getTwaPackageName(); return mDelegate.getTwaPackageName();
} }
@ -1881,8 +1893,7 @@ public class PaymentRequestService
} }
@VisibleForTesting @VisibleForTesting
@Nullable public static @Nullable BrowserPaymentRequest getBrowserPaymentRequestForTesting() {
public static BrowserPaymentRequest getBrowserPaymentRequestForTesting() {
return sShowingPaymentRequest != null return sShowingPaymentRequest != null
? sShowingPaymentRequest.mBrowserPaymentRequest ? sShowingPaymentRequest.mBrowserPaymentRequest
: null; : null;

@ -4,14 +4,15 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import androidx.annotation.Nullable; import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.content_public.browser.RenderFrameHost; import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.Visibility; import org.chromium.content_public.browser.Visibility;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsStatics; import org.chromium.content_public.browser.WebContentsStatics;
/** The utility class for PaymentRequestFactory and WebLayerPaymentRequestFactory. */ /** The utility class for PaymentRequestFactory and WebLayerPaymentRequestFactory. */
@NullMarked
public final class PaymentRequestServiceUtil { public final class PaymentRequestServiceUtil {
/** /**
* Gets the WebContents from a RenderFrameHost if the WebContents has not been destroyed; * Gets the WebContents from a RenderFrameHost if the WebContents has not been destroyed;
@ -20,8 +21,7 @@ public final class PaymentRequestServiceUtil {
* WebContents contains. * WebContents contains.
* @return The WebContents. * @return The WebContents.
*/ */
@Nullable public static @Nullable WebContents getLiveWebContents(RenderFrameHost renderFrameHost) {
public static WebContents getLiveWebContents(RenderFrameHost renderFrameHost) {
WebContents webContents = WebContentsStatics.fromRenderFrameHost(renderFrameHost); WebContents webContents = WebContentsStatics.fromRenderFrameHost(renderFrameHost);
return webContents != null && !webContents.isDestroyed() ? webContents : null; return webContents != null && !webContents.isDestroyed() ? webContents : null;
} }

@ -10,6 +10,8 @@ import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.base.UserData; import org.chromium.base.UserData;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.content.browser.webcontents.WebContentsImpl; import org.chromium.content.browser.webcontents.WebContentsImpl;
import org.chromium.content.browser.webcontents.WebContentsImpl.UserDataFactory; import org.chromium.content.browser.webcontents.WebContentsImpl.UserDataFactory;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
@ -21,8 +23,9 @@ import org.chromium.content_public.browser.WebContentsObserver;
* user activation, which is recorded and tracked by the native PaymentRequestWebContentsManager. * user activation, which is recorded and tracked by the native PaymentRequestWebContentsManager.
*/ */
@JNINamespace("payments::android") @JNINamespace("payments::android")
@NullMarked
public class PaymentRequestWebContentsData extends WebContentsObserver implements UserData { public class PaymentRequestWebContentsData extends WebContentsObserver implements UserData {
private static PaymentRequestWebContentsData sInstanceForTesting; private static @Nullable PaymentRequestWebContentsData sInstanceForTesting;
private static final class UserDataFactoryLazyHolder { private static final class UserDataFactoryLazyHolder {
private static final UserDataFactory<PaymentRequestWebContentsData> INSTANCE = private static final UserDataFactory<PaymentRequestWebContentsData> INSTANCE =
@ -40,7 +43,7 @@ public class PaymentRequestWebContentsData extends WebContentsObserver implement
* @param webContents The web contents of the current PaymentRequest. * @param webContents The web contents of the current PaymentRequest.
* @return the PaymentRequestWebContentsData instance. * @return the PaymentRequestWebContentsData instance.
*/ */
public static PaymentRequestWebContentsData from(WebContents webContents) { public static @Nullable PaymentRequestWebContentsData from(WebContents webContents) {
return sInstanceForTesting != null return sInstanceForTesting != null
? sInstanceForTesting ? sInstanceForTesting
: ((WebContentsImpl) webContents) : ((WebContentsImpl) webContents)

@ -4,6 +4,7 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.payments.mojom.PayerDetail; import org.chromium.payments.mojom.PayerDetail;
import org.chromium.payments.mojom.PaymentOptions; import org.chromium.payments.mojom.PaymentOptions;
import org.chromium.payments.mojom.PaymentResponse; import org.chromium.payments.mojom.PaymentResponse;
@ -13,6 +14,7 @@ import org.chromium.payments.mojom.PaymentResponse;
* Compared to ChromePaymentResponseHelper, this helper does not handle the Autofill data, and so * Compared to ChromePaymentResponseHelper, this helper does not handle the Autofill data, and so
* can be used for WebLayerPaymentRequestService. * can be used for WebLayerPaymentRequestService.
*/ */
@NullMarked
public class PaymentResponseHelper implements PaymentResponseHelperInterface { public class PaymentResponseHelper implements PaymentResponseHelperInterface {
private final PaymentResponse mPaymentResponse; private final PaymentResponse mPaymentResponse;
private final PaymentOptions mPaymentOptions; private final PaymentOptions mPaymentOptions;

@ -4,12 +4,14 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.payments.mojom.PaymentResponse; import org.chromium.payments.mojom.PaymentResponse;
/** /**
* The interface of a helper class that generates a {@link PaymentResponse} with the input of * The interface of a helper class that generates a {@link PaymentResponse} with the input of
* payment details. * payment details.
*/ */
@NullMarked
public interface PaymentResponseHelperInterface { public interface PaymentResponseHelperInterface {
/** /**
* Generates a {@link PaymentResponse} with the given payment details. * Generates a {@link PaymentResponse} with the given payment details.

@ -4,9 +4,11 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** The interface of PaymentUiService that provides testing methods. */ /** The interface of PaymentUiService that provides testing methods. */
@NullMarked
public interface PaymentUiServiceTestInterface { public interface PaymentUiServiceTestInterface {
/** /**
* Get the WebContents of the Payment Handler; return null if nonexistent. * Get the WebContents of the Payment Handler; return null if nonexistent.

@ -7,6 +7,7 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
import org.chromium.payments.mojom.PaymentValidationErrors; import org.chromium.payments.mojom.PaymentValidationErrors;
@ -14,6 +15,7 @@ import java.nio.ByteBuffer;
/** Static class to represent a JNI interface to a C++ validation library. */ /** Static class to represent a JNI interface to a C++ validation library. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class PaymentValidator { public class PaymentValidator {
public static boolean validatePaymentDetails(PaymentDetails details) { public static boolean validatePaymentDetails(PaymentDetails details) {
if (details == null) { if (details == null) {

@ -7,10 +7,12 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** SSL validity checker. */ /** SSL validity checker. */
@JNINamespace("payments") @JNINamespace("payments")
@NullMarked
public class SslValidityChecker { public class SslValidityChecker {
/** /**
* Returns a developer-facing error message for invalid SSL certificate state or an empty * Returns a developer-facing error message for invalid SSL certificate state or an empty

@ -4,11 +4,12 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import androidx.annotation.Nullable;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
/** This class represents the supported delegations of a service worker based payment app. */ /** This class represents the supported delegations of a service worker based payment app. */
@NullMarked
public class SupportedDelegations { public class SupportedDelegations {
private static final String TAG = "SupportedDelegations"; private static final String TAG = "SupportedDelegations";
private final boolean mShippingAddress; private final boolean mShippingAddress;
@ -57,7 +58,7 @@ public class SupportedDelegations {
} }
public static SupportedDelegations createFromStringArray( public static SupportedDelegations createFromStringArray(
@Nullable String[] supportedDelegationsNames) throws IllegalArgumentException { String @Nullable [] supportedDelegationsNames) throws IllegalArgumentException {
if (supportedDelegationsNames == null || supportedDelegationsNames.length == 0) { if (supportedDelegationsNames == null || supportedDelegationsNames.length == 0) {
return new SupportedDelegations(); return new SupportedDelegations();
} }

@ -7,11 +7,13 @@ package org.chromium.components.payments;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked;
import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.url.GURL; import org.chromium.url.GURL;
/** URL validity checker for web payment APIs. */ /** URL validity checker for web payment APIs. */
@JNINamespace("payments::android") @JNINamespace("payments::android")
@NullMarked
public class UrlUtil { public class UrlUtil {
/** /**
* Returns false for invalid URL format or a relative URI. * Returns false for invalid URL format or a relative URI.

@ -4,7 +4,10 @@
package org.chromium.components.payments; package org.chromium.components.payments;
import org.chromium.build.annotations.NullMarked;
/** Java equivalent of components/payments/content/web_app_manifest.h:WebAppManifestSection */ /** Java equivalent of components/payments/content/web_app_manifest.h:WebAppManifestSection */
@NullMarked
public final class WebAppManifestSection { public final class WebAppManifestSection {
/** /**
* Constructor that does not set the fingerprints. They have to be set after the object is * Constructor that does not set the fingerprints. They have to be set after the object is

@ -17,9 +17,12 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.IsReadyToPayService; import org.chromium.IsReadyToPayService;
import org.chromium.IsReadyToPayServiceCallback; import org.chromium.IsReadyToPayServiceCallback;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.payments.PrePurchaseQuery; import org.chromium.components.payments.PrePurchaseQuery;
/** A helper to query the payment app's IsReadyToPay service. */ /** A helper to query the payment app's IsReadyToPay service. */
@NullMarked
public class IsReadyToPayServiceHelper extends IsReadyToPayServiceCallback.Stub public class IsReadyToPayServiceHelper extends IsReadyToPayServiceCallback.Stub
implements ServiceConnection { implements ServiceConnection {
/** The maximum number of milliseconds to wait for a response from a READY_TO_PAY service. */ /** The maximum number of milliseconds to wait for a response from a READY_TO_PAY service. */
@ -31,7 +34,7 @@ public class IsReadyToPayServiceHelper extends IsReadyToPayServiceCallback.Stub
private final Context mContext; private final Context mContext;
// This callback can be used only once, set to null after that. // This callback can be used only once, set to null after that.
private ResultHandler mResultHandler; private @Nullable ResultHandler mResultHandler;
private boolean mIsServiceBindingInitiated; private boolean mIsServiceBindingInitiated;
private boolean mIsServiceConnected; private boolean mIsServiceConnected;

@ -122,7 +122,7 @@ public class WebPaymentIntentHelper {
public static void parsePaymentResponse( public static void parsePaymentResponse(
int resultCode, int resultCode,
Intent data, Intent data,
PaymentOptions requestedPaymentOptions, @Nullable PaymentOptions requestedPaymentOptions,
PaymentErrorCallback errorCallback, PaymentErrorCallback errorCallback,
PaymentSuccessCallback successCallback) { PaymentSuccessCallback successCallback) {
if (data == null) { if (data == null) {

@ -115,10 +115,10 @@ public final class WebPaymentIntentHelperType {
/** The class that corresponds mojom.PaymentDetailsModifier, with minimally required fields. */ /** The class that corresponds mojom.PaymentDetailsModifier, with minimally required fields. */
public static final class PaymentDetailsModifier { public static final class PaymentDetailsModifier {
public final PaymentItem total; public final @Nullable PaymentItem total;
public final PaymentMethodData methodData; public final PaymentMethodData methodData;
public PaymentDetailsModifier(PaymentItem total, PaymentMethodData methodData) { public PaymentDetailsModifier(@Nullable PaymentItem total, PaymentMethodData methodData) {
this.total = total; this.total = total;
this.methodData = methodData; this.methodData = methodData;
} }

@ -7,8 +7,9 @@ package org.chromium.components.payments.intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import org.chromium.build.annotations.Contract;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.payments.mojom.AddressErrors; import org.chromium.payments.mojom.AddressErrors;
import org.chromium.payments.mojom.PaymentCurrencyAmount; import org.chromium.payments.mojom.PaymentCurrencyAmount;
import org.chromium.payments.mojom.PaymentDetailsModifier; import org.chromium.payments.mojom.PaymentDetailsModifier;
@ -29,34 +30,36 @@ import java.util.Map;
* This class defines the utility functions that convert the payment info types in * This class defines the utility functions that convert the payment info types in
* org.chromium.payments.mojom to their counterparts in WebPaymentIntentHelperType. * org.chromium.payments.mojom to their counterparts in WebPaymentIntentHelperType.
*/ */
@NullMarked
public final class WebPaymentIntentHelperTypeConverter { public final class WebPaymentIntentHelperTypeConverter {
@Nullable
public static WebPaymentIntentHelperType.PaymentCurrencyAmount fromMojoPaymentCurrencyAmount( @Contract("!null -> !null")
@Nullable PaymentCurrencyAmount currencyAmount) { public static WebPaymentIntentHelperType.@Nullable PaymentCurrencyAmount
fromMojoPaymentCurrencyAmount(@Nullable PaymentCurrencyAmount currencyAmount) {
if (currencyAmount == null) return null; if (currencyAmount == null) return null;
return new WebPaymentIntentHelperType.PaymentCurrencyAmount( return new WebPaymentIntentHelperType.PaymentCurrencyAmount(
/* currency= */ currencyAmount.currency, /* value= */ currencyAmount.value); /* currency= */ currencyAmount.currency, /* value= */ currencyAmount.value);
} }
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentItem fromMojoPaymentItem( public static WebPaymentIntentHelperType.@Nullable PaymentItem fromMojoPaymentItem(
@Nullable PaymentItem item) { @Nullable PaymentItem item) {
if (item == null) return null; if (item == null) return null;
return new WebPaymentIntentHelperType.PaymentItem( return new WebPaymentIntentHelperType.PaymentItem(
fromMojoPaymentCurrencyAmount(item.amount)); fromMojoPaymentCurrencyAmount(item.amount));
} }
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentDetailsModifier fromMojoPaymentDetailsModifier( public static WebPaymentIntentHelperType.@Nullable PaymentDetailsModifier
@Nullable PaymentDetailsModifier detailsModifier) { fromMojoPaymentDetailsModifier(@Nullable PaymentDetailsModifier detailsModifier) {
if (detailsModifier == null) return null; if (detailsModifier == null) return null;
return new WebPaymentIntentHelperType.PaymentDetailsModifier( return new WebPaymentIntentHelperType.PaymentDetailsModifier(
fromMojoPaymentItem(detailsModifier.total), fromMojoPaymentItem(detailsModifier.total),
fromMojoPaymentMethodData(detailsModifier.methodData)); fromMojoPaymentMethodData(detailsModifier.methodData));
} }
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentMethodData fromMojoPaymentMethodData( public static WebPaymentIntentHelperType.@Nullable PaymentMethodData fromMojoPaymentMethodData(
@Nullable PaymentMethodData methodData) { @Nullable PaymentMethodData methodData) {
if (methodData == null) return null; if (methodData == null) return null;
return new WebPaymentIntentHelperType.PaymentMethodData( return new WebPaymentIntentHelperType.PaymentMethodData(
@ -64,9 +67,10 @@ public final class WebPaymentIntentHelperTypeConverter {
/* stringifiedData= */ methodData.stringifiedData); /* stringifiedData= */ methodData.stringifiedData);
} }
@Nullable @Contract("!null -> !null")
public static Map<String, WebPaymentIntentHelperType.PaymentMethodData> public static @Nullable
fromMojoPaymentMethodDataMap(@Nullable Map<String, PaymentMethodData> methodDataMap) { Map<String, WebPaymentIntentHelperType.PaymentMethodData> fromMojoPaymentMethodDataMap(
@Nullable Map<String, PaymentMethodData> methodDataMap) {
if (methodDataMap == null) return null; if (methodDataMap == null) return null;
Map<String, WebPaymentIntentHelperType.PaymentMethodData> compatibleMethodDataMap = Map<String, WebPaymentIntentHelperType.PaymentMethodData> compatibleMethodDataMap =
new HashMap<>(); new HashMap<>();
@ -79,10 +83,11 @@ public final class WebPaymentIntentHelperTypeConverter {
return compatibleMethodDataMap; return compatibleMethodDataMap;
} }
@Nullable @Contract("!null -> !null")
public static Map<String, WebPaymentIntentHelperType.PaymentDetailsModifier> public static @Nullable
fromMojoPaymentDetailsModifierMap( Map<String, WebPaymentIntentHelperType.PaymentDetailsModifier>
@Nullable Map<String, PaymentDetailsModifier> modifiers) { fromMojoPaymentDetailsModifierMap(
@Nullable Map<String, PaymentDetailsModifier> modifiers) {
if (modifiers == null) return null; if (modifiers == null) return null;
Map<String, WebPaymentIntentHelperType.PaymentDetailsModifier> compatibleModifiers = Map<String, WebPaymentIntentHelperType.PaymentDetailsModifier> compatibleModifiers =
new HashMap<>(); new HashMap<>();
@ -95,8 +100,8 @@ public final class WebPaymentIntentHelperTypeConverter {
return compatibleModifiers; return compatibleModifiers;
} }
@Nullable @Contract("!null -> !null")
public static List<WebPaymentIntentHelperType.PaymentItem> fromMojoPaymentItems( public static @Nullable List<WebPaymentIntentHelperType.PaymentItem> fromMojoPaymentItems(
@Nullable List<PaymentItem> paymentItems) { @Nullable List<PaymentItem> paymentItems) {
if (paymentItems == null) return null; if (paymentItems == null) return null;
List<WebPaymentIntentHelperType.PaymentItem> compatiblePaymentItems = new ArrayList<>(); List<WebPaymentIntentHelperType.PaymentItem> compatiblePaymentItems = new ArrayList<>();
@ -107,9 +112,9 @@ public final class WebPaymentIntentHelperTypeConverter {
return compatiblePaymentItems; return compatiblePaymentItems;
} }
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentShippingOption fromMojoPaymentShippingOption( public static WebPaymentIntentHelperType.@Nullable PaymentShippingOption
@Nullable PaymentShippingOption shippingOption) { fromMojoPaymentShippingOption(@Nullable PaymentShippingOption shippingOption) {
if (shippingOption == null) return null; if (shippingOption == null) return null;
return new WebPaymentIntentHelperType.PaymentShippingOption( return new WebPaymentIntentHelperType.PaymentShippingOption(
shippingOption.id, shippingOption.id,
@ -118,9 +123,10 @@ public final class WebPaymentIntentHelperTypeConverter {
shippingOption.selected); shippingOption.selected);
} }
@Nullable @Contract("!null -> !null")
public static List<WebPaymentIntentHelperType.PaymentShippingOption> fromMojoShippingOptionList( public static @Nullable
@Nullable List<PaymentShippingOption> shippingOptions) { List<WebPaymentIntentHelperType.PaymentShippingOption> fromMojoShippingOptionList(
@Nullable List<PaymentShippingOption> shippingOptions) {
if (shippingOptions == null) return null; if (shippingOptions == null) return null;
List<WebPaymentIntentHelperType.PaymentShippingOption> shippingOptionList = List<WebPaymentIntentHelperType.PaymentShippingOption> shippingOptionList =
new ArrayList<>(); new ArrayList<>();
@ -131,8 +137,8 @@ public final class WebPaymentIntentHelperTypeConverter {
return shippingOptionList; return shippingOptionList;
} }
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentOptions fromMojoPaymentOptions( public static WebPaymentIntentHelperType.@Nullable PaymentOptions fromMojoPaymentOptions(
@Nullable PaymentOptions paymentOptions) { @Nullable PaymentOptions paymentOptions) {
if (paymentOptions == null) return null; if (paymentOptions == null) return null;
String shippingType = null; String shippingType = null;
@ -157,8 +163,9 @@ public final class WebPaymentIntentHelperTypeConverter {
shippingType); shippingType);
} }
@Nullable @Contract("!null -> !null")
private static Bundle fromMojoShippingAddressErrors(@Nullable AddressErrors addressErrors) { private static @Nullable Bundle fromMojoShippingAddressErrors(
@Nullable AddressErrors addressErrors) {
if (addressErrors == null) return null; if (addressErrors == null) return null;
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
putIfNonEmpty("addressLine", addressErrors.addressLine, bundle); putIfNonEmpty("addressLine", addressErrors.addressLine, bundle);
@ -184,8 +191,8 @@ public final class WebPaymentIntentHelperTypeConverter {
* @param update The mojo PaymentRequestDetailsUpdate to be converted. * @param update The mojo PaymentRequestDetailsUpdate to be converted.
* @return The converted update. * @return The converted update.
*/ */
@Nullable @Contract("!null -> !null")
public static WebPaymentIntentHelperType.PaymentRequestDetailsUpdate public static WebPaymentIntentHelperType.@Nullable PaymentRequestDetailsUpdate
fromMojoPaymentRequestDetailsUpdate(@Nullable PaymentRequestDetailsUpdate update) { fromMojoPaymentRequestDetailsUpdate(@Nullable PaymentRequestDetailsUpdate update) {
if (update == null) return null; if (update == null) return null;
return new WebPaymentIntentHelperType.PaymentRequestDetailsUpdate( return new WebPaymentIntentHelperType.PaymentRequestDetailsUpdate(

@ -4,18 +4,21 @@
package org.chromium.components.payments.secure_payment_confirmation; package org.chromium.components.payments.secure_payment_confirmation;
import static org.chromium.build.NullUtil.assertNonNull;
import static org.chromium.build.NullUtil.assumeNonNull;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.Pair; import android.util.Pair;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.ResourcesCompat; import androidx.core.content.res.ResourcesCompat;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
@ -41,12 +44,16 @@ import java.util.Locale;
* component from other components and acts as the point of contact between them. Any code in this * component from other components and acts as the point of contact between them. Any code in this
* component that needs to interact with another component does that through this controller. * component that needs to interact with another component does that through this controller.
*/ */
@NullMarked
public class SecurePaymentConfirmationAuthnController { public class SecurePaymentConfirmationAuthnController {
private final WebContents mWebContents; private final WebContents mWebContents;
private Runnable mHider; private @Nullable Runnable mHider;
private Callback<Boolean> mResponseCallback;
private Runnable mOptOutCallback; private @Nullable Callback<Boolean> mResponseCallback;
private SecurePaymentConfirmationAuthnView mView;
private @Nullable Runnable mOptOutCallback;
private @Nullable SecurePaymentConfirmationAuthnView mView;
private InputProtector mInputProtector = new InputProtector(); private InputProtector mInputProtector = new InputProtector();
@ -66,11 +73,12 @@ public class SecurePaymentConfirmationAuthnController {
new BottomSheetContent() { new BottomSheetContent() {
@Override @Override
public View getContentView() { public View getContentView() {
assumeNonNull(mView);
return mView.getContentView(); return mView.getContentView();
} }
@Override @Override
public View getToolbarView() { public @Nullable View getToolbarView() {
return null; return null;
} }
@ -112,7 +120,7 @@ public class SecurePaymentConfirmationAuthnController {
} }
@Override @Override
public @NonNull String getSheetContentDescription(Context context) { public String getSheetContentDescription(Context context) {
return context.getString( return context.getString(
R.string.secure_payment_confirmation_authentication_sheet_description); R.string.secure_payment_confirmation_authentication_sheet_description);
} }
@ -139,7 +147,8 @@ public class SecurePaymentConfirmationAuthnController {
* *
* @param webContents The WebContents of the merchant. * @param webContents The WebContents of the merchant.
*/ */
public static SecurePaymentConfirmationAuthnController create(WebContents webContents) { public static @Nullable SecurePaymentConfirmationAuthnController create(
WebContents webContents) {
return webContents != null return webContents != null
? new SecurePaymentConfirmationAuthnController(webContents) ? new SecurePaymentConfirmationAuthnController(webContents)
: null; : null;
@ -263,7 +272,7 @@ public class SecurePaymentConfirmationAuthnController {
} }
@VisibleForTesting(otherwise = VisibleForTesting.NONE) @VisibleForTesting(otherwise = VisibleForTesting.NONE)
public SecurePaymentConfirmationAuthnView getView() { public @Nullable SecurePaymentConfirmationAuthnView getView() {
return mView; return mView;
} }
@ -272,12 +281,13 @@ public class SecurePaymentConfirmationAuthnController {
return mHider == null; return mHider == null;
} }
private String getStoreLabel(@Nullable String payeeName, @Nullable Origin payeeOrigin) { private String getStoreLabel(
@Nullable String payeeName, @Nullable Origin payeeOrigin) {
// At least one of the payeeName and payeeOrigin must be non-null in SPC; this should be // At least one of the payeeName and payeeOrigin must be non-null in SPC; this should be
// enforced by PaymentRequestService.isValidSecurePaymentConfirmationRequest. // enforced by PaymentRequestService.isValidSecurePaymentConfirmationRequest.
assert payeeName != null || payeeOrigin != null; assert payeeName != null || payeeOrigin != null;
if (payeeOrigin == null) return payeeName; if (payeeOrigin == null) return assertNonNull(payeeName);
String origin = String origin =
UrlFormatter.formatOriginForSecurityDisplay( UrlFormatter.formatOriginForSecurityDisplay(
@ -295,6 +305,7 @@ public class SecurePaymentConfirmationAuthnController {
private void onConfirm() { private void onConfirm() {
hide(); hide();
assumeNonNull(mResponseCallback);
mResponseCallback.onResult(true); mResponseCallback.onResult(true);
} }
@ -304,6 +315,7 @@ public class SecurePaymentConfirmationAuthnController {
private void onCancel() { private void onCancel() {
hide(); hide();
assumeNonNull(mResponseCallback);
mResponseCallback.onResult(false); mResponseCallback.onResult(false);
} }

@ -7,6 +7,7 @@ package org.chromium.components.payments.secure_payment_confirmation;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.Pair; import android.util.Pair;
import org.chromium.build.annotations.NullMarked;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey; import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
@ -14,6 +15,7 @@ import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
* The properties of the SecurePaymentConfirmation Authn UI, which fully describe the state of the * The properties of the SecurePaymentConfirmation Authn UI, which fully describe the state of the
* UI. * UI.
*/ */
@NullMarked
/* package */ class SecurePaymentConfirmationAuthnProperties { /* package */ class SecurePaymentConfirmationAuthnProperties {
/** The store value of the UI. */ /** The store value of the UI. */
/* package */ static final ReadableObjectPropertyKey<String> STORE_LABEL = /* package */ static final ReadableObjectPropertyKey<String> STORE_LABEL =

@ -14,6 +14,7 @@ import android.widget.RelativeLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import org.chromium.build.annotations.NullMarked;
import org.chromium.components.payments.R; import org.chromium.components.payments.R;
import org.chromium.ui.widget.TextViewWithClickableSpans; import org.chromium.ui.widget.TextViewWithClickableSpans;
@ -22,6 +23,7 @@ import org.chromium.ui.widget.TextViewWithClickableSpans;
* state. It has a fixed height, which is the height of the visible content area. It shows the * state. It has a fixed height, which is the height of the visible content area. It shows the
* payment details and provides the option to continue with the payment or to cancel. * payment details and provides the option to continue with the payment or to cancel.
*/ */
@NullMarked
/* package */ class SecurePaymentConfirmationAuthnView { /* package */ class SecurePaymentConfirmationAuthnView {
/** /**
* Bundles the information necessary to show the opt out UX, if requested by the caller. * Bundles the information necessary to show the opt out UX, if requested by the caller.

@ -11,6 +11,7 @@ import android.util.Pair;
import android.view.View; import android.view.View;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import org.chromium.build.annotations.NullMarked;
import org.chromium.components.payments.R; import org.chromium.components.payments.R;
import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
@ -23,6 +24,7 @@ import org.chromium.ui.text.SpanApplier.SpanInfo;
* The view binder of the SecurePaymentConfirmation Authn UI, which is stateless. It is called to * The view binder of the SecurePaymentConfirmation Authn UI, which is stateless. It is called to
* bind a given model to a given view. Should contain as little business logic as possible. * bind a given model to a given view. Should contain as little business logic as possible.
*/ */
@NullMarked
/* package */ class SecurePaymentConfirmationAuthnViewBinder { /* package */ class SecurePaymentConfirmationAuthnViewBinder {
/* package */ static void bind( /* package */ static void bind(
PropertyModel model, SecurePaymentConfirmationAuthnView view, PropertyKey propertyKey) { PropertyModel model, SecurePaymentConfirmationAuthnView view, PropertyKey propertyKey) {

@ -3,12 +3,15 @@
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.components.payments.secure_payment_confirmation; package org.chromium.components.payments.secure_payment_confirmation;
import static org.chromium.build.NullUtil.assumeNonNull;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
@ -28,12 +31,13 @@ import org.chromium.ui.base.WindowAndroid;
* between them. Any code in this component that needs to interact with another component does that * between them. Any code in this component that needs to interact with another component does that
* through this controller. * through this controller.
*/ */
@NullMarked
public class SecurePaymentConfirmationNoMatchingCredController { public class SecurePaymentConfirmationNoMatchingCredController {
private final WebContents mWebContents; private final WebContents mWebContents;
private Runnable mHider; private @Nullable Runnable mHider;
private Runnable mResponseCallback; private @Nullable Runnable mResponseCallback;
private Runnable mOptOutCallback; private @Nullable Runnable mOptOutCallback;
private SecurePaymentConfirmationNoMatchingCredView mView; private @Nullable SecurePaymentConfirmationNoMatchingCredView mView;
private InputProtector mInputProtector = new InputProtector(); private InputProtector mInputProtector = new InputProtector();
@ -53,11 +57,12 @@ public class SecurePaymentConfirmationNoMatchingCredController {
new BottomSheetContent() { new BottomSheetContent() {
@Override @Override
public View getContentView() { public View getContentView() {
assumeNonNull(mView);
return mView.getContentView(); return mView.getContentView();
} }
@Override @Override
public View getToolbarView() { public @Nullable View getToolbarView() {
return null; return null;
} }
@ -99,7 +104,7 @@ public class SecurePaymentConfirmationNoMatchingCredController {
} }
@Override @Override
public @NonNull String getSheetContentDescription(Context context) { public String getSheetContentDescription(Context context) {
return context.getString( return context.getString(
R.string R.string
.secure_payment_confirmation_no_matching_credential_sheet_description); .secure_payment_confirmation_no_matching_credential_sheet_description);
@ -127,7 +132,7 @@ public class SecurePaymentConfirmationNoMatchingCredController {
* *
* @param webContents The WebContents of the merchant. * @param webContents The WebContents of the merchant.
*/ */
public static SecurePaymentConfirmationNoMatchingCredController create( public static @Nullable SecurePaymentConfirmationNoMatchingCredController create(
WebContents webContents) { WebContents webContents) {
return webContents != null return webContents != null
? new SecurePaymentConfirmationNoMatchingCredController(webContents) ? new SecurePaymentConfirmationNoMatchingCredController(webContents)
@ -223,7 +228,7 @@ public class SecurePaymentConfirmationNoMatchingCredController {
} }
@VisibleForTesting(otherwise = VisibleForTesting.NONE) @VisibleForTesting(otherwise = VisibleForTesting.NONE)
public SecurePaymentConfirmationNoMatchingCredView getView() { public @Nullable SecurePaymentConfirmationNoMatchingCredView getView() {
return mView; return mView;
} }

@ -15,6 +15,7 @@ import android.widget.RelativeLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import org.chromium.build.annotations.NullMarked;
import org.chromium.components.payments.R; import org.chromium.components.payments.R;
import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.text.ChromeClickableSpan; import org.chromium.ui.text.ChromeClickableSpan;
@ -27,6 +28,7 @@ import org.chromium.ui.widget.TextViewWithClickableSpans;
* peeked or half-open state. It has a fixed height, which is the height of the visible content * peeked or half-open state. It has a fixed height, which is the height of the visible content
* area. It informs the user that additional steps are needed to verify the payment. * area. It informs the user that additional steps are needed to verify the payment.
*/ */
@NullMarked
public class SecurePaymentConfirmationNoMatchingCredView { public class SecurePaymentConfirmationNoMatchingCredView {
private final RelativeLayout mContentView; private final RelativeLayout mContentView;
private final ScrollView mScrollView; private final ScrollView mScrollView;

@ -287,7 +287,7 @@ public class GURL {
} }
@Override @Override
public final boolean equals(Object other) { public final boolean equals(@Nullable Object other) {
if (other == this) return true; if (other == this) return true;
if (!(other instanceof GURL)) return false; if (!(other instanceof GURL)) return false;
return mSpec.equals(((GURL) other).mSpec); return mSpec.equals(((GURL) other).mSpec);