public void onPurchaseStateChanged(string itemId, PurchaseState state)
 {
     onPurchaseStateChanged(itemId, state);
 }
 public void onPurchaseStateChanged(string itemId, PurchaseState state)
 {
     Log.Info(TAG, "onPurchaseStateChanged() itemId: " + itemId);
     updateOwnedItems();
 }
 /// <summary>
 /// Inserts a purchased product into the database. There may be multiple
 /// rows in the table for the same product if it was purchased multiple times
 /// or if it was refunded. </summary>
 /// <param name="orderId"> the order ID (matches the value in the product list) </param>
 /// <param name="productId"> the product ID (sku) </param>
 /// <param name="state"> the state of the purchase </param>
 /// <param name="purchaseTime"> the purchase time (in milliseconds since the epoch) </param>
 /// <param name="developerPayload"> the developer provided "payload" associated with
 ///     the order. </param>
 private void insertOrder(string orderId, string productId, PurchaseState state, long purchaseTime, string developerPayload)
 {
     ContentValues values = new ContentValues();
     values.Put(HISTORY_ORDER_ID_COL, orderId);
     values.Put(HISTORY_PRODUCT_ID_COL, productId);
     values.Put(HISTORY_STATE_COL, state.ToString());
     values.Put(HISTORY_PURCHASE_TIME_COL, purchaseTime);
     values.Put(HISTORY_DEVELOPER_PAYLOAD_COL, developerPayload);
     mDb.Replace(PURCHASE_HISTORY_TABLE_NAME, null, values); // nullColumnHack
 }
 /// <summary>
 /// Notifies the application of purchase state changes. The application
 /// can offer an item for sale to the user via
 /// <seealso cref="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. </summary>
 /// <param name="purchaseState"> the state of the purchase request (PURCHASED,
 ///     CANCELED, or REFUNDED) </param>
 /// <param name="productId"> a string identifying a product for sale </param>
 /// <param name="orderId"> a string identifying the order </param>
 /// <param name="purchaseTime"> the time the product was purchased, in milliseconds
 ///     since the epoch (Jan 1, 1970) </param>
 /// <param name="developerPayload"> the developer provided "payload" associated with
 ///     the order </param>
 //JAVA TO C# CONVERTER WARNING: 'final' parameters are not allowed in .NET:
 //ORIGINAL LINE: public static void purchaseResponse(final android.content.Context context, final InAppBilling.Consts.PurchaseState purchaseState, final String productId, final String orderId, final long purchaseTime, final String developerPayload)
 public static void purchaseResponse(Context context, PurchaseState purchaseState, string productId, string orderId, long purchaseTime, 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.
     //JAVA TO C# CONVERTER TODO TASK: Anonymous inner classes are not converted to C# if the base type is not defined in the code being converted:
     //			new Thread(new Runnable()
     //		{
     //			public void run()
     //			{
     //				PurchaseDatabase db = new PurchaseDatabase(context);
     //				int quantity = db.updatePurchase(orderId, productId, purchaseState, purchaseTime, developerPayload);
     //				db.close();
     //
     //				// 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, quantity, purchaseTime, developerPayload);
     //					}
     //				}
     //			}
     //		}).start();
 }
        public virtual int updatePurchase(string orderId, string productId, PurchaseState purchaseState, long purchaseTime, string developerPayload)
        {
            insertOrder(orderId, productId, purchaseState, purchaseTime, developerPayload);
            ICursor ICursor = mDb.Query(PURCHASE_HISTORY_TABLE_NAME, HISTORY_COLUMNS, HISTORY_PRODUCT_ID_COL + "=?", new string[] { productId }, null, null, null, null);
            if (ICursor == null)
            {
                return 0;
            }
            int quantity = 0;
            try
            {
                // Count the number of times the product was purchased
                while (ICursor.MoveToNext())
                {
                    int stateIndex = ICursor.GetInt(2);
                    PurchaseState state = (PurchaseState)stateIndex;
                    // Note that a refunded purchase is treated as a purchase. Such
                    // a friendly refund policy is nice for the user.
                    if (state == PurchaseState.PURCHASED || state == PurchaseState.REFUNDED)
                    {
                        quantity += 1;
                    }
                }

                // Update the "purchased items" table
                updatePurchasedItem(productId, quantity);
            }
            catch
            {
                if (ICursor != null)
                {
                    ICursor.Close();
                }
            }
            return quantity;
        }