Skip to content

Commit

Permalink
Closes #17. Closes #13. Closes #6.
Browse files Browse the repository at this point in the history
  • Loading branch information
Robot Media committed Jul 13, 2011
1 parent 43c874f commit 3a5e5f9
Show file tree
Hide file tree
Showing 30 changed files with 767 additions and 55 deletions.
Expand Up @@ -29,6 +29,7 @@
import net.robotmedia.billing.model.TransactionManager;
import net.robotmedia.billing.request.BillingRequest;
import net.robotmedia.billing.request.ResponseCode;
import net.robotmedia.billing.request.RestoreTransactions;
import net.robotmedia.billing.utils.Compatibility;
import net.robotmedia.billing.utils.Security;

Expand Down Expand Up @@ -427,6 +428,8 @@ protected static void onPurchaseStateChanged(Context context, String signedData,
}
}

private static HashMap<Long, BillingRequest> pendingRequests = new HashMap<Long, BillingRequest>();

/**
* Called after a {@link net.robotmedia.billing.request.BillingRequest} is
* sent.
Expand All @@ -440,14 +443,16 @@ protected static void onRequestSent(long requestId, BillingRequest request) {
if (debug) {
Log.d(BillingController.class.getSimpleName(), "Request " + requestId + " of type " + request.getRequestType() + " sent");
}
if (!request.isSuccess() && request.hasNonce()) {
if (request.isSuccess()) {
pendingRequests.put(requestId, request);
} else if (request.hasNonce()) {
Security.removeNonce(request.getNonce());
}
}

/**
* Called after a {@link net.robotmedia.billing.request.BillingRequest} is
* sent. Mostly used for debugging purposes.
* sent.
*
* @param context
* @param requestId
Expand All @@ -460,6 +465,11 @@ protected static void onResponseCode(Context context, long requestId, int respon
if (debug) {
Log.d(BillingController.class.getSimpleName(), "Request " + requestId + " received response " + ResponseCode.valueOf(responseCode));
}
final BillingRequest request = pendingRequests.get(requestId);
if (request != null) {
pendingRequests.remove(requestId);
request.onResponseCode(responseCode);
}
}

/**
Expand Down Expand Up @@ -639,4 +649,14 @@ private static boolean verifyNonce(JSONObject data) {
}
}

/**
*
* @param restoreTransactions
*/
public static void onTransactionsRestored(RestoreTransactions restoreTransactions) {
for (IBillingObserver o : observers) {
o.onTransactionsRestored();
}
}

}
Expand Up @@ -23,6 +23,7 @@
import net.robotmedia.billing.request.RequestPurchase;
import net.robotmedia.billing.request.RestoreTransactions;
import net.robotmedia.billing.request.BillingRequest;
import net.robotmedia.billing.utils.Compatibility;

import com.android.vending.billing.IMarketBillingService;

Expand Down Expand Up @@ -163,10 +164,10 @@ public void onStart(Intent intent, int startId) {
handleCommand(intent);
}

@Override
// @Override // Avoid compile errors on pre-2.0
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand(intent);
return START_NOT_STICKY;
return Compatibility.START_NOT_STICKY;
}

private void handleCommand(Intent intent) {
Expand Down
Expand Up @@ -55,4 +55,9 @@ public interface IBillingObserver {
*/
public void onPurchaseRefunded(String itemId);

/**
* Called after a restore transactions request has been successfully received by the server.
*/
public void onTransactionsRestored();

}
Expand Up @@ -22,8 +22,8 @@ public class Transaction {

public enum PurchaseState {
// Responses to requestPurchase or restoreTransactions.
PURCHASED, // 0: The charge failed on the server.
CANCELLED, // 1: User was charged for the order.
PURCHASED, // 0: User was charged for the order.
CANCELLED, // 1: The charge failed on the server.
REFUNDED; // 2: User received a refund for the order.

// Converts from an ordinal value to the PurchaseState
Expand Down
Expand Up @@ -27,33 +27,53 @@ public abstract class BillingRequest {
private static final String KEY_API_VERSION = "API_VERSION";
private static final String KEY_PACKAGE_NAME = "PACKAGE_NAME";
private static final String KEY_RESPONSE_CODE = "RESPONSE_CODE";
private static final String KEY_REQUEST_ID = "REQUEST_ID";
protected static final String KEY_REQUEST_ID = "REQUEST_ID";
private static final String KEY_NONCE = "NONCE";
public static final long IGNORE_REQUEST_ID = -1;

public abstract String getRequestType();
protected abstract void addParams(Bundle request);
protected abstract void processOkResponse(Bundle response);
private String packageName;
private boolean success;
private long nonce;

public boolean hasNonce() {
return false;
public BillingRequest(String packageName) {
this.packageName = packageName;
}

private String packageName;
private boolean success;
private long nonce;
protected void addParams(Bundle request) {
// Do nothing by default
}

public long getNonce() {
return nonce;
}
public void setNonce(long nonce) {
this.nonce = nonce;
}
public BillingRequest(String packageName) {
this.packageName = packageName;
public abstract String getRequestType();

public boolean hasNonce() {
return false;
}
public boolean isSuccess() {
return success;
}
protected Bundle makeRequestBundle() {
final Bundle request = new Bundle();
request.putString(KEY_BILLING_REQUEST, getRequestType());
request.putInt(KEY_API_VERSION, 1);
request.putString(KEY_PACKAGE_NAME, packageName);
if (hasNonce()) {
request.putLong(KEY_NONCE, nonce);
}
return request;
}

public long run(IMarketBillingService mService) throws RemoteException {
public void onResponseCode(int responseCode) {
// Do nothing by default
}

protected void processOkResponse(Bundle response) {
// Do nothing by default
}

public long run(IMarketBillingService mService) throws RemoteException {
final Bundle request = makeRequestBundle();
addParams(request);
final Bundle response = mService.sendBillingRequest(request);
Expand All @@ -64,18 +84,11 @@ public long run(IMarketBillingService mService) throws RemoteException {
return IGNORE_REQUEST_ID;
}
}

protected Bundle makeRequestBundle() {
final Bundle request = new Bundle();
request.putString(KEY_BILLING_REQUEST, getRequestType());
request.putInt(KEY_API_VERSION, 1);
request.putString(KEY_PACKAGE_NAME, packageName);
if (hasNonce()) {
request.putLong(KEY_NONCE, nonce);
}
return request;
}


public void setNonce(long nonce) {
this.nonce = nonce;
}

protected boolean validateResponse(Bundle response) {
final int responseCode = response.getInt(KEY_RESPONSE_CODE);
success = ResponseCode.isResponseOk(responseCode);
Expand All @@ -85,8 +98,4 @@ protected boolean validateResponse(Bundle response) {
return success;
}

public boolean isSuccess() {
return success;
}

}
Expand Up @@ -29,9 +29,6 @@ public String getRequestType() {
return "CHECK_BILLING_SUPPORTED";
}

@Override
protected void addParams(Bundle request) {}

@Override
protected void processOkResponse(Bundle response) {
final boolean supported = this.isSuccess();
Expand Down
Expand Up @@ -37,8 +37,5 @@ public String getRequestType() {
protected void addParams(Bundle request) {
request.putStringArray(KEY_NOTIFY_IDS, notifyIds);
}

@Override
protected void processOkResponse(Bundle response) {}

}
Expand Up @@ -39,9 +39,5 @@ public String getRequestType() {
protected void addParams(Bundle request) {
request.putStringArray(KEY_NOTIFY_IDS, notifyIds);
}

@Override
protected void processOkResponse(Bundle response) {
}

}
Expand Up @@ -15,7 +15,7 @@

package net.robotmedia.billing.request;

import android.os.Bundle;
import net.robotmedia.billing.BillingController;

public class RestoreTransactions extends BillingRequest {

Expand All @@ -29,11 +29,13 @@ public RestoreTransactions(String packageName) {
public String getRequestType() {
return "RESTORE_TRANSACTIONS";
}

@Override
protected void addParams(Bundle request) {}


@Override
protected void processOkResponse(Bundle response) {}
public void onResponseCode(int responseCode) {
super.onResponseCode(responseCode);
if (ResponseCode.isResponseOk(responseCode)) {
BillingController.onTransactionsRestored(this);
}
}

}
Expand Up @@ -15,15 +15,18 @@

package net.robotmedia.billing.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.content.IntentSender;
import android.util.Log;

public class Compatibility {
private static Method startIntentSender;
public static int START_NOT_STICKY;
@SuppressWarnings("rawtypes")
private static final Class[] START_INTENT_SENDER_SIG = new Class[] {
IntentSender.class, Intent.class, int.class, int.class, int.class
Expand All @@ -34,7 +37,13 @@ public class Compatibility {
};

private static void initCompatibility() {
try {
try {
final Field field = Service.class.getField("START_NOT_STICKY");
START_NOT_STICKY = field.getInt(null);
} catch (Exception e) {
START_NOT_STICKY = 2;
}
try {
startIntentSender = Activity.class.getMethod("startIntentSender",
START_INTENT_SENDER_SIG);
} catch (SecurityException e) {
Expand Down
Expand Up @@ -15,14 +15,19 @@

package net.robotmedia.billing;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.robotmedia.billing.model.BillingDB;
import net.robotmedia.billing.model.BillingDBTest;
import net.robotmedia.billing.model.Transaction;
import net.robotmedia.billing.model.TransactionTest;
import net.robotmedia.billing.request.RestoreTransactions;
import android.app.PendingIntent;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;

public class BillingControllerTest extends AndroidTestCase {

Expand Down Expand Up @@ -99,4 +104,27 @@ public void testGetTransactionsString() throws Exception {
final List<Transaction> transactions2 = BillingController.getTransactions(getContext(), TransactionTest.TRANSACTION_1.productId);
assertEquals(transactions2.size(), 1);
}

@SmallTest
public void testOnTransactionRestored() throws Exception {
final Set<Boolean> flags = new HashSet<Boolean>();
final IBillingObserver observer = new IBillingObserver() {

@Override
public void onTransactionsRestored() {
flags.add(true);
}

public void onPurchaseRefunded(String itemId) {}
public void onPurchaseIntent(String itemId, PendingIntent purchaseIntent) {}
public void onPurchaseExecuted(String itemId) {}
public void onPurchaseCancelled(String itemId) {}
public void onBillingChecked(boolean supported) {}
};
BillingController.registerObserver(observer);
final RestoreTransactions request = new RestoreTransactions(getContext().getPackageName());
BillingController.onTransactionsRestored(request);
assertEquals(flags.size(), 1);
BillingController.unregisterObserver(observer);
}
}
Expand Up @@ -53,4 +53,9 @@ public String getPublicKey() {
return null;
}

@Override
public void onTransactionsRestored() {
// TODO Auto-generated method stub
}

}
@@ -0,0 +1,14 @@
package net.robotmedia.billing.utils;

import android.app.Service;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

public class CompatibilityTest extends AndroidTestCase {

@SmallTest
public void testStartNotSticky() throws Exception {
assertEquals(Compatibility.START_NOT_STICKY, Service.START_NOT_STICKY);
}

}
8 changes: 8 additions & 0 deletions DungeonsRedux/.classpath
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="src" path="AndroidBillingLibrary_src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
2 changes: 2 additions & 0 deletions DungeonsRedux/.gitignore
@@ -0,0 +1,2 @@
bin
gen

0 comments on commit 3a5e5f9

Please sign in to comment.