// Copyright 2010 Google Inc. All Rights Reserved.
package com.todoroo.astrid.billing;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.todoroo.astrid.billing.BillingConstants.PurchaseState;
import com.todoroo.astrid.billing.BillingConstants.ResponseCode;
import com.todoroo.astrid.billing.BillingService.RequestPurchase;
import com.todoroo.astrid.billing.BillingService.RestoreTransactions;
/**
* 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 = "response-handler"; //$NON-NLS-1$
/**
* 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, String type) {
if (sPurchaseObserver != null) {
sPurchaseObserver.onBillingSupported(supported, type);
}
}
/**
* 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 (BillingConstants.DEBUG) {
Log.d(TAG, "UI is not running"); //$NON-NLS-1$
}
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, final String purchaseToken) {
new Thread(new Runnable() {
@Override
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, purchaseToken);
}
}
}
}).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);
}
}
}