@Override public void disconnected(GdxPayException exception) { observer.handleInstallError(new GdxPayException("Failed to bind to service", exception)); } });
private void setInstalledAndNotifyObserver() { if (!installationComplete) { installationComplete = true; observer.handleInstall(); } }
@Override public void purchaseError(GdxPayException exception) { if (observer != null) { observer.handlePurchaseError(exception); } }
@Override public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) { // check the edge case that the callback comes with a delay right after dispose() was called if (observer == null) return; if (responseCode == BillingClient.BillingResponse.OK && purchases != null) { handlePurchase(purchases, false); } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) { observer.handlePurchaseCanceled(); } else if (responseCode == BillingClient.BillingResponse.ITEM_ALREADY_OWNED) { observer.handlePurchaseError(new ItemAlreadyOwnedException()); } else { Gdx.app.error(TAG, "onPurchasesUpdated failed with responseCode " + responseCode); observer.handlePurchaseError(new GdxPayException("onPurchasesUpdated failed with responseCode " + responseCode)); } }
observer.handlePurchase(t); observer.handlePurchase(t); if (error == null) { log(LOGTYPEERROR, "Transaction failed but error-object is null: " + transaction); observer.handlePurchaseError(new RuntimeException("Transaction failed: " + transaction)); observer.handlePurchaseCanceled(); } else { log(LOGTYPEERROR, "Transaction failed: " + error.toString()); observer.handlePurchaseError(new RuntimeException("Transaction failed: " + error.toString()));
@Override public void purchaseRestore() { try { List<Transaction> transactions = googleInAppBillingService.getPurchases(); Array<Transaction> entitlements = new Array<>(Transaction.class); for (int i = 0; i < transactions.size(); i++) { Transaction transaction = transactions.get(i); if (OfferType.CONSUMABLE == getOfferType(transaction.getIdentifier())) { googleInAppBillingService.consumePurchase(transaction, observer); } else { entitlements.add(transaction); } } if (observer != null) { observer.handleRestore(entitlements.toArray()); } } catch (GdxPayException e) { if (observer != null) { observer.handleRestoreError(e); } } }
@Override public void purchaseSuccess(Transaction transaction) { if (observer != null) { switch (offerType) { case CONSUMABLE: // Warning: observer.handlePurchase is called in googleInAppBillingService.consumePurchase. // That is not clean, I would prefer to keep it on one place. // Should be refactored later. googleInAppBillingService.consumePurchase(transaction, observer); break; case ENTITLEMENT: case SUBSCRIPTION: observer.handlePurchase(transaction); break; default: String error = "Unsupported OfferType=" + getOfferType(identifier) + " for identifier=" + identifier; throw new GdxPayException(error); } } }
@Override public void run() { try { Log.d(LOG_TAG, "Purchase consumer starting"); final int result = consumePurchaseToken(transaction.getTransactionData()); if (result == 0) { observer.handlePurchase(transaction); } else { ResponseCode responseCode = ResponseCode.findByCode(result); String productId = transaction.getIdentifier(); String error = "Consuming " + productId + " failed, " + responseCode; observer.handlePurchaseError(new ConsumeException(error, transaction)); } } catch (final RemoteException e) { applicationProxy.postRunnable(new Runnable() { @Override public void run() { String message = "Failed consuming product: " + transaction.getIdentifier(); observer.handlePurchaseError(new ConsumeException(message, transaction, e)); } }); } } }
transactions.add(transaction); else observer.handlePurchase(transaction); observer.handleRestore(transactions.toArray(new Transaction[transactions.size()]));
@Override public void onPurchaseHistoryResponse(int responseCode, List<Purchase> purchases) { if (responseCode == BillingClient.BillingResponse.OK && purchases != null) { handlePurchase(purchases, true); } else { Gdx.app.error(TAG, "onPurchaseHistoryResponse failed with responseCode " + responseCode); observer.handleRestoreError(new GdxPayException("onPurchaseHistoryResponse failed with " + "responseCode " + responseCode)); } } });
@Override public void paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue queue) { // All products have been restored. log(LOGTYPELOG, "All transactions have been restored!"); observer.handleRestore(restoredTransactions.toArray(new Transaction[restoredTransactions .size()])); restoredTransactions.clear(); }
@Override public void purchaseCanceled() { if (observer != null) { observer.handlePurchaseCanceled(); } } });
observer.handlePurchase(t); observer.handlePurchase(t); log(LOGTYPEERROR, "Transaction failed but error-object is null: " + transaction); observer.handlePurchaseError(new RuntimeException("Transaction failed: " + transaction)); } else if (error.code() == SKErrorCode.PaymentCancelled) { log(LOGTYPEERROR, "Transaction was cancelled by user!"); observer.handlePurchaseCanceled(); } else { log(LOGTYPEERROR, "Transaction failed: " + error.toString()); observer.handlePurchaseError(new RuntimeException("Transaction failed: " + error.toString()));
observer.handleRestore(transactions.toArray(new Transaction[transactions.size()])); observer.handleRestoreError(new GdxPayException("onPurchaseUpdatesResponse: FAILED, should retry request")); break; observer.handleRestoreError(new GdxPayException("onPurchaseUpdatesResponse: NOT_SUPPORTED, should retry request")); break;
@Override public void didFail (SKRequest request, NSError error) { // Receipt refresh request failed. Let's just continue. log(LOGTYPEERROR, "Receipt fetching failed: " + error.toString()); log(LOGTYPELOG, "Transaction was completed: " + getOriginalTxID(transaction)); observer.handlePurchase(t); // Finish transaction. SKPaymentQueue.getDefaultQueue().finishTransaction(transaction); } });
@Override public void paymentQueueRestoreCompletedTransactionsFailedWithError(SKPaymentQueue queue, NSError error) { // Restoration failed. // Decide if user cancelled or transaction failed. if (error.code() == SKErrorCode.PaymentCancelled) { log(LOGTYPEERROR, "Restoring of transactions was cancelled by user!"); observer.handleRestoreError(new RuntimeException("Restoring of purchases was " + "cancelled by user!")); } else { log(LOGTYPEERROR, "Restoring of transactions failed: " + error.toString()); observer.handleRestoreError(new RuntimeException("Restoring of purchases failed: " + error.toString())); } } }
@Override public void restoreCompletedTransactionsFinished (SKPaymentQueue queue) { // All products have been restored. log(LOGTYPELOG, "All transactions have been restored!"); observer.handleRestore(restoredTransactions.toArray(new Transaction[restoredTransactions.size()])); restoredTransactions.clear(); }
@Test public void purchaseCanceledShouldDelegateResultToObserver() throws Exception { PurchaseRequestCallback callback = connectBindAndPurchaseRequestForFullEditionEntitlement(); callback.purchaseCanceled(); verify(purchaseObserver).handlePurchaseCanceled(); }
@Override public void run() { // it might happen that this was already disposed until the service connection was established if (PurchaseManagerGoogleBilling.this.observer == null) return; if (!serviceConnected) PurchaseManagerGoogleBilling.this.observer.handleInstallError( new GdxPayException("Connection to Play Billing not possible")); else if (autoFetchInformation) { fetchOfferDetails(); } else setInstalledAndNotifyObserver(); } });
@Override public void requestDidFailWithError(SKRequest request, NSError error) { String errorMessage = "Error requesting product info to later purchase: " + (error != null ? error.toString() : "unknown"); log(LOGTYPEERROR, errorMessage); observer.handlePurchaseError(new RuntimeException(errorMessage)); } }