// Copyright 2010 Google Inc. All Rights Reserved. package com.godsandtowers.billing.google; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.util.Log; import com.godsandtowers.billing.google.BillingService.RequestPurchase; import com.godsandtowers.billing.google.BillingService.RestoreTransactions; import com.godsandtowers.billing.google.Consts.PurchaseState; import com.godsandtowers.billing.google.Consts.ResponseCode; /** * This class contains the methods that handle responses from Android Market. The implementation of these methods is * specific to a particular application. The methods in this example update the database and, if the main application * has registered a {@llink PurchaseObserver}, will also update the UI. An application might also want to forward some * responses on to its own server, and that could be done here (in a background thread) but this example does not do * that. * * You should modify and obfuscate this code before using it. */ public class ResponseHandler { private static final String TAG = "ResponseHandler"; /** * This is a static instance of {@link PurchaseObserver} that the application creates and registers with this class. * The PurchaseObserver is used for updating the UI if the UI is visible. */ private static PurchaseObserver sPurchaseObserver; /** * Registers an observer that updates the UI. * * @param observer * the observer to register */ public static synchronized void register(PurchaseObserver observer) { sPurchaseObserver = observer; } /** * Unregisters a previously registered observer. * * @param observer * the previously registered observer. */ public static synchronized void unregister(PurchaseObserver observer) { sPurchaseObserver = null; } /** * Notifies the application of the availability of the MarketBillingService. This method is called in response to * the application calling {@link BillingService#checkBillingSupported()}. * * @param supported * true if in-app billing is supported. */ public static void checkBillingSupportedResponse(boolean supported) { if (sPurchaseObserver != null) { sPurchaseObserver.onBillingSupported(supported); } } /** * Starts a new activity for the user to buy an item for sale. This method forwards the intent on to the * PurchaseObserver (if it exists) because we need to start the activity on the activity stack of the application. * * @param pendingIntent * a PendingIntent that we received from Android Market that will create the new buy page activity * @param intent * an intent containing a request id in an extra field that will be passed to the buy page activity when * it is created */ public static void buyPageIntentResponse(PendingIntent pendingIntent, Intent intent) { if (sPurchaseObserver == null) { if (Consts.DEBUG) { Log.d(TAG, "UI is not running"); } return; } sPurchaseObserver.startBuyPageActivity(pendingIntent, intent); } /** * Notifies the application of purchase state changes. The application can offer an item for sale to the user via * {@link BillingService#requestPurchase(String)}. The BillingService calls this method after it gets the response. * Another way this method can be called is if the user bought something on another device running this same app. * Then Android Market notifies the other devices that the user has purchased an item, in which case the * BillingService will also call this method. Finally, this method can be called if the item was refunded. * * @param purchaseState * the state of the purchase request (PURCHASED, CANCELED, or REFUNDED) * @param productId * a string identifying a product for sale * @param orderId * a string identifying the order * @param purchaseTime * the time the product was purchased, in milliseconds since the epoch (Jan 1, 1970) * @param developerPayload * the developer provided "payload" associated with the order */ public static void purchaseResponse(final Context context, final PurchaseState purchaseState, final String productId, final String orderId, final long purchaseTime, final String developerPayload) { // Update the database with the purchase state. We shouldn't do that // from the main thread so we do the work in a background thread. // We don't update the UI here. We will update the UI after we update // the database because we need to read and update the current quantity // first. new Thread(new Runnable() { public void run() { // This needs to be synchronized because the UI thread can change the // value of sPurchaseObserver. synchronized (ResponseHandler.class) { if (sPurchaseObserver != null) { sPurchaseObserver.postPurchaseStateChange(purchaseState, productId, 1, purchaseTime, developerPayload); } } } }).start(); } /** * This is called when we receive a response code from Android Market for a RequestPurchase request that we made. * This is used for reporting various errors and also for acknowledging that an order was sent successfully to the * server. This is NOT used for any purchase state changes. All purchase state changes are received in the * {@link BillingReceiver} and are handled in {@link Security#verifyPurchase(String, String)}. * * @param context * the context * @param request * the RequestPurchase request for which we received a response code * @param responseCode * a response code from Market to indicate the state of the request */ public static void responseCodeReceived(Context context, RequestPurchase request, ResponseCode responseCode) { if (sPurchaseObserver != null) { sPurchaseObserver.onRequestPurchaseResponse(request, responseCode); } } /** * This is called when we receive a response code from Android Market for a RestoreTransactions request. * * @param context * the context * @param request * the RestoreTransactions request for which we received a response code * @param responseCode * a response code from Market to indicate the state of the request */ public static void responseCodeReceived(Context context, RestoreTransactions request, ResponseCode responseCode) { if (sPurchaseObserver != null) { sPurchaseObserver.onRestoreTransactionsResponse(request, responseCode); } } }