package com.jdroid.android.google.inappbilling; import com.jdroid.android.google.inappbilling.Purchase.PurchaseState; import org.json.JSONException; public class Product { public enum ItemType { MANAGED("inapp"), SUBSCRIPTION("subs"); private String type; ItemType(String type) { this.type = type; } public String getType() { return type; } } private ProductType productType; private String title; private String description; private Purchase purchase; private Boolean available; private String formattedPrice; private Double price; private String currencyCode; public Product(ProductType productType, String formattedPrice, Double price, String currencyCode, String title, String description) { this.productType = productType; this.title = title; this.description = description; this.formattedPrice = formattedPrice; this.price = price; this.currencyCode = currencyCode; available = true; } /** * @return the Formatted price of the item, including its currency sign. The price does not include tax. */ public String getFormattedPrice() { return formattedPrice; } public Double getPrice() { return price; } /** * @return the title */ public String getTitle() { return title; } /** * @return the description */ public String getDescription() { return description; } /** * @return the productType */ public ProductType getProductType() { return productType; } public void setPurchase(String signatureBase64, String jsonPurchaseInfo, String signature) throws JSONException { available = false; purchase = new Purchase(jsonPurchaseInfo, signature); if (Security.verifyPurchase(signatureBase64, jsonPurchaseInfo, signature)) { if (!verifyDeveloperPayload()) { throw InAppBillingErrorCode.VERIFICATION_FAILED.newErrorCodeException("Purchase developer payload verification FAILED. " + jsonPurchaseInfo); } } else { throw InAppBillingErrorCode.VERIFICATION_FAILED.newErrorCodeException("Purchase signature verification FAILED. " + jsonPurchaseInfo); } purchase.markAsVerified(); } public Boolean isPurchaseVerified() { return (purchase != null) && (purchase.getState() == PurchaseState.PURCHASED) && purchase.isVerified(); } public Boolean isAvailable() { return available; } public void consume() { purchase = null; available = true; } public Boolean isWaitingToConsume() { return productType.isConsumable() && !available && isPurchaseVerified(); } public String getDeveloperPayload() { /* * TODO: for security, generate your payload here for verification. See the comments on verifyDeveloperPayload() * for more info. Since this is a SAMPLE, we just use an empty string, but on a production app you should * carefully generate this. */ return productType.getProductId(); } /** * Verifies the developer payload of a purchase. * * @return */ protected Boolean verifyDeveloperPayload() { String payload = purchase.getDeveloperPayload(); /* * TODO: verify that the developer payload of the purchase is correct. It will be the same one that you sent * when initiating the purchase. WARNING: Locally generating a random string when starting a purchase and * verifying it here might seem like a good approach, but this will fail in the case where the user purchases an * item on one device and then uses your app on a different device, because on the other device you will not * have access to the random string you originally generated. So a good developer payload has these * characteristics: 1. If two different users purchase an item, the payload is different between them, so that * one user's purchase can't be replayed to another user. 2. The payload must be such that you can verify it * even when the app wasn't the one who initiated the purchase flow (so that items purchased by the user on one * device work on other devices owned by the user). Using your own server to store and verify developer payloads * across app installations is recommended. */ return purchase.getProductId().equals(payload); } /** * @return the purchase */ public Purchase getPurchase() { return purchase; } public String getCurrencyCode() { return currencyCode; } public String getId() { return getProductType().getProductId(); } @Override public String toString() { return "Product [productType=" + productType + ", title=" + title + ", description=" + description + ", purchase=" + purchase + ", available=" + available + ", formattedPrice=" + formattedPrice + ", price=" + price + ", currencyCode=" + currencyCode + "]"; } }