/** Converts a product to our transaction object. */ Transaction convertPurchasedProductToTransaction (Product product, String uniquePurchaseRequestID) { // build the transaction from the purchase object Transaction transaction = new Transaction(); transaction.setIdentifier(config.getOfferForStore(storeName(), product.getIdentifier()).getIdentifier()); transaction.setStoreName(storeName()); transaction.setOrderId(uniquePurchaseRequestID); //---- should work ---- TODO: Testing ------------------------- transaction.setPurchaseTime(new Date()); // FIXME: we need the purchase date (from receipt!) ..... maybe this is correct.... this is the "receipt" for the purchased product transaction.setPurchaseText("Purchased for " + product.getFormattedPrice() + "."); transaction.setPurchaseCost((int)(product.getLocalPrice() * 100)); //--------------- TODO: not sure if this works in every case! transaction.setPurchaseCostCurrency(product.getCurrencyCode()); transaction.setReversalTime(null); transaction.setReversalText(null); transaction.setTransactionData(null); transaction.setTransactionDataSignature(null); showMessage(LOGTYPELOG, "converted purchased product to transaction."); return transaction; }
/** Converts a purchase to our transaction object. */ Transaction convertToTransaction (Receipt receipt) { // build the transaction from the purchase object Transaction transaction = new Transaction(); transaction.setIdentifier(config.getOfferForStore(storeName(), receipt.getIdentifier()).getIdentifier()); transaction.setStoreName(storeName()); transaction.setOrderId("not available"); //----- TODO: how can i get the uniqueID out of the JSON response!? transaction.setPurchaseTime(receipt.getPurchaseDate()); transaction.setPurchaseText("Purchased by \"" + receipt.getGamer() + "\" for " + receipt.getFormattedPrice() + "."); transaction.setPurchaseCost((int)(receipt.getLocalPrice() * 100)); //--------------- TODO: not sure if this works in every case! transaction.setPurchaseCostCurrency(receipt.getCurrency()); transaction.setReversalTime(null); transaction.setReversalText(null); transaction.setTransactionData(null); transaction.setTransactionDataSignature(null); showMessage(LOGTYPELOG, "converted receipt to transaction."); return transaction; }
/** Just used for testing... */ public static void main(String[] args) { // test in sandbox-mode PurchaseVerifieriOSApple verifier = new PurchaseVerifieriOSApple(true); // our sample receipt for the sandbox (returns error 21004) String receipt = "{\n" + "\"signature\" = \"AluGxOuMy+RT1gkyFCoD1i1KT3KUZl+F5FAAW0ELBlCUbC9dW14876aW0OXBlNJ6pXbBBFB8K0LDy6LuoAS8iBiq3529aRbVRUSKCPeCDZ7apC2zqFYZ4N7bSFDMeb92wzN0X/dELxlkRH4bWjO67X7gnHcN47qHoVckSlGo/mpbAAADVzCCA1MwggI7oAMCAQICCGUUkU3ZWAS1MA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAwwqQXBwbGUgaVR1bmVzIFN0b3JlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA5MDYxNTIyMDU1NloXDTE0MDYxNDIyMDU1NlowZDEjMCEGA1UEAwwaUHVyY2hhc2VSZWNlaXB0Q2VydGlmaWNhdGUxGzAZBgNVBAsMEkFwcGxlIGlUdW5lcyBTdG9yZTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrRjF2ct4IrSdiTChaI0g8pwv/cmHs8p/RwV/rt/91XKVhNl4XIBimKjQQNfgHsDs6yju++DrKJE7uKsphMddKYfFE5rGXsAdBEjBwRIxexTevx3HLEFGAt1moKx509dhxtiIdDgJv2YaVs49B0uJvNdy6SMqNNLHsDLzDS9oZHAgMBAAGjcjBwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUNh3o4p2C0gEYtTJrDtdDC5FYQzowDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSpg4PyGUjFPhJXCBTMzaN+mV8k9TAQBgoqhkiG92NkBgUBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAEaSbPjtmN4C/IB3QEpK32RxacCDXdVXAeVReS5FaZxc+t88pQP93BiAxvdW/3eTSMGY5FbeAYL3etqP5gm8wrFojX0ikyVRStQ+/AQ0KEjtqB07kLs9QUe8czR8UGfdM1EumV/UgvDd4NwNYxLQMg4WTQfgkQQVy8GXZwVHgbE/UC6Y7053pGXBk51NPM3woxhd3gSRLvXj+loHsStcTEqe9pBDpmG5+sk4tw+GK3GMeEN5/+e1QT9np/Kl1nj+aBw7C0xsy0bFnaAd1cSS6xdory/CUvM6gtKsmnOOdqTesbp0bs8sn6Wqs0C9dgcxRHuOMZ2tm8npLUm7argOSzQ==\";\n" + "\"purchase-info\" = \"ewoJInF1YW50aXR5IiA9ICIxIjsKCSJwdXJjaGFzZS1kYXRlIiA9ICIyMDExLTEwLTEyIDIwOjA1OjUwIEV0Yy9HTVQiOwoJIml0ZW0taWQiID0gIjQ3MjQxNTM1MyI7CgkiZXhwaXJlcy1kYXRlLWZvcm1hdHRlZCIgPSAiMjAxMS0xMC0xMiAyMDoxMDo1MCBFdGMvR01UIjsKCSJleHBpcmVzLWRhdGUiID0gIjEzMTg0NTAyNTAwMDAiOwoJInByb2R1Y3QtaWQiID0gImNvbS5kYWlseWJ1cm4ud29kMW1vbnRoIjsKCSJ0cmFuc2FjdGlvbi1pZCIgPSAiMTAwMDAwMDAwOTk1NzYwMiI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZSIgPSAiMjAxMS0xMC0xMiAyMDowNTo1MiBFdGMvR01UIjsKCSJvcmlnaW5hbC10cmFuc2FjdGlvbi1pZCIgPSAiMTAwMDAwMDAwOTk1NzYwMiI7CgkiYmlkIiA9ICJjb20uZGFpbHlidXJuLndvZCI7CgkiYnZycyIgPSAiMC4wLjgiOwp9\";\n" + "\"environment\" = \"Sandbox\";\n" + "\"pod\" = \"100\";\n" + "\"signing-status\" = \"0\";\n" + "}\n"; // build a sample transaction (only receipt is important for validation) Transaction transaction = new Transaction(); transaction.setTransactionData(receipt); if (verifier.isValid(transaction)) { System.out.println("Purchase is VALID!"); } }
@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); } } }
public static Transaction convertJSONPurchaseToTransaction(String inAppPurchaseData) throws JSONException { JSONObject object = new JSONObject(inAppPurchaseData); Transaction transaction = new Transaction(); transaction.setStoreName(PurchaseManagerConfig.STORE_NAME_ANDROID_GOOGLE); if (object.has(PURCHASE_TOKEN)) { transaction.setTransactionData(object.getString(PURCHASE_TOKEN)); } if (object.has(ORDER_ID)) { transaction.setOrderId(object.getString(ORDER_ID)); } transaction.setIdentifier(object.getString(PRODUCT_ID)); transaction.setPurchaseTime(new Date(object.getLong(PURCHASE_TIME))); if (object.has(PURCHASE_STATE)) { fillTransactionForPurchaseState(transaction, object.getInt(PURCHASE_STATE)); } return transaction; }
public Transaction convertToTransaction(Intent responseData) { String purchaseDataString = responseData.getStringExtra(GoogleBillingConstants.INAPP_PURCHASE_DATA); try { Transaction transaction = convertJSONPurchaseToTransaction(purchaseDataString); transaction.setTransactionDataSignature(responseData.getStringExtra(GoogleBillingConstants.INAPP_DATA_SIGNATURE)); String productId = transaction.getIdentifier(); setInformationFields(transaction, productId); return transaction; } catch (JSONException e) { throw new GdxPayException("JSON Exception while parsing: " + purchaseDataString, e); } }
@Override public List<Transaction> getPurchases() { try { Bundle inAppPurchases = billingService().getPurchases(BILLING_API_VERSION, installerPackageName, PURCHASE_TYPE_IN_APP, null); Bundle subscriptions = billingService().getPurchases(BILLING_API_VERSION, installerPackageName, PURCHASE_TYPE_SUBSCRIPTION, null); List<Transaction> transactions = new ArrayList<>(); transactions.addAll(convertPurchasesResponseToTransactions(inAppPurchases)); transactions.addAll(convertPurchasesResponseToTransactions(subscriptions)); return transactions; } catch (RemoteException | RuntimeException e) { // TODO: unit test RuntimeException scenario, e.g. : java.lang.IllegalArgumentException: Unexpected response code: ResponseCode{code=3, message='Billing API version is not supported for the type requested'}, response: Bundle[{RESPONSE_CODE=3}] throw new GdxPayException("Unexpected exception in getPurchases()", e); } }
private static ArrayList<String> makeStringArrayListForTransaction(Transaction transaction) { ArrayList<String> list = new ArrayList<>(); JSONObject jsonObject = new JSONObject(); try { jsonObject.put(ORDER_ID, transaction.getOrderId()); jsonObject.put(PACKAGE_NAME, PACKAGE_NAME_GOOD); jsonObject.put(ORDER_ID, transaction.getOrderId()); jsonObject.put(PRODUCT_ID, transaction.getIdentifier()); jsonObject.put(PURCHASE_TIME, System.currentTimeMillis()); jsonObject.put(PURCHASE_TOKEN, transaction.getTransactionData()); list.add(jsonObject.toString()); } catch (JSONException e) { throw new RuntimeException(e); } return list; }
@Override public void handleRestore(Transaction[] transactions) { for (Transaction transaction : transactions) { if (transaction.isPurchased()) { SpaceTravels3.services.setPurchasedSku(transaction.getIdentifier()); } } }
@Override public void handlePurchase(Transaction transaction) { if (transaction.isPurchased()) { SpaceTravels3.services.setPurchasedSku(transaction.getIdentifier()); ScreenManager.addScreen(new PurchaseThanksScreen()); } }
/** Converts a Receipt to our transaction object. */ static Transaction convertReceiptToTransaction(int i, String requestId, Receipt receipt, final UserData userData) { // build the transaction from the purchase object Transaction transaction = new Transaction(); transaction.setIdentifier(receipt.getSku()); transaction.setOrderId(receipt.getReceiptId()); transaction.setStoreName(PurchaseManagerConfig.STORE_NAME_ANDROID_AMAZON); transaction.setRequestId(requestId); transaction.setUserId(userData.getUserId()); transaction.setPurchaseTime(receipt.getPurchaseDate()); transaction.setPurchaseText("Purchased: " + receipt.getSku().toString()); // transaction.setPurchaseCost(receipt.getSku()); // TODO: GdxPay: impl. // parsing of COST + CURRENCY via skuDetails.getPrice()! // transaction.setPurchaseCostCurrency(null); if (receipt.isCanceled()) { // order has been refunded or cancelled transaction.setReversalTime(receipt.getCancelDate()); // transaction.setReversalText(receipt..getPurchaseState() == 1 ? // "Cancelled" : "Refunded"); } else { // still valid! transaction.setReversalTime(null); transaction.setReversalText(null); } transaction.setTransactionData(receipt.toJSON().toString()); // transaction.setTransactionDataSignature(purchase.getSignature()); return transaction; }
/** * Method to handle receipts * * @param requestId * @param receipt * @param userData */ public void handleReceipt(final String requestId, final Receipt receipt, final UserData userData) { showMessage(LOGTYPELOG, "Handle receipt: requestId (" + requestId + ") receipt: " + receipt + ")"); // convert receipt to transaction Transaction trans = AmazonTransactionUtils.convertReceiptToTransaction(1, requestId, receipt, userData); // provides cancleState also switch (receipt.getProductType()) { case CONSUMABLE: // inform the listener observer.handlePurchase(trans); // Automatically consume item PurchasingService.notifyFulfillment(receipt.getReceiptId(), FulfillmentResult.FULFILLED); break; case ENTITLED: // inform the listener observer.handlePurchase(trans); break; case SUBSCRIPTION: // TODO: check subscription sample for how to handle consumable purchases break; } }
@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(); }
/** Returns true if a transaction is deemed valid. * <p> * IMPORTANT: will return "defaultIfNoVerifierFound" if no verifier was found for the given transaction. * * @param transaction The transaction to verify. * @return True for considered valid. */ public boolean isValid (Transaction transaction) { // find the verifier and verify via verifier if a purchase is valid PurchaseVerifier verifier = verifiers.get(transaction.getStoreName()); if (verifier == null) { return defaultIfNoVerifierFound; } else { return verifier.isValid(transaction); } }
@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(); }
private static List<Transaction> convertPurchasesToTransactions(ArrayList<String> jsonPurchases) { List<Transaction> transactions = new ArrayList<>(); for(String jsonPurchase : jsonPurchases) { try { transactions.add(convertJSONPurchaseToTransaction(jsonPurchase)); // Do not add price from Information.java: price might have changes since purchase. } catch (JSONException e) { throw new IllegalArgumentException("JSON operation failed for json: " + jsonPurchase, e); } } return transactions; }
private static void fillTransactionForPurchaseState(Transaction transaction, int purchaseState) { switch (purchaseState) { case PURCHASE_STATE_CANCELLED: transaction.setReversalTime(new Date()); transaction.setReversalText(REVERSAL_TEXT_CANCELLED); break; case PURCHASE_STATE_REFUNDED: transaction.setReversalTime(new Date()); transaction.setReversalText(REVERSAL_TEXT_REFUNDED); } }
private void setInformationFields(Transaction transaction, String productId) { Information information = purchaseManager.getInformation(productId); Integer priceInCents = information.getPriceInCents(); transaction.setPurchaseCost(priceInCents == null ? 0 : priceInCents); transaction.setPurchaseCostCurrency(information.getPriceCurrencyCode()); }
@Override public void consumePurchase(final Transaction transaction, final PurchaseObserver observer) { // TODO: unit-test this method. Log.i(LOG_TAG, "consumePurchase: " + transaction); new Thread( new PurchaseConsumer(transaction, observer)) .start(); }
@Override public void cancelTestPurchases() { List<Transaction> purchases = getPurchases(); for(Transaction transaction : purchases) { cancelIfTestPurchase(transaction); } }
private void cancelIfTestPurchase(Transaction transaction) { if (isTestPurchase(transaction)) { try { int result = consumePurchaseToken(transaction.getTransactionData()); Log.d(LOG_TAG, "cancelTestPurchase " + transaction + " response code: " + result); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to cancel transaction: " + transaction, e); } } }
public static Transaction transactionFullEditionEuroGooglePlaySandbox() { Transaction transaction = new Transaction(); transaction.setPurchaseCostCurrency("EUR"); transaction.setPurchaseCost(100); transaction.setStoreName(PurchaseManagerConfig.STORE_NAME_ANDROID_GOOGLE); transaction.setPurchaseTime(new Date()); transaction.setIdentifier(PRODUCT_IDENTIFIER_FULL_EDITION); transaction.setTransactionData("minodojglppganfbiedlabed.AO-J1OyNtpooSraUdtKlZ_9gYs0o20ZF_0ryTNACmvaaaG5EwPX0hPruUdGbE3XejoXYCYzJA2xjjAxrDLFhmu9WC4fvTDNL-RDXCWjlHKpzLOigxCr1QhScXR8uXtX8R94iV6MmMHqD"); return transaction; }
@Test public void fillsPurchaseFromJson() throws Exception { String payload = "{\"packageName\":\"com.app.name\",\"productId\":\"com.app.name.productId\",\n" + " \"purchaseTime\":1466539081315,\"purchaseState\":0,\n" + " \"developerPayload\":\"justSomePayload\",\n" + " \"purchaseToken\":\"randomToken\"}\n"; Transaction transaction = convertJSONPurchaseToTransaction(payload); assertThat(transaction.getIdentifier()).isEqualTo("com.app.name.productId"); assertThat(transaction.getPurchaseTime()).isWithinMonth(6); assertThat(transaction.getReversalTime()).isNull(); assertThat(transaction.getReversalText()).isNull(); }
@Test public void marksTransactionAsReversedWhenPurchaseStateIsCancelled() throws Exception { String payload = "{\"packageName\":\"com.app.name\",\"productId\":\"com.app.name.productId\",\n" + " \"purchaseTime\":1466539081315,\"purchaseState\":1,\n" + " \"developerPayload\":\"justSomePayload\",\n" + " \"purchaseToken\":\"randomToken\"}\n"; Transaction transaction = convertJSONPurchaseToTransaction(payload); assertThat(transaction.getReversalTime()).isCloseTo(new Date(), 100); assertThat(transaction.getReversalText()).isEqualTo(REVERSAL_TEXT_CANCELLED); }
@Test public void marksTransactionAsReversedWhenPurchaseStateIsRefunded() throws Exception { String payload = "{\"packageName\":\"com.app.name\",\"productId\":\"com.app.name.productId\",\n" + " \"purchaseTime\":1466539081315,\"purchaseState\":2,\n" + " \"developerPayload\":\"justSomePayload\",\n" + " \"purchaseToken\":\"randomToken\"}\n"; Transaction transaction = convertJSONPurchaseToTransaction(payload); assertThat(transaction.getReversalTime()).isCloseTo(new Date(), 100); assertThat(transaction.getReversalText()).isEqualTo(REVERSAL_TEXT_REFUNDED); }
@Test public void shouldCreateTransactionForInformationWithoutPriceInCents() throws Exception { Information information = informationFullEditionEntitlementNoPriceInCents(); when(purchaseManager.getInformation(PRODUCT_IDENTIFIER_FULL_EDITION)).thenReturn(information); Transaction transaction = converter.convertToTransaction(activityResultPurchaseFullEditionSuccess()); assertEquals(0, transaction.getPurchaseCost()); assertEquals(INAPP_DATA_SIGNATURE_ACTIVITY_RESULT_SUCCESS, transaction.getTransactionDataSignature()); }
/** * This is the callback for {@link PurchasingService#getPurchaseUpdates}. * * You will receive Entitlement receipts from this callback. * */ @Override public void onPurchaseUpdatesResponse(final PurchaseUpdatesResponse response) { showMessage(LOGTYPELOG, "onPurchaseUpdatesResponse: requestId (" + response.getRequestId() + ") purchaseUpdatesResponseStatus (" + response.getRequestStatus() + ") userId (" + response.getUserData().getUserId() + ")"); final PurchaseUpdatesResponse.RequestStatus status = response.getRequestStatus(); switch (status) { case SUCCESSFUL: updateUserData(response.getUserData()); // for (final Receipt receipt : response.getReceipts()) { // handleReceipt(response.getRequestId().toString(), receipt, response.getUserData()); // } // send result to observer -------- List<Transaction> transactions = new ArrayList<Transaction>(response.getReceipts().size()); Array<Receipt> consumables = new Array<Receipt>(response.getReceipts().size()); for (int i = 0; i < response.getReceipts().size(); i++) { Receipt receipt = response.getReceipts().get(i); // Memoize consumables for later check if (receipt.getProductType() == ProductType.CONSUMABLE) consumables.add(receipt); transactions.add(AmazonTransactionUtils.convertReceiptToTransaction(i, response.getRequestId().toString(), receipt, response.getUserData())); } // send inventory to observer observer.handleRestore(transactions.toArray(new Transaction[transactions.size()])); // Automatically consume consumables if this was not previously the case for (int i = 0; i < consumables.size; i++) { Receipt consumable = consumables.get(i); PurchasingService.notifyFulfillment(consumable.getReceiptId(), FulfillmentResult.FULFILLED); } //---- check if there are more receipts ------- if (response.hasMore()) { PurchasingService.getPurchaseUpdates(false); } break; case FAILED: showMessage(LOGTYPEERROR, "onPurchaseUpdatesResponse: FAILED, should retry request"); observer.handleRestoreError(new Throwable("onPurchaseUpdatesResponse: FAILED, should retry request")); break; case NOT_SUPPORTED: showMessage(LOGTYPEERROR, "onPurchaseUpdatesResponse: NOT_SUPPORTED, should retry request"); observer.handleRestoreError(new Throwable("onPurchaseUpdatesResponse: NOT_SUPPORTED, should retry request")); break; } }
@Override public boolean isValid (Transaction transaction) { // TODO: implement... return true; }
@Override public boolean isValid (Transaction transaction) { // the transaction data is our original == receipt! String receipt = transaction.getTransactionData(); // encode the data final String receiptData = Base64Util.toBase64(receipt.getBytes()); final String jsonData = "{\"receipt-data\" : \"" + receiptData + "\"}"; try { // send the data to Apple final URL url = new URL(sandbox ? SANDBOX_URL : PRODUCTION_URL); final HttpURLConnection conn = (HttpsURLConnection)url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Accept", "application/json"); final OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); wr.write(jsonData); wr.flush(); // obtain the response final BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = rd.readLine(); wr.close(); rd.close(); // verify the response: something like {"status":21004} etc... int status = Integer.parseInt(line.substring(line.indexOf(":") + 1, line.indexOf("}"))); switch (status) { case 0: return true; case 21000: System.out.println(status + ": App store could not read"); return false; case 21002: System.out.println(status + ": Data was malformed"); return false; case 21003: System.out.println(status + ": Receipt not authenticated"); return false; case 21004: System.out.println(status + ": Shared secret does not match"); return false; case 21005: System.out.println(status + ": Receipt server unavailable"); return false; case 21006: System.out.println(status + ": Receipt valid but sub expired"); return false; case 21007: System.out.println(status + ": Sandbox receipt sent to Production environment"); return false; case 21008: System.out.println(status + ": Production receipt sent to Sandbox environment"); return false; default: // unknown error code (nevertheless a problem) System.out.println("Unknown error: status code = " + status); return false; } } catch (IOException e) { // I/O-error: let's assume bad news... System.err.println("I/O error during verification: " + e); e.printStackTrace(); return false; } }
/** Returns true if the transaction was determined valid. */ boolean isValid(Transaction transaction);
public ConsumeException(String message, Transaction transaction, Exception rootCause) { super(message, rootCause); this.transaction = transaction; }
public ConsumeException(String message, Transaction transaction) { this(message, transaction, null); }
@Override public void purchase(final String identifier) { assertInstalled(); final OfferType offerType = getOfferType(identifier); googleInAppBillingService.startPurchaseRequest(identifier, OfferToInAppPurchaseConverter.convertOfferType(offerType), new PurchaseRequestCallback() { @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 purchaseError(GdxPayException exception) { if (observer != null) { observer.handlePurchaseError(exception); } } @Override public void purchaseCanceled() { if (observer != null) { observer.handlePurchaseCanceled(); } } }); }
private boolean isTestPurchase(Transaction transaction) { return transaction.getOrderId() == null || transaction.getOrderId().length() == 0; }
private Transaction convertPurchaseResponseDataToTransaction(Intent responseIntentData) { return purchaseResponseActivityResultConverter.convertToTransaction(responseIntentData); }
public PurchaseConsumer(Transaction transaction, PurchaseObserver observer) { this.transaction = transaction; this.observer = observer; }
public static Transaction transactionFullEditionEuroGooglePlay() { Transaction transaction = transactionFullEditionEuroGooglePlaySandbox(); transaction.setOrderId("GPA.1234-5678-9012-34567"); return transaction; }
public static List<Transaction> convertPurchasesResponseToTransactions(Bundle purchasesResponseBundle) { assertResponseOk(purchasesResponseBundle); ArrayList<String> jsonPurchases = purchasesResponseBundle.getStringArrayList(INAPP_PURCHASE_DATA_LIST); return convertPurchasesToTransactions(jsonPurchases); }
@Test public void purchaseSuccessShouldDelegateResultSuccessToObserver() throws Exception { PurchaseRequestCallback callback = connectBindAndPurchaseRequestForFullEditionEntitlement(); Transaction transaction = transactionFullEditionEuroGooglePlay(); callback.purchaseSuccess(transaction); verify(purchaseObserver).handlePurchase(transaction); }