static void insertPurchases( @Nonnull Billing billing, @Nonnull String product, @Nonnull List<Purchase> purchases) throws RemoteException { final Bundle bundle = newBundle(OK); final ArrayList<String> list = new ArrayList<String>(); for (Purchase purchase : purchases) { list.add(purchase.toJson()); } bundle.putStringArrayList(Purchases.BUNDLE_DATA_LIST, list); final IInAppBillingService service = ((TestServiceConnector) billing.getConnector()).service; when(service.getPurchases(anyInt(), anyString(), eq(product), isNull(String.class))) .thenReturn(bundle); }
@Click(R.id.get_purchases_button) public void getPurchases(View v) { try { Bundle ownedItems; ownedItems = billingService.getPurchases(apiLevel, getPackageName(), "inapp", null); if (ownedItems.getInt("RESPONSE_CODE") != 0) { logView.append("getPurchases Fail\n"); return; } ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); if (purchaseDataList.size() == 0) { logView.append("getPurchases empty\n"); } for (String purchaseData : purchaseDataList) { logView.append("getPurchases: " + purchaseData + "\n"); } } catch (RemoteException e) { String msg = "getPurchases: " + e.getMessage() + "\n"; logView.append(msg); Log.e(TAG, msg); e.printStackTrace(); } }
int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { // Query purchases logDebug("Querying owned items, item type: " + itemType); logDebug("Package name: " + mContext.getPackageName()); boolean verificationFailed = false; String continueToken = null; do { logDebug("Calling getPurchases with continuation token: " + continueToken); Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), itemType, continueToken); int response = getResponseCodeFromBundle(ownedItems); logDebug("Owned items response: " + String.valueOf(response)); if (response != BILLING_RESPONSE_RESULT_OK) { logDebug("getPurchases() failed: " + getResponseDesc(response)); return response; } if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) { logError("Bundle returned from getPurchases() doesn't contain required fields."); return IABHELPER_BAD_RESPONSE; } ArrayList<String> ownedSkus = ownedItems.getStringArrayList(RESPONSE_INAPP_ITEM_LIST); ArrayList<String> purchaseDataList = ownedItems.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST); ArrayList<String> signatureList = ownedItems.getStringArrayList(RESPONSE_INAPP_SIGNATURE_LIST); for (int i = 0; i < purchaseDataList.size(); ++i) { String purchaseData = purchaseDataList.get(i); String signature = signatureList.get(i); String sku = ownedSkus.get(i); if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) { logDebug("Sku is owned: " + sku); Purchase purchase = new Purchase(itemType, purchaseData, signature); if (TextUtils.isEmpty(purchase.getToken())) { logWarn("BUG: empty/null token!"); logDebug("Purchase data: " + purchaseData); } // Record ownership and token inv.addPurchase(purchase); } else { logWarn("Purchase signature verification **FAILED**. Not adding item."); logDebug(" Purchase data: " + purchaseData); logDebug(" Signature: " + signature); verificationFailed = true; } } continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN); logDebug("Continuation token: " + continueToken); } while (!TextUtils.isEmpty(continueToken)); return verificationFailed ? IABHELPER_VERIFICATION_FAILED : BILLING_RESPONSE_RESULT_OK; }
/** * Consumes a given in-app product. Consuming can only be done on an item that's owned, and as a * result of consumption, the user will no longer own it. This method may block or take long to * return. Do not call from the UI thread. For that, see {@link #consumeAsync}. * * @param itemInfo The PurchaseInfo that represents the item to consume. * @throws IabException if there is a problem during consumption. */ void consume(Purchase itemInfo) throws IabException { checkSetupDone("consume"); try { String token = itemInfo.getToken(); String sku = itemInfo.getSku(); if (token == null || token.equals("")) { logError("Can't consume " + sku + ". No token."); throw new IabException( IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " + sku + " " + itemInfo); } logDebug("Consuming sku: " + sku + ", token: " + token); int response = mService.consumePurchase(BILLING_API_VERSION, mContext.getPackageName(), token); if (response == BILLING_RESPONSE_RESULT_OK) { logDebug("Successfully consumed sku: " + sku); } else { logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); throw new IabException(response, "Error consuming sku " + sku); } } catch (RemoteException e) { throw new IabException( IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e); } }
@Override public void queryPurchases(Preferences pref) { this.pref = pref; try { Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null); int response = ownedItems.getInt("RESPONSE_CODE"); if (response == 0) { ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST"); for (int i = 0; i < ownedSkus.size(); i++) { String name = null; if (ownedSkus.get(i).equals("ryan")) name = "Ryan"; else if (ownedSkus.get(i).equals("ash")) name = "Ash"; else if (ownedSkus.get(i).equals("rob")) name = "Rob"; else if (ownedSkus.get(i).equals("battle_cat")) name = "BattleCat"; else if (ownedSkus.get(i).equals("xorp")) name = "Xorp"; else if (ownedSkus.get(i).equals("rootsworth")) name = "Rootsworth"; else if (ownedSkus.get(i).equals("snap")) name = "Snap"; else if (ownedSkus.get(i).equals("metatron")) name = "Metatron"; else if (ownedSkus.get(i).equals("abaddon")) name = "Abaddon"; pref.putBoolean(name, true); pref.flush(); } } } catch (RemoteException e) { e.printStackTrace(); } }
@Override public void onServiceConnected(ComponentName name, IBinder service) { billingService = IInAppBillingService.Stub.asInterface(service); String packageName = context.getPackageName(); try { // check for in-app billing v3 support int response = billingService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP); if (response != BILLING_RESPONSE_RESULT_OK) { if (listener != null) { listener.onSetupFinished( new Result(response, "Error checking for billing v3 support.")); } return; } } catch (RemoteException e) { if (listener != null) { listener.onSetupFinished( new Result( HELPER_REMOTE_EXCEPTION, "RemoteException while setting up in-app billing.")); } e.printStackTrace(); return; } if (listener != null) { listener.onSetupFinished(new Result(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); } }
@Click(R.id.get_buy_intent_button) public void getBuyIntent(View v) { try { Bundle buyIntentBundle = billingService.getBuyIntent( apiLevel, getPackageName(), skuName, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ"); PendingIntent buyIntent = buyIntentBundle.getParcelable("BUY_INTENT"); MainActivity.this.startIntentSenderForResult( buyIntent.getIntentSender(), requestCode, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); } catch (Exception e) { String msg = "getBuyIntent: " + e.getMessage() + "\n"; logView.append(msg); Log.e(TAG, msg); e.printStackTrace(); } }
/** * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase, * which will involve bringing up the Google Play screen. The calling activity will be paused * while the user interacts with Google Play, and the result will be delivered via the activity's * {@link android.app.Activity#onActivityResult} method, at which point you must call this * object's {@link #handleActivityResult} method to continue the purchase flow. This method MUST * be called from the UI thread of the Activity. * * @param act The calling activity. * @param sku The sku of the item to purchase. * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or * ITEM_TYPE_SUBS) * @param requestCode A request code (to differentiate from other responses -- as in {@link * android.app.Activity#startActivityForResult}). * @param listener The listener to notify when the purchase process finishes * @param extraData Extra data (developer payload), which will be returned with the purchase data * when the purchase completes. This extra data will be permanently bound to that purchase and * will always be returned when the purchase is queried. */ public void launchPurchaseFlow( Activity act, String sku, String itemType, int requestCode, OnIabPurchaseFinishedListener listener, String extraData) { checkSetupDone("launchPurchaseFlow"); flagStartAsync("launchPurchaseFlow"); IabResult result; if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) { IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, "Subscriptions are not available."); if (listener != null) listener.onIabPurchaseFinished(r, null); return; } try { logDebug("Constructing buy intent for " + sku + ", item type: " + itemType); Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, extraData); int response = getResponseCodeFromBundle(buyIntentBundle); if (response != BILLING_RESPONSE_RESULT_OK) { logError("Unable to buy item, Error response: " + getResponseDesc(response)); result = new IabResult(response, "Unable to buy item"); if (listener != null) listener.onIabPurchaseFinished(result, null); return; } PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT); logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode); mRequestCode = requestCode; mPurchaseListener = listener; mPurchasingItemType = itemType; act.startIntentSenderForResult( pendingIntent.getIntentSender(), requestCode, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); } catch (SendIntentException e) { logError("SendIntentException while launching purchase flow for sku " + sku); e.printStackTrace(); result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent."); if (listener != null) listener.onIabPurchaseFinished(result, null); } catch (RemoteException e) { logError("RemoteException while launching purchase flow for sku " + sku); e.printStackTrace(); result = new IabResult( IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow"); if (listener != null) listener.onIabPurchaseFinished(result, null); } }
public void purchase(final String sku, final String transactionId) { Log.d("XXX", "Starting purchase for: " + sku); PaymentsCache pc = new PaymentsCache(context); Boolean isBlocked = pc.getConsumableFlag("block", sku); // if(isBlocked){ // Log.d("XXX", "Is awaiting payment confirmation"); // error("Awaiting payment confirmation"); // return; // } final String hash = transactionId; Bundle buyIntentBundle; try { buyIntentBundle = mService.getBuyIntent( 3, context.getApplicationContext().getPackageName(), sku, "inapp", hash); } catch (RemoteException e) { // Log.d("XXX", "Error: " + e.getMessage()); error(e.getMessage()); return; } Object rc = buyIntentBundle.get("RESPONSE_CODE"); int responseCode = 0; if (rc == null) { responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK; } else if (rc instanceof Integer) { responseCode = ((Integer) rc).intValue(); } else if (rc instanceof Long) { responseCode = (int) ((Long) rc).longValue(); } // Log.d("XXX", "Buy intent response code: " + responseCode); if (responseCode == 1 || responseCode == 3 || responseCode == 4) { canceled(); return; } PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); pc.setConsumableValue("validation_hash", sku, hash); try { if (context == null) { // Log.d("XXX", "No context!"); } if (pendingIntent == null) { // Log.d("XXX", "No pending intent"); } // Log.d("XXX", "Starting activity for purchase!"); context.startIntentSenderForResult( pendingIntent.getIntentSender(), PaymentsManager.REQUEST_CODE_FOR_PURCHASE, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); } catch (SendIntentException e) { error(e.getMessage()); } }
@Override public void consume(@NonNull Purchase purchase) throws BillingException { try { int rc = delegate.consumePurchase(3, packageName, purchase.purchaseToken()); BillingException.checkCode(rc); } catch (RemoteException e) { throw new UnsupportedOperationException(e); } }
@Override public boolean arePurchasesSupported(@NonNull @ProductType String type) throws BillingException { try { int rc = delegate.isBillingSupported(API_VERSION, packageName, type); BillingException.checkCode(rc); return true; } catch (RemoteException e) { throw new BillingException(e); } }
/** * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase, * which will involve bringing up the Google Play screen. The calling activity will be paused * while the user interacts with Google Play, and the result will be delivered via the activity's * {@link android.app.Activity#onActivityResult} method, at which point you must call this * object's {@link #handleActivityResult} method to continue the purchase flow. This method MUST * be called from the UI thread of the Activity. * * @param act The calling activity. * @param sku The sku of the item to purchase. * @param requestCode A request code (to differentiate from other responses -- as in {@link * android.app.Activity#startActivityForResult}). * @param listener The listener to notify when the purchase process finishes * @param extraData Extra data (developer payload), which will be returned with the purchase data * when the purchase completes. This extra data will be permanently bound to that purchase and * will always be returned when the purchase is queried. */ public void launchPurchaseFlow( Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData) { checkSetupDone("launchPurchaseFlow"); flagStartAsync("launchPurchaseFlow"); IabResult result; try { logDebug("Constructing buy intent for " + sku); Bundle buyIntentBundle = mService.getBuyIntent( BILLING_API_VERSION, mContext.getPackageName(), sku, ITEM_TYPE_INAPP, extraData); int response = getResponseCodeFromBundle(buyIntentBundle); if (response != BILLING_RESPONSE_RESULT_OK) { logError("Unable to buy item, Error response: " + getResponseDesc(response)); result = new IabResult(response, "Unable to buy item", requestCode); if (listener != null) listener.onIabPurchaseFinished(result, null); } else { PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT); logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode); SYSLOG("MoSync Launching buy intent for " + sku + ". Request code: " + requestCode); mRequestCode = requestCode; mPurchaseListener = listener; act.startIntentSenderForResult( pendingIntent.getIntentSender(), requestCode, new Intent(Consts.METHOD_REQUEST_PURCHASE), 0, 0, 0); } } catch (SendIntentException e) { logError("SendIntentException while launching purchase flow for sku " + sku); SYSLOG("MoSync SendIntentException while launching purchase flow for sku " + sku); e.printStackTrace(); result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.", requestCode); if (listener != null) listener.onIabPurchaseFinished(result, null); } catch (RemoteException e) { logError("RemoteException while launching purchase flow for sku " + sku); SYSLOG("MoSync RemoteException while launching purchase flow for sku " + sku); e.printStackTrace(); result = new IabResult( IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow", requestCode); if (listener != null) listener.onIabPurchaseFinished(result, null); } }
@Click(R.id.consume_purchase) public void consumePurchase(View v) { try { Bundle ownedItems = billingService.getPurchases(apiLevel, getPackageName(), "inapp", null); ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); for (String purchaseData : purchaseDataList) { JSONObject obj = new JSONObject(purchaseData); String purchaseToken = obj.optString("token", obj.optString("purchaseToken")); billingService.consumePurchase(apiLevel, getPackageName(), purchaseToken); logView.append("消費しました\n"); } } catch (Exception e) { String msg = "getPurchases: " + e.getMessage() + "\n"; logView.append(msg); Log.e(TAG, msg); e.printStackTrace(); } }
@Click(R.id.billing_supported_button) public void billingSupported(View v) { try { int result = billingService.isBillingSupported(apiLevel, getPackageName(), "inapp"); String msg = "isBillingSupported:" + responseCode(result) + "\n"; logView.append(msg); Log.d(TAG, msg); } catch (RemoteException e) { String msg = "isBillingSupported:" + e.getMessage() + "\n"; logView.append(msg); Log.e(TAG, msg); e.printStackTrace(); } }
@Override public void makePurchase(String itemID, Preferences pref) { this.pref = pref; try { Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), itemID, "inapp", null); PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); startIntentSenderForResult( pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); } catch (RemoteException e) { e.printStackTrace(); } catch (SendIntentException e) { e.printStackTrace(); } }
@NonNull @Override public PendingIntent getProductBuyIntent( @NonNull @ProductType String type, @NonNull String sku, @Nullable String developerPayload) throws BillingException { try { Bundle response = delegate.getBuyIntent(API_VERSION, packageName, sku, type, developerPayload); checkBundle(response); //noinspection UnnecessaryLocalVariable PendingIntent pendingIntent = response.getParcelable("BUY_INTENT"); if (pendingIntent == null) { throw new BillingException.UnexpectedDataException("BUY_INTENT == null"); } return pendingIntent; } catch (RemoteException e) { throw new BillingException(e); } }
/** Get sku details for an item that is not in the inventory. */ public SkuDetails getSkuDetails(String sku) throws IabException { logDebug("Querying SKU details for one item."); SYSLOG("MoSync Querying SKU details for one item: " + sku); Bundle querySkus = new Bundle(); ArrayList<String> skuList = new ArrayList<String>(); skuList.add(sku); querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList); try { Bundle skuDetails = mService.getSkuDetails( BILLING_API_VERSION, mContext.getPackageName(), ITEM_TYPE_INAPP, querySkus); if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) { int response = getResponseCodeFromBundle(skuDetails); SYSLOG("@@MoSync maPurchaseCreate querySkuDetails response error " + response); if (response != BILLING_RESPONSE_RESULT_OK) { logDebug("getSkuDetails() failed: " + getResponseDesc(response)); } else { logError("getSkuDetails() returned a bundle with neither an error nor a detail list."); } return null; } ArrayList<String> responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST); for (String thisResponse : responseList) { SkuDetails details = new SkuDetails(thisResponse); logDebug("Got sku details: " + details); return details; } return null; } catch (RemoteException e) { SYSLOG("@@MoSync remote exception while getting sku details"); throw new IabException( IABHELPER_REMOTE_EXCEPTION, "Remote exception while getting sku details.", e); } catch (JSONException e) { SYSLOG("@@MoSync JSON exception while getting sku details"); throw new IabException( IABHELPER_BAD_RESPONSE, "Error parsing JSON response while getting sku details.", e); } }
int querySkuDetails(String itemType, Inventory inv, List<String> moreSkus) throws RemoteException, JSONException { logDebug("Querying SKU details."); ArrayList<String> skuList = new ArrayList<String>(); skuList.addAll(inv.getAllOwnedSkus(itemType)); if (moreSkus != null) { for (String sku : moreSkus) { if (!skuList.contains(sku)) { skuList.add(sku); } } } if (skuList.size() == 0) { logDebug("queryPrices: nothing to do because there are no SKUs."); return BILLING_RESPONSE_RESULT_OK; } Bundle querySkus = new Bundle(); querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList); Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), itemType, querySkus); if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) { int response = getResponseCodeFromBundle(skuDetails); if (response != BILLING_RESPONSE_RESULT_OK) { logDebug("getSkuDetails() failed: " + getResponseDesc(response)); return response; } else { logError("getSkuDetails() returned a bundle with neither an error nor a detail list."); return IABHELPER_BAD_RESPONSE; } } ArrayList<String> responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST); for (String thisResponse : responseList) { SkuDetails d = new SkuDetails(itemType, thisResponse); logDebug("Got sku details: " + d); inv.addSkuDetails(d); } return BILLING_RESPONSE_RESULT_OK; }
@NonNull @Override public ReceiptResponse getProductPurchases( @NonNull @ProductType String type, String continueToken) throws BillingException { try { Bundle data = delegate.getPurchases(API_VERSION, packageName, type, continueToken); checkBundle(data); ArrayList<String> skus = data.getStringArrayList("INAPP_PURCHASE_ITEM_LIST"); ArrayList<String> purchases = data.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); ArrayList<String> signatures = data.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); String nextToken = data.getString("INAPP_CONTINUATION_TOKEN"); if (skus == null || purchases == null || signatures == null || skus.size() != purchases.size() || purchases.size() != signatures.size()) { throw new BillingException("unexpected data in response"); } List<Receipt> receipts = new ArrayList<>(skus.size()); for (int i = 0; i < skus.size(); i++) { String json = purchases.get(i); String signature = signatures.get(i); Purchase purchase = gson.fromJson(json, Purchase.class); Receipt receipt = new Receipt.Builder() .purchase(purchase) .signature(signature) .originalJson(json) .build(); receipts.add(receipt); } return ReceiptResponse.Factory.make(receipts, nextToken); } catch (RemoteException e) { throw new BillingException(e); } }
@Click(R.id.get_sku_details_button) public void getSkuDetails(View v) { try { ArrayList<String> itemList = new ArrayList<String>(); itemList.add(skuName); Bundle skusBundle = new Bundle(); skusBundle.putStringArrayList("ITEM_ID_LIST", itemList); Bundle details = billingService.getSkuDetails(apiLevel, getPackageName(), "inapp", skusBundle); int responseCode = details.getInt("RESPONSE_CODE"); ArrayList<String> responseList = details.getStringArrayList("DETAILS_LIST"); if (responseList.size() == 0) { String msg = "getSkuDetails: empty" + "\n"; ; logView.append(msg); Log.d(TAG, msg); } for (String info : responseList) { String msg = "getSkuDetails: " + info + "\n"; ; logView.append(msg); Log.d(TAG, msg); } } catch (RemoteException e) { String msg = "getSkuDetails: " + e.getMessage() + "\n"; logView.append(msg); Log.e(TAG, msg); e.printStackTrace(); } }
@NonNull @Override public List<Product> getProductDetails(@NonNull @ProductType String type, List<String> skuList) throws BillingException { try { Bundle skuBundle = new Bundle(); skuBundle.putStringArrayList("ITEM_ID_LIST", new ArrayList<>(skuList)); Bundle response = delegate.getSkuDetails(API_VERSION, packageName, type, skuBundle); checkBundle(response); List<String> jsons = response.getStringArrayList("DETAILS_LIST"); if (jsons == null) { return Collections.emptyList(); } List<Product> products = new ArrayList<>(jsons.size()); for (String json : jsons) { Product product = gson.fromJson(json, Product.class); products.add(product); } return products; } catch (RemoteException e) { throw new BillingException(e); } }
public Bundle getBuyIntent(String sku, String extraData) throws RemoteException { return billingService.getBuyIntent( 3, context.getPackageName(), sku, ITEM_TYPE_INAPP, extraData); }
public Bundle getPurchases(String continueToken) throws RemoteException { return billingService.getPurchases( 3, context.getPackageName(), ITEM_TYPE_INAPP, continueToken); }
public Bundle getSkuDetails(Bundle querySkus) throws RemoteException { return billingService.getSkuDetails(3, context.getPackageName(), ITEM_TYPE_INAPP, querySkus); }