Skip to content

update util & IInAppBillingService according to TrivialDrive #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,45 @@ interface IInAppBillingService {
* @return 0 if consumption succeeded. Appropriate error values for failures.
*/
int consumePurchase(int apiVersion, String packageName, String purchaseToken);
}

/**
* Returns an intent to launch the purchase flow for an in-app item by providing a SKU,
* the type, a unique purchase token and an optional developer payload.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type the type of the in-app item ("inapp" for one-time purchases
* and "subs" for subscription).
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "BUY_INTENT" - Intent to start the purchase flow
*
* The intent should be launched with startActivityForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
* TODO: change this to app-specific keys.
*/
Bundle getBuyIntentV2(int apiVersion, String packageName, String sku, String type,
String developerPayload);

/**
* Returns the config of purchase.
*
* @return Bundle containing the following key-value pair
* "INTENT_V2_SUPPORT" with boolean value
*/
Bundle getPurchaseConfig(int apiVersion);
}
119 changes: 92 additions & 27 deletions android/app/src/main/java/com/contoriel/cafebazaar/util/IabHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.IntentSender;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
Expand Down Expand Up @@ -141,6 +143,9 @@ public class IabHelper {
public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";

// Keys for the response from getPurchaseConfig
private static final String INTENT_V2_SUPPORT = "INTENT_V2_SUPPORT";

// Item types
public static final String ITEM_TYPE_INAPP = "inapp";
public static final String ITEM_TYPE_SUBS = "subs";
Expand Down Expand Up @@ -264,7 +269,10 @@ public void onServiceConnected(ComponentName name, IBinder service) {

Intent serviceIntent = new Intent("ir.cafebazaar.pardakht.InAppBillingService.BIND");
serviceIntent.setPackage("com.farsitel.bazaar");
if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {

PackageManager pm=mContext.getPackageManager();
List<ResolveInfo> intentServices = pm.queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) {
// service available to handle that Intent
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}
Expand All @@ -289,7 +297,9 @@ public void dispose() {
mSetupDone = false;
if (mServiceConn != null) {
logDebug("Unbinding from service.");
if (mContext != null && mService != null) mContext.unbindService(mServiceConn);
if (mContext != null && mService != null) {
mContext.unbindService(mServiceConn);
}
}
mDisposed = true;
mContext = null;
Expand Down Expand Up @@ -383,35 +393,26 @@ public void launchPurchaseFlow(Activity act, String sku, String itemType, int re

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));
flagEndAsync();
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) {
int apiVersion = 3;
String packageName = mContext.getPackageName();

Bundle configBundle = mService.getPurchaseConfig(apiVersion);
if (configBundle != null && configBundle.getBoolean(INTENT_V2_SUPPORT)) {
logDebug("launchBuyIntentV2 for " + sku + ", item type: " + itemType);
launchBuyIntentV2(act, sku, itemType, requestCode, listener, extraData);
} else {
logDebug("launchBuyIntent for " + sku + ", item type: " + itemType);
launchBuyIntent(act, sku, itemType, requestCode, listener, extraData);
}
} catch (IntentSender.SendIntentException e) {
logError("SendIntentException while launching purchase flow for sku " + sku);
e.printStackTrace();
flagEndAsync();

result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.");
if (listener != null) listener.onIabPurchaseFinished(result, null);
}
catch (RemoteException e) {
} catch (RemoteException e) {
logError("RemoteException while launching purchase flow for sku " + sku);
e.printStackTrace();
flagEndAsync();
Expand All @@ -421,6 +422,69 @@ requestCode, new Intent(),
}
}

private void launchBuyIntentV2(
Activity act,
String sku,
String itemType,
int requestCode,
OnIabPurchaseFinishedListener listener,
String extraData
) throws RemoteException {
int apiVersion = 3;
String packageName = mContext.getPackageName();

Bundle buyIntentBundle = mService.getBuyIntentV2(apiVersion, packageName, sku, itemType, extraData);
int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) {
logError("Unable to buy item, Error response: " + getResponseDesc(response));
flagEndAsync();
IabResult result = new IabResult(response, "Unable to buy item");
if (listener != null) listener.onIabPurchaseFinished(result, null);
return;
}

Intent intent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
mRequestCode = requestCode;
mPurchaseListener = listener;
mPurchasingItemType = itemType;
act.startActivityForResult(intent, requestCode);
}

private void launchBuyIntent(
Activity act,
String sku,
String itemType,
int requestCode,
OnIabPurchaseFinishedListener listener,
String extraData
) throws RemoteException, IntentSender.SendIntentException {

int apiVersion = 3;
String packageName = mContext.getPackageName();

Bundle buyIntentBundle = mService.getBuyIntent(apiVersion, packageName, sku, itemType, extraData);
int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) {
logError("Unable to buy item, Error response: " + getResponseDesc(response));
flagEndAsync();
IabResult 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));
}

/**
* Handles an activity result that's part of the purchase flow in in-app billing. If you
* are calling {@link #launchPurchaseFlow}, then you must call this method from your
Expand Down Expand Up @@ -525,7 +589,7 @@ public Inventory queryInventory(boolean querySkuDetails, List<String> moreSkus)
/**
* Queries the inventory. This will query all owned items from the server, as well as
* information on additional skus, if specified. This method may block or take long to execute.
* Do not call from a UI thread. For that, use the non-blocking version {@link #refreshInventoryAsync}.
* Do not call from a UI thread.
*
* @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well
* as purchase information.
Expand Down Expand Up @@ -730,7 +794,8 @@ public void consumeAsync(Purchase purchase, OnConsumeFinishedListener listener)
}

/**
* Same as {@link consumeAsync}, but for multiple items at once.
* Same as {@link #consumeAsync(Purchase, OnConsumeFinishedListener)}, but for multiple items at once.
*
* @param purchases The list of PurchaseInfo objects representing the purchases to consume.
* @param listener The listener to notify when the consumption operation finishes.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.String;

/**
* Represents a block of information about in-app items.
Expand Down Expand Up @@ -78,7 +77,7 @@ List<String> getAllOwnedSkus(String itemType) {
}

/** Returns a list of all purchases. */
public List<Purchase> getAllPurchases() {
List<Purchase> getAllPurchases() {
return new ArrayList<Purchase>(mPurchaseMap.values());
}

Expand Down