Chromium Code Reviews| OLD | NEW |
|---|---|
| 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; | |
| 8 import android.graphics.Bitmap; | |
| 9 import android.text.TextUtils; | |
| 10 | |
| 11 import org.chromium.base.Callback; | |
| 12 import org.chromium.chrome.browser.autofill.PersonalDataManager; | |
| 13 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; | |
| 14 import org.chromium.chrome.browser.favicon.FaviconHelper; | |
| 15 import org.chromium.chrome.browser.payments.ui.LineItem; | |
| 16 import org.chromium.chrome.browser.payments.ui.PaymentInformation; | |
| 17 import org.chromium.chrome.browser.payments.ui.PaymentOption; | |
| 18 import org.chromium.chrome.browser.payments.ui.PaymentRequestUI; | |
| 19 import org.chromium.chrome.browser.payments.ui.SectionInformation; | |
| 20 import org.chromium.chrome.browser.profiles.Profile; | |
| 21 import org.chromium.content.browser.ContentViewCore; | |
| 7 import org.chromium.content_public.browser.WebContents; | 22 import org.chromium.content_public.browser.WebContents; |
| 8 import org.chromium.mojo.system.MojoException; | 23 import org.chromium.mojo.system.MojoException; |
| 9 import org.chromium.mojom.payments.PaymentDetails; | 24 import org.chromium.mojom.payments.PaymentDetails; |
| 25 import org.chromium.mojom.payments.PaymentItem; | |
| 10 import org.chromium.mojom.payments.PaymentOptions; | 26 import org.chromium.mojom.payments.PaymentOptions; |
| 11 import org.chromium.mojom.payments.PaymentRequest; | 27 import org.chromium.mojom.payments.PaymentRequest; |
| 12 import org.chromium.mojom.payments.PaymentRequestClient; | 28 import org.chromium.mojom.payments.PaymentRequestClient; |
| 29 import org.chromium.mojom.payments.PaymentResponse; | |
| 30 import org.chromium.mojom.payments.ShippingOption; | |
| 31 import org.chromium.ui.base.WindowAndroid; | |
| 32 | |
| 33 import org.json.JSONException; | |
| 34 import org.json.JSONObject; | |
| 35 | |
| 36 import java.util.ArrayList; | |
| 37 import java.util.HashSet; | |
| 38 import java.util.Iterator; | |
| 39 import java.util.LinkedList; | |
| 40 import java.util.List; | |
| 13 | 41 |
| 14 /** | 42 /** |
| 15 * Android implementation of the PaymentRequest service defined in | 43 * Android implementation of the PaymentRequest service defined in |
| 16 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. | 44 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. |
| 17 */ | 45 */ |
| 18 public class PaymentRequestImpl implements PaymentRequest { | 46 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, |
| 47 PaymentApp.InstrumentsCallback, | |
|
Ted C
2016/04/22 03:59:37
indent 8 from the start of the previous line
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 48 PaymentInstrument.DetailsCallback { | |
| 49 /** | |
| 50 * The size for the favicon in density-independent pixels. | |
| 51 */ | |
| 52 private static final int FAVICON_SIZE_DP = 24; | |
| 53 | |
| 54 private Activity mContext; | |
| 55 private String mMerchantName; | |
| 56 private String mOrigin; | |
| 57 private Bitmap mFavicon; | |
| 58 private List<PaymentApp> mApps; | |
| 59 private PaymentRequestClient mClient; | |
| 60 private HashSet<String> mSupportedMethods; | |
|
Ted C
2016/04/22 03:59:38
Set/List generic versions plz
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 61 private ArrayList<LineItem> mLineItems; | |
| 62 private SectionInformation mShippingOptions; | |
| 63 private JSONObject mData; | |
| 64 private SectionInformation mShippingAddresses; | |
| 65 private List<PaymentApp> mPendingApps; | |
| 66 private List<PaymentInstrument> mPendingInstruments; | |
| 67 private SectionInformation mPaymentMethods; | |
| 68 private PaymentRequestUI mUI; | |
| 69 private Callback<PaymentInformation> mPaymentInformationCallback; | |
| 70 private Callback<SectionInformation> mPaymentMethodsCallback; | |
| 71 private boolean mClientCompletion; | |
| 72 | |
| 19 /** | 73 /** |
| 20 * Builds the dialog. | 74 * Builds the dialog. |
| 21 * | 75 * |
| 22 * @param webContents The web contents that have invoked the PaymentRequest API. | 76 * @param webContents The web contents that have invoked the PaymentRequest API. |
| 23 */ | 77 */ |
| 24 public PaymentRequestImpl(WebContents webContents) {} | 78 public PaymentRequestImpl(WebContents webContents) { |
| 79 if (webContents == null) return; | |
| 80 | |
| 81 ContentViewCore contentViewCore = ContentViewCore.fromWebContents(webCon tents); | |
| 82 if (contentViewCore == null) return; | |
| 83 | |
| 84 WindowAndroid window = contentViewCore.getWindowAndroid(); | |
| 85 if (window == null) return; | |
| 86 | |
| 87 mContext = window.getActivity().get(); | |
| 88 if (mContext == null) return; | |
|
Ted C
2016/04/22 03:59:38
personal aside...we should really write a helper f
please use gerrit instead
2016/04/25 19:22:30
Acknowledged.
| |
| 89 | |
| 90 mMerchantName = webContents.getTitle(); | |
| 91 mOrigin = webContents.getVisibleUrl(); | |
| 92 | |
| 93 final FaviconHelper faviconHelper = new FaviconHelper(); | |
| 94 float scale = mContext.getResources().getDisplayMetrics().density; | |
| 95 faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), | |
| 96 webContents.getVisibleUrl(), (int) (FAVICON_SIZE_DP * scale + 0. 5f), | |
| 97 new FaviconHelper.FaviconImageCallback() { | |
| 98 @Override | |
| 99 public void onFaviconAvailable(Bitmap bitmap, String iconUrl ) { | |
| 100 faviconHelper.destroy(); | |
| 101 if (bitmap == null) return; | |
| 102 if (mUI == null) { | |
| 103 mFavicon = bitmap; | |
| 104 return; | |
| 105 } | |
| 106 mUI.setTitleBitmap(bitmap); | |
| 107 } | |
| 108 }); | |
| 109 | |
| 110 mApps = PaymentAppFactory.create(webContents); | |
| 111 } | |
| 25 | 112 |
| 26 /** | 113 /** |
| 27 * Called by the renderer to provide an endpoint for callbacks. | 114 * Called by the renderer to provide an endpoint for callbacks. |
| 28 */ | 115 */ |
| 29 @Override | 116 @Override |
| 30 public void setClient(PaymentRequestClient client) { | 117 public void setClient(PaymentRequestClient client) { |
| 31 assert client != null; | 118 mClient = client; |
|
Ted C
2016/04/22 03:59:37
can this be called more than once?
should we asse
please use gerrit instead
2016/04/25 19:22:31
Should not be called more than once. Added the ass
| |
| 32 client.onError(); | 119 if (mClient == null) return; |
| 120 if (mContext == null) mClient.onError(); | |
| 33 } | 121 } |
| 34 | 122 |
| 35 /** | 123 /** |
| 36 * Called by the merchant website to show the payment request to the user. | 124 * Called by the merchant website to show the payment request to the user. |
| 37 */ | 125 */ |
| 38 @Override | 126 @Override |
| 39 public void show(String[] supportedMethods, PaymentDetails details, PaymentO ptions options, | 127 public void show(String[] supportedMethods, PaymentDetails details, PaymentO ptions options, |
| 40 String stringifiedData) {} | 128 String stringifiedData) { |
| 129 if (mClient == null) return; | |
| 130 | |
| 131 if (mSupportedMethods != null) { | |
| 132 mClient.onError(); | |
|
Ted C
2016/04/22 03:59:37
for debugging, we might want to log each of these
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 mSupportedMethods = getValidatedSupportedMethods(supportedMethods); | |
| 137 if (mSupportedMethods == null) { | |
| 138 mClient.onError(); | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 mLineItems = getValidatedLineItems(details); | |
| 143 if (mLineItems == null) { | |
| 144 mClient.onError(); | |
| 145 return; | |
| 146 } | |
| 147 | |
| 148 mShippingOptions = getValidatedShippingOptions(details); | |
| 149 if (mShippingOptions == null) { | |
| 150 mClient.onError(); | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 mData = getValidatedData(mSupportedMethods, stringifiedData); | |
| 155 if (mData == null) { | |
| 156 mClient.onError(); | |
| 157 return; | |
| 158 } | |
| 159 | |
| 160 List<AutofillAddress> addresses = new LinkedList<AutofillAddress>(); | |
| 161 for (AutofillProfile profile : PersonalDataManager.getInstance().getProf iles()) { | |
|
Ted C
2016/04/22 03:59:37
same comment about iterator vs for int i = 0...
a
please use gerrit instead
2016/04/25 19:22:32
Done.
| |
| 162 addresses.add(new AutofillAddress(profile)); | |
| 163 } | |
| 164 | |
| 165 if (addresses.isEmpty()) { | |
| 166 mShippingAddresses = new SectionInformation(); | |
| 167 } else { | |
| 168 mShippingAddresses = new SectionInformation(0, addresses); | |
| 169 } | |
| 170 | |
| 171 mPendingApps = new LinkedList<PaymentApp>(mApps); | |
| 172 mPendingInstruments = new LinkedList<PaymentInstrument>(); | |
| 173 boolean isGettingInstruments = false; | |
| 174 | |
| 175 for (PaymentApp app : mApps) { | |
| 176 HashSet<String> appMethods = app.getSupportedMethodNames(); | |
| 177 appMethods.retainAll(mSupportedMethods); | |
| 178 if (!appMethods.isEmpty()) { | |
| 179 isGettingInstruments = true; | |
| 180 app.getInstruments(mLineItems, this); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 if (!isGettingInstruments) mPaymentMethods = new SectionInformation(); | |
| 185 | |
| 186 boolean requestShipping = options != null && options.requestShipping; | |
| 187 mUI = new PaymentRequestUI(mContext, this, requestShipping, mMerchantNam e, mOrigin); | |
| 188 if (mFavicon != null) mUI.setTitleBitmap(mFavicon); | |
|
Ted C
2016/04/22 03:59:37
should we set mFavicon = null after this?
please use gerrit instead
2016/04/25 19:22:32
Done.
| |
| 189 } | |
| 190 | |
| 191 private HashSet<String> getValidatedSupportedMethods(String[] methods) { | |
|
Ted C
2016/04/22 03:59:37
s/HashSet/Set
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 192 if (methods == null || methods.length == 0) return null; | |
| 193 | |
| 194 HashSet<String> result = new HashSet<String>(); | |
|
Ted C
2016/04/22 03:59:37
when creating like this, you can do:
Set<String>
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 195 for (String method : methods) { | |
| 196 if (TextUtils.isEmpty(method)) return null; | |
|
Ted C
2016/04/22 03:59:37
continue or return?
please use gerrit instead
2016/04/25 19:22:31
"return null" to indicate invalid method name.
Ted C
2016/04/25 22:49:02
I'm still somewhat surprised we don't just skip ov
please use gerrit instead
2016/04/25 23:19:24
Acknowledged.
| |
| 197 result.add(method); | |
| 198 } | |
| 199 | |
| 200 return result; | |
| 201 } | |
| 202 | |
| 203 private ArrayList<LineItem> getValidatedLineItems(PaymentDetails details) { | |
|
Ted C
2016/04/22 03:59:37
List
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 204 if (null == details || details.items == null || details.items.length == 0) return null; | |
|
Ted C
2016/04/22 03:59:37
details == null is the more consistent thing to do
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 205 | |
| 206 for (PaymentItem item : details.items) { | |
| 207 if (item == null || TextUtils.isEmpty(item.id) || TextUtils.isEmpty( item.label) | |
| 208 || item.amount == null || TextUtils.isEmpty(item.amount.curr encyCode) | |
| 209 || TextUtils.isEmpty(item.amount.value)) { | |
| 210 return null; | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 PaymentItem total = details.items[details.items.length - 1]; | |
| 215 String totalCurrencyCode = total.amount.currencyCode; | |
| 216 CurrencyStringFormatter totalFormatter = new CurrencyStringFormatter(tot alCurrencyCode); | |
| 217 ArrayList<LineItem> result = new ArrayList<LineItem>(details.items.lengt h); | |
| 218 | |
| 219 for (PaymentItem item : details.items) { | |
|
Ted C
2016/04/22 03:59:37
i would do i < length - 1 and skip the == total ch
please use gerrit instead
2016/04/25 19:22:32
Done.
| |
| 220 if (item == total) break; | |
| 221 String currencyCode = item.amount.currencyCode; | |
| 222 if (currencyCode.equals(totalCurrencyCode)) { | |
| 223 result.add(new LineItem(item.label, "", totalFormatter.format(it em.amount.value))); | |
| 224 } else { | |
| 225 result.add(new LineItem(item.label, currencyCode, | |
|
Ted C
2016/04/22 03:59:37
yikes...we support multiple currencies in a single
please use gerrit instead
2016/04/25 19:22:31
Although the spec does not explicitly prohibit thi
| |
| 226 new CurrencyStringFormatter(currencyCode).format(item.am ount.value))); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 result.add(new LineItem( | |
| 231 total.label, totalCurrencyCode, totalFormatter.format(total.amou nt.value))); | |
| 232 | |
| 233 return result; | |
| 234 } | |
| 235 | |
| 236 private SectionInformation getValidatedShippingOptions(PaymentDetails detail s) { | |
| 237 if (details.shippingOptions == null || details.shippingOptions.length == 0) { | |
| 238 return new SectionInformation(); | |
| 239 } | |
| 240 | |
| 241 ArrayList<PaymentOption> result = new ArrayList<PaymentOption>(); | |
| 242 for (ShippingOption option : details.shippingOptions) { | |
| 243 if (option == null || TextUtils.isEmpty(option.id) || TextUtils.isEm pty(option.label) | |
| 244 || option.amount == null || TextUtils.isEmpty(option.amount. currencyCode) | |
| 245 || TextUtils.isEmpty(option.amount.value)) { | |
| 246 return null; | |
|
Ted C
2016/04/22 03:59:37
return or continue?
please use gerrit instead
2016/04/25 19:22:31
"return null" to indicate invalid shipping options
| |
| 247 } | |
| 248 result.add(new PaymentOption(option.id, option.label, "", PaymentOpt ion.NO_ICON)); | |
| 249 } | |
| 250 | |
| 251 return new SectionInformation( | |
| 252 result.size() == 1 ? 0 : SectionInformation.NO_SELECTION, result ); | |
| 253 } | |
| 254 | |
| 255 private JSONObject getValidatedData(HashSet<String> supportedMethods, String stringifiedData) { | |
| 256 if (TextUtils.isEmpty(stringifiedData)) return new JSONObject(); | |
| 257 | |
| 258 JSONObject result; | |
| 259 try { | |
| 260 result = new JSONObject(stringifiedData); | |
| 261 } catch (JSONException e) { | |
| 262 return null; | |
| 263 } | |
| 264 | |
| 265 Iterator<String> it = result.keys(); | |
| 266 while (it.hasNext()) { | |
| 267 String name = it.next(); | |
| 268 if (!supportedMethods.contains(name)) return null; | |
|
Ted C
2016/04/22 03:59:37
same...return or continue?
please use gerrit instead
2016/04/25 19:22:31
"return null" to indicate invalid data. I'll add a
| |
| 269 if (result.optJSONObject(name) == null) return null; | |
| 270 } | |
| 271 | |
| 272 return result; | |
| 273 } | |
| 274 | |
| 275 /** | |
| 276 * Called to retrieve the data to show in the initial PaymentRequest UI. | |
| 277 */ | |
| 278 @Override | |
| 279 public void getDefaultPaymentInformation(Callback<PaymentInformation> callba ck) { | |
| 280 mPaymentInformationCallback = callback; | |
| 281 if (mPaymentMethods == null) return; | |
| 282 provideDefaultPaymentInformation(); | |
|
Ted C
2016/04/22 03:59:37
in general I would avoid this indirection for now.
please use gerrit instead
2016/04/25 19:22:31
I call provideDefault() also when I've finished lo
| |
| 283 } | |
| 284 | |
| 285 private void provideDefaultPaymentInformation() { | |
| 286 mPaymentInformationCallback.onResult(new PaymentInformation( | |
| 287 mLineItems.get(mLineItems.size() - 1), mShippingAddresses.getSel ectedItem(), | |
| 288 mShippingOptions.getSelectedItem(), mPaymentMethods.getSelectedI tem())); | |
| 289 mPaymentInformationCallback = null; | |
| 290 } | |
| 291 | |
| 292 @Override | |
| 293 public void getLineItems(Callback<ArrayList<LineItem>> callback) { | |
| 294 callback.onResult(mLineItems); | |
|
Ted C
2016/04/22 03:59:37
same async-ness for all the callbacks
please use gerrit instead
2016/04/25 19:22:31
Done.
| |
| 295 } | |
| 296 | |
| 297 @Override | |
| 298 public void getShippingAddresses(Callback<SectionInformation> callback) { | |
| 299 callback.onResult(mShippingAddresses); | |
| 300 } | |
| 301 | |
| 302 @Override | |
| 303 public void getShippingOptions(Callback<SectionInformation> callback) { | |
| 304 callback.onResult(mShippingOptions); | |
| 305 } | |
| 306 | |
| 307 @Override | |
| 308 public void getPaymentMethods(Callback<SectionInformation> callback) { | |
| 309 mPaymentMethodsCallback = callback; | |
| 310 if (mPaymentMethods == null) return; | |
| 311 providePaymentMethods(); | |
| 312 } | |
| 313 | |
| 314 private void providePaymentMethods() { | |
| 315 mPaymentMethodsCallback.onResult(mPaymentMethods); | |
| 316 mPaymentMethodsCallback = null; | |
| 317 } | |
| 318 | |
| 319 @Override | |
| 320 public void onShippingAddressChanged(PaymentOption selectedShippingAddress) { | |
| 321 assert selectedShippingAddress instanceof AutofillAddress; | |
| 322 mShippingAddresses.setSelectedItem(selectedShippingAddress); | |
| 323 mClient.onShippingAddressChange( | |
| 324 ((AutofillAddress) selectedShippingAddress).toShippingAddress()) ; | |
| 325 } | |
| 326 | |
| 327 @Override | |
| 328 public void onShippingOptionChanged(PaymentOption selectedShippingOption) { | |
| 329 mShippingOptions.setSelectedItem(selectedShippingOption); | |
| 330 mClient.onShippingOptionChange(selectedShippingOption.getIdentifier()); | |
| 331 } | |
| 332 | |
| 333 @Override | |
| 334 public void onPaymentMethodChanged(PaymentOption selectedPaymentMethod) { | |
| 335 assert selectedPaymentMethod instanceof PaymentInstrument; | |
| 336 mPaymentMethods.setSelectedItem(selectedPaymentMethod); | |
| 337 } | |
| 338 | |
| 339 @Override | |
| 340 public void onPayClicked(PaymentOption selectedShippingAddress, | |
| 341 PaymentOption selectedShippingOption, PaymentOption selectedPaymentM ethod) { | |
| 342 assert selectedPaymentMethod instanceof PaymentInstrument; | |
| 343 PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod ; | |
| 344 instrument.getDetails(mMerchantName, mOrigin, mLineItems, | |
| 345 mData.optJSONObject(instrument.getMethodName()), this); | |
| 346 } | |
| 347 | |
| 348 @Override | |
| 349 public void onDismiss() { | |
| 350 mClient.onError(); | |
| 351 closeUI(false); | |
| 352 } | |
| 41 | 353 |
| 42 /** | 354 /** |
| 43 * Called by the merchant website to abort the payment. | 355 * Called by the merchant website to abort the payment. |
| 44 */ | 356 */ |
| 45 @Override | 357 @Override |
| 46 public void abort() {} | 358 public void abort() { |
| 359 closeUI(false); | |
| 360 } | |
| 47 | 361 |
| 48 /** | 362 /** |
| 49 * Called when the merchant website has processed the payment. | 363 * Called when the merchant website has processed the payment. |
| 50 */ | 364 */ |
| 51 @Override | 365 @Override |
| 52 public void complete(boolean success) {} | 366 public void complete(boolean success) { |
| 367 mClientCompletion = true; | |
| 368 closeUI(success); | |
| 369 } | |
| 53 | 370 |
| 54 /** | 371 /** |
| 55 * Called when the renderer closes the Mojo connection. | 372 * Called when the renderer closes the Mojo connection. |
| 56 */ | 373 */ |
| 57 @Override | 374 @Override |
| 58 public void close() {} | 375 public void close() { |
| 376 closeUI(false); | |
| 377 } | |
| 59 | 378 |
| 60 /** | 379 /** |
| 61 * Called when the Mojo connection encounters an error. | 380 * Called when the Mojo connection encounters an error. |
| 62 */ | 381 */ |
| 63 @Override | 382 @Override |
| 64 public void onConnectionError(MojoException e) {} | 383 public void onConnectionError(MojoException e) { |
| 384 closeUI(false); | |
| 385 } | |
| 386 | |
| 387 /** | |
| 388 * Called after retrieving the list of payment instruments in an app. | |
| 389 */ | |
| 390 @Override | |
| 391 public void onInstrumentsReady(PaymentApp app, List<PaymentInstrument> instr uments) { | |
| 392 mPendingApps.remove(app); | |
| 393 | |
| 394 if (instruments != null) { | |
| 395 for (PaymentInstrument instrument : instruments) { | |
| 396 if (mSupportedMethods.contains(instrument.getMethodName())) { | |
| 397 mPendingInstruments.add(instrument); | |
| 398 } else { | |
| 399 instrument.dismiss(); | |
| 400 } | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 if (mPendingApps.isEmpty()) { | |
| 405 if (mPendingInstruments.isEmpty()) { | |
| 406 mPaymentMethods = new SectionInformation(); | |
| 407 } else { | |
| 408 mPaymentMethods = new SectionInformation(0, mPendingInstruments) ; | |
| 409 mPendingInstruments.clear(); | |
| 410 } | |
| 411 | |
| 412 if (mPaymentInformationCallback != null) provideDefaultPaymentInform ation(); | |
| 413 if (mPaymentMethodsCallback != null) providePaymentMethods(); | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 /** | |
| 418 * Called after retrieving instrument details. | |
| 419 */ | |
| 420 @Override | |
| 421 public void onInstrumentDetailsReady(String methodName, String stringifiedDe tails) { | |
| 422 PaymentResponse response = new PaymentResponse(); | |
| 423 response.methodName = methodName; | |
| 424 response.stringifiedDetails = stringifiedDetails; | |
| 425 mClient.onPaymentResponse(response); | |
| 426 } | |
| 427 | |
| 428 /** | |
| 429 * Called if unable to retrieve instrument details. | |
| 430 */ | |
| 431 @Override | |
| 432 public void onInstrumentDetailsError() { | |
| 433 mClient.onError(); | |
| 434 closeUI(false); | |
| 435 } | |
| 436 | |
| 437 /** | |
| 438 * Stop communications with the client and closes the UI. | |
| 439 */ | |
| 440 private void closeUI(boolean paymentSuccess) { | |
| 441 if (mUI != null) { | |
| 442 mUI.close(paymentSuccess, new Runnable() { | |
| 443 @Override | |
| 444 public void run() { | |
| 445 if (!mClientCompletion) return; | |
| 446 if (mClient == null) return; | |
| 447 mClient.onComplete(); | |
| 448 mClient = null; | |
| 449 } | |
| 450 }); | |
| 451 mUI = null; | |
| 452 } else { | |
| 453 mClient = null; | |
| 454 } | |
| 455 | |
| 456 if (mPaymentMethods != null) { | |
| 457 for (int i = 0; i < mPaymentMethods.getSize(); i++) { | |
| 458 PaymentOption option = mPaymentMethods.getItem(i); | |
| 459 assert option instanceof PaymentInstrument; | |
| 460 ((PaymentInstrument) option).dismiss(); | |
| 461 } | |
| 462 mPaymentMethods = null; | |
| 463 } | |
| 464 } | |
| 65 } | 465 } |
| OLD | NEW |