Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java

Issue 2507223002: Implement IsReadyToPay handling (Closed)
Patch Set: Use aidl Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.payments; 5 package org.chromium.chrome.browser.payments;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.graphics.Bitmap; 8 import android.graphics.Bitmap;
9 import android.os.Handler; 9 import android.os.Handler;
10 import android.text.TextUtils; 10 import android.text.TextUtils;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 import java.util.List; 62 import java.util.List;
63 import java.util.Locale; 63 import java.util.Locale;
64 import java.util.Map; 64 import java.util.Map;
65 import java.util.Set; 65 import java.util.Set;
66 66
67 /** 67 /**
68 * Android implementation of the PaymentRequest service defined in 68 * Android implementation of the PaymentRequest service defined in
69 * components/payments/payment_request.mojom. 69 * components/payments/payment_request.mojom.
70 */ 70 */
71 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, 71 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt,
72 PaymentAppFactory.PaymentAppsCallback,
72 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb ack, 73 PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallb ack,
73 PaymentResponseHelper.PaymentResponseRequesterDelegate { 74 PaymentResponseHelper.PaymentResponseRequesterDelegate {
74 /** 75 /**
75 * Observer to be notified when PaymentRequest UI has been dismissed. 76 * Observer to be notified when PaymentRequest UI has been dismissed.
76 */ 77 */
77 public interface PaymentRequestDismissObserver { 78 public interface PaymentRequestDismissObserver {
78 /** 79 /**
79 * Called when PaymentRequest UI has been dismissed. 80 * Called when PaymentRequest UI has been dismissed.
80 */ 81 */
81 void onPaymentRequestDismissed(); 82 void onPaymentRequestDismissed();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 /** Monitors changes in the current TabModel. */ 132 /** Monitors changes in the current TabModel. */
132 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver () { 133 private final TabModelObserver mTabModelObserver = new EmptyTabModelObserver () {
133 @Override 134 @Override
134 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { 135 public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
135 if (tab == null || tab.getId() != lastId) onDismiss(); 136 if (tab == null || tab.getId() != lastId) onDismiss();
136 } 137 }
137 }; 138 };
138 139
139 private final Handler mHandler = new Handler(); 140 private final Handler mHandler = new Handler();
140 private final ChromeActivity mContext; 141 private final ChromeActivity mContext;
142 private final WebContents mWebContents;
141 private final PaymentRequestDismissObserver mDismissObserver; 143 private final PaymentRequestDismissObserver mDismissObserver;
142 private final String mMerchantName; 144 private final String mMerchantName;
143 private final String mOrigin; 145 private final String mOrigin;
144 private final List<PaymentApp> mApps;
145 private final AddressEditor mAddressEditor; 146 private final AddressEditor mAddressEditor;
146 private final CardEditor mCardEditor; 147 private final CardEditor mCardEditor;
147 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques tJourneyLogger(); 148 private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentReques tJourneyLogger();
148 149
149 private Bitmap mFavicon; 150 private Bitmap mFavicon;
150 private PaymentRequestClient mClient; 151 private PaymentRequestClient mClient;
151 152
152 /** 153 /**
153 * The raw total amount being charged, as it was received from the website. This data is passed 154 * The raw total amount being charged, as it was received from the website. This data is passed
154 * to the payment app. 155 * to the payment app.
(...skipping 24 matching lines...) Expand all
179 private List<PaymentApp> mPendingApps; 180 private List<PaymentApp> mPendingApps;
180 private List<PaymentInstrument> mPendingInstruments; 181 private List<PaymentInstrument> mPendingInstruments;
181 private List<PaymentInstrument> mPendingAutofillInstruments; 182 private List<PaymentInstrument> mPendingAutofillInstruments;
182 private SectionInformation mPaymentMethodsSection; 183 private SectionInformation mPaymentMethodsSection;
183 private PaymentRequestUI mUI; 184 private PaymentRequestUI mUI;
184 private Callback<PaymentInformation> mPaymentInformationCallback; 185 private Callback<PaymentInformation> mPaymentInformationCallback;
185 private boolean mPaymentAppRunning; 186 private boolean mPaymentAppRunning;
186 private boolean mMerchantSupportsAutofillPaymentInstruments; 187 private boolean mMerchantSupportsAutofillPaymentInstruments;
187 private ContactEditor mContactEditor; 188 private ContactEditor mContactEditor;
188 private boolean mHasRecordedAbortReason; 189 private boolean mHasRecordedAbortReason;
190 private boolean mWaitingForPaymentFactory;
189 191
190 /** True if any of the requested payment methods are supported. */ 192 /** True if any of the requested payment methods are supported. */
191 private boolean mArePaymentMethodsSupported; 193 private boolean mArePaymentMethodsSupported;
192 194
193 /** True if show() was called. */ 195 /** True if show() was called. */
194 private boolean mIsShowing; 196 private boolean mIsShowing;
195 197
196 /** The helper to create and fill the response to send to the merchant. */ 198 /** The helper to create and fill the response to send to the merchant. */
197 private PaymentResponseHelper mPaymentResponseHelper; 199 private PaymentResponseHelper mPaymentResponseHelper;
198 200
199 /** 201 /**
200 * Builds the PaymentRequest service implementation. 202 * Builds the PaymentRequest service implementation.
201 * 203 *
202 * @param context The context where PaymentRequest has been invoked. 204 * @param context The context where PaymentRequest has been invoked.
203 * @param webContents The web contents that have invoked the PaymentRequ est API. 205 * @param webContents The web contents that have invoked the PaymentRequ est API.
204 * @param dismissObserver The observer to notify when PaymentRequest UI has been dismissed. 206 * @param dismissObserver The observer to notify when PaymentRequest UI has been dismissed.
205 */ 207 */
206 public PaymentRequestImpl(Activity context, WebContents webContents, 208 public PaymentRequestImpl(Activity context, WebContents webContents,
207 PaymentRequestDismissObserver dismissObserver) { 209 PaymentRequestDismissObserver dismissObserver) {
208 assert context != null; 210 assert context != null;
209 assert webContents != null; 211 assert webContents != null;
210 assert dismissObserver != null; 212 assert dismissObserver != null;
211 213
212 assert context instanceof ChromeActivity; 214 assert context instanceof ChromeActivity;
213 mContext = (ChromeActivity) context; 215 mContext = (ChromeActivity) context;
216 mWebContents = webContents;
214 217
215 mDismissObserver = dismissObserver; 218 mDismissObserver = dismissObserver;
216 mMerchantName = webContents.getTitle(); 219 mMerchantName = mWebContents.getTitle();
217 // The feature is available only in secure context, so it's OK to not sh ow HTTPS. 220 // The feature is available only in secure context, so it's OK to not sh ow HTTPS.
218 mOrigin = UrlFormatter.formatUrlForSecurityDisplay(webContents.getVisibl eUrl(), false); 221 mOrigin = UrlFormatter.formatUrlForSecurityDisplay(mWebContents.getVisib leUrl(), false);
219 222
220 final FaviconHelper faviconHelper = new FaviconHelper(); 223 final FaviconHelper faviconHelper = new FaviconHelper();
221 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), 224 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(),
222 webContents.getVisibleUrl(), 225 mWebContents.getVisibleUrl(),
223 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f avicon_size), 226 mContext.getResources().getDimensionPixelSize(R.dimen.payments_f avicon_size),
224 new FaviconHelper.FaviconImageCallback() { 227 new FaviconHelper.FaviconImageCallback() {
225 @Override 228 @Override
226 public void onFaviconAvailable(Bitmap bitmap, String iconUrl ) { 229 public void onFaviconAvailable(Bitmap bitmap, String iconUrl ) {
227 faviconHelper.destroy(); 230 faviconHelper.destroy();
228 if (bitmap == null) return; 231 if (bitmap == null) return;
229 if (mUI == null) { 232 if (mUI == null) {
230 mFavicon = bitmap; 233 mFavicon = bitmap;
231 return; 234 return;
232 } 235 }
233 mUI.setTitleBitmap(bitmap); 236 mUI.setTitleBitmap(bitmap);
234 } 237 }
235 }); 238 });
236 239
237 mApps = PaymentAppFactory.create(mContext, webContents);
238
239 mAddressEditor = new AddressEditor(); 240 mAddressEditor = new AddressEditor();
240 mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTe st); 241 mCardEditor = new CardEditor(mWebContents, mAddressEditor, sObserverForT est);
241 242
242 recordSuccessFunnelHistograms("Initiated"); 243 recordSuccessFunnelHistograms("Initiated");
243 } 244 }
244 245
245 /** 246 /**
246 * Called by the merchant website to initialize the payment request data. 247 * Called by the merchant website to initialize the payment request data.
247 */ 248 */
248 @Override 249 @Override
249 public void init(PaymentRequestClient client, PaymentMethodData[] methodData , 250 public void init(PaymentRequestClient client, PaymentMethodData[] methodData ,
250 PaymentDetails details, PaymentOptions options) { 251 PaymentDetails details, PaymentOptions options) {
(...skipping 10 matching lines...) Expand all
261 mMethodData = getValidatedMethodData(methodData, mCardEditor); 262 mMethodData = getValidatedMethodData(methodData, mCardEditor);
262 if (mMethodData == null) { 263 if (mMethodData == null) {
263 disconnectFromClientWithDebugMessage("Invalid payment methods or dat a"); 264 disconnectFromClientWithDebugMessage("Invalid payment methods or dat a");
264 recordAbortReasonHistogram( 265 recordAbortReasonHistogram(
265 PaymentRequestMetrics.ABORT_REASON_INVALID_DATA_FROM_RENDERE R); 266 PaymentRequestMetrics.ABORT_REASON_INVALID_DATA_FROM_RENDERE R);
266 return; 267 return;
267 } 268 }
268 269
269 if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return; 270 if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return;
270 271
271 getMatchingPaymentInstruments(); 272 mWaitingForPaymentFactory = true;
273 PaymentAppFactory.create(mContext, mWebContents, mMethodData.keySet(), t his);
272 274
273 boolean requestShipping = options != null && options.requestShipping; 275 boolean requestShipping = options != null && options.requestShipping;
274 boolean requestPayerName = options != null && options.requestPayerName; 276 boolean requestPayerName = options != null && options.requestPayerName;
275 boolean requestPayerPhone = options != null && options.requestPayerPhone ; 277 boolean requestPayerPhone = options != null && options.requestPayerPhone ;
276 boolean requestPayerEmail = options != null && options.requestPayerEmail ; 278 boolean requestPayerEmail = options != null && options.requestPayerEmail ;
277 279
278 List<AutofillProfile> profiles = null; 280 List<AutofillProfile> profiles = null;
279 if (requestShipping || requestPayerName || requestPayerPhone || requestP ayerEmail) { 281 if (requestShipping || requestPayerName || requestPayerPhone || requestP ayerEmail) {
280 profiles = PersonalDataManager.getInstance().getProfilesToSuggest( 282 profiles = PersonalDataManager.getInstance().getProfilesToSuggest(
281 false /* includeNameInLabel */); 283 false /* includeNameInLabel */);
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 // Payment methods should be non-empty. 446 // Payment methods should be non-empty.
445 if (TextUtils.isEmpty(methods[j])) return null; 447 if (TextUtils.isEmpty(methods[j])) return null;
446 result.put(methods[j], data); 448 result.put(methods[j], data);
447 } 449 }
448 450
449 paymentMethodsCollector.addAcceptedPaymentMethodsIfRecognized(method s); 451 paymentMethodsCollector.addAcceptedPaymentMethodsIfRecognized(method s);
450 } 452 }
451 return result; 453 return result;
452 } 454 }
453 455
454 /** Queries the installed payment apps for their instruments that merchant s upports. */ 456 /**
455 private void getMatchingPaymentInstruments() { 457 * Called when installed payment apps have been determined. Queries the inst alled payment apps
456 mPendingApps = new ArrayList<>(mApps); 458 * for their instruments that merchant supports.
459 */
460 @Override
461 public void onPaymentAppsReady(List<PaymentApp> apps) {
462 mPendingApps = new ArrayList<>(apps);
457 mPendingInstruments = new ArrayList<>(); 463 mPendingInstruments = new ArrayList<>();
458 mPendingAutofillInstruments = new ArrayList<>(); 464 mPendingAutofillInstruments = new ArrayList<>();
459 465
460 Map<PaymentApp, Map<String, JSONObject>> queryApps = new HashMap<>(); 466 Map<PaymentApp, Map<String, JSONObject>> queryApps = new HashMap<>();
461 for (int i = 0; i < mApps.size(); i++) { 467 for (int i = 0; i < apps.size(); i++) {
462 PaymentApp app = mApps.get(i); 468 PaymentApp app = apps.get(i);
463 Map<String, JSONObject> appMethods = 469 Map<String, JSONObject> appMethods =
464 filterMerchantMethodData(mMethodData, app.getAppMethodNames( )); 470 filterMerchantMethodData(mMethodData, app.getAppMethodNames( ));
465 if (appMethods == null) { 471 if (appMethods == null) {
466 mPendingApps.remove(app); 472 mPendingApps.remove(app);
467 } else { 473 } else {
468 mArePaymentMethodsSupported = true; 474 mArePaymentMethodsSupported = true;
469 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au tofillPaymentApp; 475 mMerchantSupportsAutofillPaymentInstruments |= app instanceof Au tofillPaymentApp;
470 queryApps.put(app, appMethods); 476 queryApps.put(app, appMethods);
471 } 477 }
472 } 478 }
473 479
474 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h as been initialized, 480 // Query instruments after mMerchantSupportsAutofillPaymentInstruments h as been initialized,
475 // so a fast response from a non-autofill payment app at the front of th e app list does not 481 // so a fast response from a non-autofill payment app at the front of th e app list does not
476 // cause NOT_SUPPORTED payment rejection. 482 // cause NOT_SUPPORTED payment rejection.
477 for (Map.Entry<PaymentApp, Map<String, JSONObject>> q : queryApps.entryS et()) { 483 for (Map.Entry<PaymentApp, Map<String, JSONObject>> q : queryApps.entryS et()) {
478 q.getKey().getInstruments(q.getValue(), this); 484 q.getKey().getInstruments(q.getValue(), mOrigin, this);
479 } 485 }
486 mWaitingForPaymentFactory = false;
480 } 487 }
481 488
482 /** Filter out merchant method data that's not relevant to a payment app. Ca n return null. */ 489 /** Filter out merchant method data that's not relevant to a payment app. Ca n return null. */
483 private static Map<String, JSONObject> filterMerchantMethodData( 490 private static Map<String, JSONObject> filterMerchantMethodData(
484 Map<String, JSONObject> merchantMethodData, Set<String> appMethods) { 491 Map<String, JSONObject> merchantMethodData, Set<String> appMethods) {
485 Map<String, JSONObject> result = null; 492 Map<String, JSONObject> result = null;
486 for (String method : appMethods) { 493 for (String method : appMethods) {
487 if (merchantMethodData.containsKey(method)) { 494 if (merchantMethodData.containsKey(method)) {
488 if (result == null) result = new HashMap<>(); 495 if (result == null) result = new HashMap<>();
489 result.put(method, merchantMethodData.get(method)); 496 result.put(method, merchantMethodData.get(method));
(...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 // UI has requested the full list of payment instruments. Provide it now . 1058 // UI has requested the full list of payment instruments. Provide it now .
1052 if (mPaymentInformationCallback != null) providePaymentInformation(); 1059 if (mPaymentInformationCallback != null) providePaymentInformation();
1053 } 1060 }
1054 1061
1055 /** 1062 /**
1056 * If no payment methods are supported, disconnect from the client and retur n true. 1063 * If no payment methods are supported, disconnect from the client and retur n true.
1057 * 1064 *
1058 * @return True if no payment methods are supported 1065 * @return True if no payment methods are supported
1059 */ 1066 */
1060 private boolean disconnectIfNoPaymentMethodsSupported() { 1067 private boolean disconnectIfNoPaymentMethodsSupported() {
1068 // Waiting for payment app factory to respond.
1069 if (mPendingApps == null || mPendingInstruments == null) return false;
please use gerrit instead 2016/11/17 20:40:08 Maybe check mWaitingForPaymentFactory here instead
1070
1061 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst ruments.isEmpty(); 1071 boolean waitingForPaymentApps = !mPendingApps.isEmpty() || !mPendingInst ruments.isEmpty();
1062 boolean foundPaymentMethods = 1072 boolean foundPaymentMethods =
1063 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt y(); 1073 mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpt y();
1064 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen ts 1074 boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstrumen ts
1065 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD _ABORT); 1075 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD _ABORT);
1066 1076
1067 if (!mArePaymentMethodsSupported 1077 if (!mArePaymentMethodsSupported
1068 || (mIsShowing && !waitingForPaymentApps && !foundPaymentMethods 1078 || (mIsShowing && !waitingForPaymentApps && !foundPaymentMethods
1069 && !userCanAddCreditCard)) { 1079 && !mWaitingForPaymentFactory && !userCanAddCreditCar d)) {
1070 // All payment apps have responded, but none of them have instrument s. It's possible to 1080 // All payment apps have responded, but none of them have instrument s. It's possible to
1071 // add credit cards, but the merchant does not support them either. The payment request 1081 // add credit cards, but the merchant does not support them either. The payment request
1072 // must be rejected. 1082 // must be rejected.
1073 disconnectFromClientWithDebugMessage("Requested payment methods have no instruments", 1083 disconnectFromClientWithDebugMessage("Requested payment methods have no instruments",
1074 PaymentErrorReason.NOT_SUPPORTED); 1084 PaymentErrorReason.NOT_SUPPORTED);
1075 recordAbortReasonHistogram(mArePaymentMethodsSupported 1085 recordAbortReasonHistogram(mArePaymentMethodsSupported
1076 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY MENT_METHOD 1086 ? PaymentRequestMetrics.ABORT_REASON_NO_MATCHING_PAY MENT_METHOD
1077 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA YMENT_METHOD); 1087 : PaymentRequestMetrics.ABORT_REASON_NO_SUPPORTED_PA YMENT_METHOD);
1078 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi ceShowFailed(); 1088 if (sObserverForTest != null) sObserverForTest.onPaymentRequestServi ceShowFailed();
1079 return true; 1089 return true;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
1223 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, 1233 "PaymentRequest.CheckoutFunnel.Aborted", abortReason,
1224 PaymentRequestMetrics.ABORT_REASON_MAX); 1234 PaymentRequestMetrics.ABORT_REASON_MAX);
1225 1235
1226 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { 1236 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) {
1227 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); 1237 mJourneyLogger.recordJourneyStatsHistograms("UserAborted");
1228 } else { 1238 } else {
1229 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); 1239 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted");
1230 } 1240 }
1231 } 1241 }
1232 } 1242 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698