| Index: chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b38562ee18c5fa57a002ceaea4541428cf694c5c
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
|
| @@ -0,0 +1,250 @@
|
| +// Copyright 2016 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.chrome.browser.payments;
|
| +
|
| +import android.app.Activity;
|
| +import android.content.ComponentName;
|
| +import android.content.ContentResolver;
|
| +import android.content.Context;
|
| +import android.content.Intent;
|
| +import android.content.ServiceConnection;
|
| +import android.graphics.drawable.Drawable;
|
| +import android.os.Bundle;
|
| +import android.os.Handler;
|
| +import android.os.IBinder;
|
| +import android.os.RemoteException;
|
| +import android.util.JsonWriter;
|
| +
|
| +import org.json.JSONObject;
|
| +
|
| +import org.chromium.IsReadyToPayService;
|
| +import org.chromium.chrome.R;
|
| +import org.chromium.payments.mojom.PaymentItem;
|
| +import org.chromium.ui.base.WindowAndroid;
|
| +
|
| +import java.io.IOException;
|
| +import java.io.StringWriter;
|
| +import java.util.ArrayList;
|
| +import java.util.HashSet;
|
| +import java.util.List;
|
| +import java.util.Map;
|
| +import java.util.Set;
|
| +
|
| +/** A locally installed payment app. */
|
| +public class AndroidPaymentApp extends PaymentInstrument implements PaymentApp,
|
| + WindowAndroid.IntentCallback {
|
| + private static final String DATA_EXTRA = "data";
|
| + private static final String DETAILS_EXTRA = "details";
|
| + private static final String EMPTY_JSON_DATA = "{}";
|
| + private static final String METHOD_NAME_EXTRA = "methodName";
|
| + private static final String INSTRUMENT_DETAILS_EXTRA = "instrumentDetails";
|
| + private static final String ORIGIN_EXTRA = "origin";
|
| + private static final String READY_TO_PAY = "readyToPay";
|
| +
|
| + private final Handler mHandler;
|
| + private final WindowAndroid mWindow;
|
| + private final Intent mIsReadyToPayIntent;
|
| + private final Intent mPayIntent;
|
| + private final Set<String> mMethodNames;
|
| + private IsReadyToPayService mIsReadyToPayService;
|
| + private InstrumentsCallback mInstrumentsCallback;
|
| + private InstrumentDetailsCallback mInstrumentDetailsCallback;
|
| +
|
| + public AndroidPaymentApp(WindowAndroid window, String packageName, String activity,
|
| + String label, Drawable icon) {
|
| + super(packageName, label, null, icon);
|
| + mHandler = new Handler();
|
| + mWindow = window;
|
| + mIsReadyToPayIntent = new Intent();
|
| + mIsReadyToPayIntent.setPackage(packageName);
|
| + mPayIntent = new Intent();
|
| + mPayIntent.setClassName(packageName, activity);
|
| + mMethodNames = new HashSet<>();
|
| + }
|
| +
|
| + public void addMethodName(String methodName) {
|
| + mMethodNames.add(methodName);
|
| + }
|
| +
|
| + public void setIsReadyToPayAction(String className) {
|
| + mIsReadyToPayIntent.setClassName(mIsReadyToPayIntent.getPackage(), className);
|
| + }
|
| +
|
| + @Override
|
| + public void getInstruments(
|
| + final Map<String, JSONObject> methodData, final String origin,
|
| + final InstrumentsCallback callback) {
|
| + mInstrumentsCallback = callback;
|
| + mHandler.post(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + if (mIsReadyToPayIntent.getComponent() != null) {
|
| + isReadyToPay(origin, methodData.get(getInstrumentMethodName()));
|
| + } else {
|
| + sendInstrumentsReady(AndroidPaymentApp.this);
|
| + }
|
| + }
|
| + });
|
| + }
|
| +
|
| + private void sendInstrumentsReady(PaymentInstrument instrument) {
|
| + assert mInstrumentsCallback != null;
|
| + List<PaymentInstrument> instruments = new ArrayList<>();
|
| + instruments.add(instrument);
|
| + mInstrumentsCallback.onInstrumentsReady(AndroidPaymentApp.this, instruments);
|
| + }
|
| +
|
| + private void isReadyToPay(String origin, JSONObject data) {
|
| + Bundle extras = new Bundle();
|
| + extras.putString(METHOD_NAME_EXTRA, getInstrumentMethodName());
|
| + extras.putString(ORIGIN_EXTRA, origin);
|
| + extras.putString(DATA_EXTRA,
|
| + data == null ? EMPTY_JSON_DATA : data.toString());
|
| + mIsReadyToPayIntent.putExtras(extras);
|
| +
|
| + if (mIsReadyToPayService != null) {
|
| + sendIsReadyToPay();
|
| + } else {
|
| + try {
|
| + mWindow.getApplicationContext().bindService(
|
| + mIsReadyToPayIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
|
| + } catch (SecurityException e) {
|
| + sendInstrumentsReady(null);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private final ServiceConnection mServiceConnection = new ServiceConnection() {
|
| + @Override
|
| + public void onServiceConnected(ComponentName name, IBinder service) {
|
| + mIsReadyToPayService = IsReadyToPayService.Stub.asInterface(service);
|
| + if (mIsReadyToPayService == null) {
|
| + sendInstrumentsReady(null);
|
| + } else {
|
| + sendIsReadyToPay();
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void onServiceDisconnected(ComponentName name) {
|
| + sendInstrumentsReady(null);
|
| + }
|
| + };
|
| + private void sendIsReadyToPay() {
|
| + assert mIsReadyToPayService != null;
|
| + try {
|
| + if (mIsReadyToPayService.isReadyToPay()) {
|
| + sendInstrumentsReady(AndroidPaymentApp.this);
|
| + return;
|
| + }
|
| + } catch (RemoteException e) {
|
| + }
|
| + mInstrumentsCallback.onInstrumentsReady(AndroidPaymentApp.this, null);
|
| + }
|
| +
|
| + @Override
|
| + public String getAppIdentifier() {
|
| + return getIdentifier();
|
| + }
|
| +
|
| + @Override
|
| + public Set<String> getAppMethodNames() {
|
| + return mMethodNames;
|
| + }
|
| +
|
| + @Override
|
| + public String getInstrumentMethodName() {
|
| + assert !mMethodNames.isEmpty();
|
| + return mMethodNames.iterator().next();
|
| + }
|
| +
|
| + @Override
|
| + public void getInstrumentDetails(String merchantName, String origin, PaymentItem total,
|
| + List<PaymentItem> cart, JSONObject data, InstrumentDetailsCallback callback) {
|
| + assert !mMethodNames.isEmpty();
|
| +
|
| + Bundle extras = new Bundle();
|
| + extras.putString(METHOD_NAME_EXTRA, mMethodNames.iterator().next());
|
| + extras.putString(DATA_EXTRA, data == null ? EMPTY_JSON_DATA : data.toString());
|
| + extras.putString(ORIGIN_EXTRA, origin);
|
| + String details = serializeDetails(total, cart);
|
| + extras.putString(DETAILS_EXTRA, details == null ? EMPTY_JSON_DATA : details);
|
| + mPayIntent.putExtras(extras);
|
| +
|
| + mInstrumentDetailsCallback = callback;
|
| + if (!mWindow.showIntent(mPayIntent, this, R.string.payments_android_app_error)) {
|
| + mHandler.post(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mInstrumentDetailsCallback.onInstrumentDetailsError();
|
| + }
|
| + });
|
| + }
|
| + }
|
| +
|
| + private static String serializeDetails(PaymentItem total, List<PaymentItem> cart) {
|
| + StringWriter stringWriter = new StringWriter();
|
| + JsonWriter json = new JsonWriter(stringWriter);
|
| + try {
|
| + // details {{{
|
| + json.beginObject();
|
| +
|
| + // total {{{
|
| + json.name("total");
|
| + serializePaymentItem(json, total);
|
| + // }}} total
|
| +
|
| + // displayitems {{{
|
| + if (cart != null) {
|
| + json.name("displayItems").beginArray();
|
| + for (int i = 0; i < cart.size(); i++) {
|
| + serializePaymentItem(json, cart.get(i));
|
| + }
|
| + json.endArray();
|
| + }
|
| + // }}} displayItems
|
| +
|
| + json.endObject();
|
| + // }}} details
|
| + } catch (IOException e) {
|
| + return null;
|
| + }
|
| +
|
| + return stringWriter.toString();
|
| + }
|
| +
|
| + private static void serializePaymentItem(JsonWriter json, PaymentItem item) throws IOException {
|
| + // item {{{
|
| + json.beginObject();
|
| + json.name("label").value(item.label);
|
| +
|
| + // amount {{{
|
| + json.name("amount").beginObject();
|
| + json.name("currency").value(item.amount.currency);
|
| + json.name("value").value(item.amount.value);
|
| + json.endObject();
|
| + // }}} amount
|
| +
|
| + json.endObject();
|
| + // }}} item
|
| + }
|
| +
|
| + @Override
|
| + public void onIntentCompleted(
|
| + WindowAndroid window, int resultCode, ContentResolver contentResolver, Intent data) {
|
| + mWindow.removeIntentCallback(this);
|
| + if (data == null || data.getExtras() == null || resultCode != Activity.RESULT_OK) {
|
| + mInstrumentDetailsCallback.onInstrumentDetailsError();
|
| + } else {
|
| + mInstrumentDetailsCallback.onInstrumentDetailsReady(
|
| + data.getExtras().getString(METHOD_NAME_EXTRA),
|
| + data.getExtras().getString(INSTRUMENT_DETAILS_EXTRA));
|
| + }
|
| + mInstrumentDetailsCallback = null;
|
| + }
|
| +
|
| + @Override
|
| + public void dismissInstrument() {}
|
| +}
|
|
|