package yuku.easybilling; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import yuku.easybilling.BillingSecurity.SignedData; public class BillingDb { public static final String TAG = BillingDb.class.getSimpleName(); private static BillingDb instance = null; public static BillingDb get() { if (instance == null) { throw new RuntimeException("Pass in context for first time"); } return instance; } public static synchronized BillingDb get(Context context) { if (instance == null) { instance = new BillingDb(new BillingDbHelper(context)); } return instance; } protected final BillingDbHelper helper; private BillingDb(BillingDbHelper helper) { this.helper = helper; } public int getInventoryAmount(String productId) { SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.query("Inventory", new String[] {"amount"}, "productId=?", new String[] {productId}, null, null, null); try { if (c.moveToNext()) { return c.getInt(0); } return 0; } finally { c.close(); } } public Map<String, Integer> getAllInventory() { Map<String, Integer> res = new LinkedHashMap<String, Integer>(); SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.query("Inventory", new String[] {"productId", "amount"}, null, null, null, null, null); try { while (c.moveToNext()) { String productId = c.getString(0); int amount = c.getInt(1); res.put(productId, amount); } } finally { c.close(); } return res; } public void updateWithChange(SignedData.Order change, Set<EasyBillingListener> listenerSet) { SQLiteDatabase db = helper.getWritableDatabase(); String orderId = change.orderId; String productId = change.productId; Log.d(TAG, "@@updateWithOrder orderId: " + orderId); db.beginTransaction(); try { { // put to permanent log ContentValues cv = new ContentValues(); cv.put("orderId", change.orderId); cv.put("packageName", change.packageName); cv.put("productId", change.productId); cv.put("purchaseTime", change.purchaseTime); cv.put("purchaseState", change.purchaseState.ordinal()); cv.put("developerPayload", change.developerPayload); db.insert("Changes", null, cv); } boolean orderInDb = count(db, "Orders", "orderId=?", orderId) > 0; Log.d(TAG, "This order is in db?: " + orderInDb); if (orderInDb) { PurchaseState oldPurchaseState = PurchaseState.valueOf(getInt(db, "Orders", "purchaseState", -1, "orderId=?", orderId)); PurchaseState newPurchaseState = change.purchaseState; boolean oldHave = oldPurchaseState == PurchaseState.PURCHASED; boolean newHave = newPurchaseState == PurchaseState.PURCHASED; { // update db ContentValues cv = new ContentValues(); cv.put("orderId", change.orderId); cv.put("purchaseState", change.purchaseState.ordinal()); db.update("Orders", cv, "orderId=?", new String[] {orderId}); } if (oldHave == newHave) { Log.d(TAG, "productId " + change.productId + " inventory not updated, purchase state old=" + oldPurchaseState + " new=" + newPurchaseState); } else { int[] amounts = modifyAmount(db, productId, newHave? +1: -1); for (EasyBillingListener listener: listenerSet) { listener.onInventoryAmountChange(productId, newPurchaseState, amounts[0], amounts[1]); } } } else { PurchaseState newPurchaseState = change.purchaseState; boolean newHave = newPurchaseState == PurchaseState.PURCHASED; { // insert to db ContentValues cv = new ContentValues(); cv.put("orderId", change.orderId); cv.put("purchaseState", change.purchaseState.ordinal()); db.insert("Orders", null, cv); } if (newHave) { int[] amounts = modifyAmount(db, productId, +1); for (EasyBillingListener listener: listenerSet) { listener.onInventoryAmountChange(productId, newPurchaseState, amounts[0], amounts[1]); } } else { Log.d(TAG, "new purchase state: " + newPurchaseState + " for non-existing product in inventory, not modifying amount"); } } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } private int[] modifyAmount(SQLiteDatabase db, String productId, int delta) { int oldAmount = getInt(db, "Inventory", "amount", 0, "productId=?", productId); int newAmount = oldAmount + delta; if (newAmount < 0) { Log.w(TAG, "New inventory amount of " + productId + " is negative: " + newAmount + " was: " + oldAmount + ", using 0 instead"); newAmount = 0; } ContentValues cv = new ContentValues(); cv.put("productId", productId); cv.put("amount", newAmount); if (count(db, "Inventory", "productId=?", productId) > 0) { // already on the table db.update("Inventory", cv, "productId=?", new String[] {productId}); } else { db.insert("Inventory", null, cv); } Log.w(TAG, "Inventory amount of " + productId + " was: " + oldAmount + ", now: " + newAmount); return new int[] {oldAmount, newAmount}; } private int count(SQLiteDatabase db, String table, String whereClause, String... whereArgs) { Cursor c = db.query(table, new String[] {"count(*)"}, whereClause, whereArgs, null, null, null); try { c.moveToNext(); return c.getInt(0); } finally { c.close(); } } private int getInt(SQLiteDatabase db, String table, String column, int def, String whereClause, String... whereArgs) { Cursor c = db.query(table, new String[] {column}, whereClause, whereArgs, null, null, null); try { if (c.moveToNext()) { return c.getInt(0); } else { return def; } } finally { c.close(); } } }