blob: e414d7a252bf774fb43185a7e9d12a0e6f97e75a [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.payments;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import androidx.annotation.Nullable;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.payments.mojom.PaymentDetailsModifier;
import org.chromium.payments.mojom.PaymentItem;
import org.chromium.payments.mojom.PaymentMethodData;
import org.chromium.payments.mojom.PaymentOptions;
import org.chromium.payments.mojom.PaymentRequestDetailsUpdate;
import org.chromium.payments.mojom.PaymentResponse;
import org.chromium.payments.mojom.PaymentShippingOption;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Wrapper around a C++ payment app. */
@JNINamespace("payments")
public class JniPaymentApp extends PaymentApp {
private final Handler mHandler = new Handler();
private final @PaymentAppType int mPaymentAppType;
// The Java object owns the C++ payment app and frees it in dismissInstrument().
private long mNativeObject;
private AbortCallback mAbortCallback;
private InstrumentDetailsCallback mInvokeCallback;
@CalledByNative
private JniPaymentApp(String id, String label, String sublabel, Bitmap icon,
@PaymentAppType int paymentAppType, long nativeObject) {
super(id, label, sublabel, new BitmapDrawable(icon));
mPaymentAppType = paymentAppType;
mNativeObject = nativeObject;
}
@CalledByNative
public void onAbortResult(boolean aborted) {
mHandler.post(() -> {
if (mAbortCallback == null) return;
mAbortCallback.onInstrumentAbortResult(aborted);
mAbortCallback = null;
});
}
@CalledByNative
public void onInvokeResult(String methodName, String stringifiedDetails, PayerData payerData) {
mHandler.post(() -> {
if (mInvokeCallback == null) return;
mInvokeCallback.onInstrumentDetailsReady(methodName, stringifiedDetails, payerData);
mInvokeCallback = null;
});
}
@CalledByNative
public void onInvokeError(String errorMessage) {
mHandler.post(() -> {
if (mInvokeCallback == null) return;
mInvokeCallback.onInstrumentDetailsError(errorMessage);
mInvokeCallback = null;
});
}
@CalledByNative
private static PayerData createPayerData(String payerName, String payerPhone, String payerEmail,
Address shippingAddress, String selectedShippingOptionId) {
return new PayerData(
payerName, payerPhone, payerEmail, shippingAddress, selectedShippingOptionId);
}
@CalledByNative
private static Address createShippingAddress(String country, String[] addressLine,
String region, String city, String dependentLocality, String postalCode,
String sortingCode, String organization, String recipient, String phone) {
return new Address(country, addressLine, region, city, dependentLocality, postalCode,
sortingCode, organization, recipient, phone);
}
@Override
public Set<String> getInstrumentMethodNames() {
return new HashSet<>(
Arrays.asList(JniPaymentAppJni.get().getInstrumentMethodNames(mNativeObject)));
}
@Override
public boolean isValidForPaymentMethodData(String method, @Nullable PaymentMethodData data) {
return JniPaymentAppJni.get().isValidForPaymentMethodData(
mNativeObject, method, data != null ? data.serialize() : null);
}
@Override
public boolean handlesShippingAddress() {
return JniPaymentAppJni.get().handlesShippingAddress(mNativeObject);
}
@Override
public boolean handlesPayerName() {
return JniPaymentAppJni.get().handlesPayerName(mNativeObject);
}
@Override
public boolean handlesPayerEmail() {
return JniPaymentAppJni.get().handlesPayerEmail(mNativeObject);
}
@Override
public boolean handlesPayerPhone() {
return JniPaymentAppJni.get().handlesPayerPhone(mNativeObject);
}
@Override
@Nullable
public String getCountryCode() {
return JniPaymentAppJni.get().getCountryCode(mNativeObject);
}
@Override
public boolean canMakePayment() {
return JniPaymentAppJni.get().canMakePayment(mNativeObject);
}
@Override
public boolean canPreselect() {
return JniPaymentAppJni.get().canPreselect(mNativeObject);
}
@Override
public void invokePaymentApp(String id, String merchantName, String origin, String iframeOrigin,
@Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap,
PaymentItem total, List<PaymentItem> displayItems,
Map<String, PaymentDetailsModifier> modifiers, PaymentOptions paymentOptions,
List<PaymentShippingOption> shippingOptions, InstrumentDetailsCallback callback) {
mInvokeCallback = callback;
JniPaymentAppJni.get().invokePaymentApp(mNativeObject, /*callback=*/this);
}
@Override
public void updateWith(PaymentRequestDetailsUpdate response) {
JniPaymentAppJni.get().updateWith(mNativeObject, response.serialize());
}
@Override
public void onPaymentDetailsNotUpdated() {
JniPaymentAppJni.get().onPaymentDetailsNotUpdated(mNativeObject);
}
@Override
public boolean isWaitingForPaymentDetailsUpdate() {
return JniPaymentAppJni.get().isWaitingForPaymentDetailsUpdate(mNativeObject);
}
@Override
public void abortPaymentApp(AbortCallback callback) {
mAbortCallback = callback;
JniPaymentAppJni.get().abortPaymentApp(mNativeObject, this);
}
@Override
@Nullable
public String getApplicationIdentifierToHide() {
return JniPaymentAppJni.get().getApplicationIdentifierToHide(mNativeObject);
}
@Override
@Nullable
public Set<String> getApplicationIdentifiersThatHideThisApp() {
return new HashSet<>(Arrays.asList(
JniPaymentAppJni.get().getApplicationIdentifiersThatHideThisApp(mNativeObject)));
}
@Override
public long getUkmSourceId() {
return JniPaymentAppJni.get().getUkmSourceId(mNativeObject);
}
@Override
public void setPaymentHandlerHost(PaymentHandlerHost host) {
JniPaymentAppJni.get().setPaymentHandlerHost(mNativeObject, host);
}
@Override
public void dismissInstrument() {
if (mNativeObject == 0) return;
JniPaymentAppJni.get().freeNativeObject(mNativeObject);
mNativeObject = 0;
}
@Override
public void finalize() throws Throwable {
dismissInstrument();
super.finalize();
}
@Override
public @PaymentAppType int getPaymentAppType() {
return mPaymentAppType;
}
@Override
public PaymentResponse setAppSpecificResponseFields(PaymentResponse response) {
byte[] byteResult = JniPaymentAppJni.get().setAppSpecificResponseFields(
mNativeObject, response.serialize());
return PaymentResponse.deserialize(ByteBuffer.wrap(byteResult));
}
@NativeMethods
interface Natives {
String[] getInstrumentMethodNames(long nativeJniPaymentApp);
boolean isValidForPaymentMethodData(
long nativeJniPaymentApp, String method, ByteBuffer dataByteBuffer);
boolean handlesShippingAddress(long nativeJniPaymentApp);
boolean handlesPayerName(long nativeJniPaymentApp);
boolean handlesPayerEmail(long nativeJniPaymentApp);
boolean handlesPayerPhone(long nativeJniPaymentApp);
String getCountryCode(long nativeJniPaymentApp);
boolean canMakePayment(long nativeJniPaymentApp);
boolean canPreselect(long nativeJniPaymentApp);
void invokePaymentApp(long nativeJniPaymentApp, JniPaymentApp callback);
void updateWith(long nativeJniPaymentApp, ByteBuffer responseByteBuffer);
void onPaymentDetailsNotUpdated(long nativeJniPaymentApp);
boolean isWaitingForPaymentDetailsUpdate(long nativeJniPaymentApp);
void abortPaymentApp(long nativeJniPaymentApp, JniPaymentApp callback);
String getApplicationIdentifierToHide(long nativeJniPaymentApp);
String[] getApplicationIdentifiersThatHideThisApp(long nativeJniPaymentApp);
long getUkmSourceId(long nativeJniPaymentApp);
void setPaymentHandlerHost(long nativeJniPaymentApp, PaymentHandlerHost paymentHandlerHost);
void freeNativeObject(long nativeJniPaymentApp);
byte[] setAppSpecificResponseFields(long nativeJniPaymentApp, ByteBuffer paymentResponse);
}
}