/** * Adds <var>runnable</var> to the end of waiting list. * * @param runnable runnable to be executed when connection is established */ void add(@Nonnull RequestRunnable runnable) { synchronized (mList) { Billing.debug("Adding pending request: " + runnable); mList.add(runnable); } }
/** * Method removes first element from the waiting list * * @return first list element or null if waiting list is empty */ @Nullable RequestRunnable pop() { synchronized (mList) { final RequestRunnable runnable = !mList.isEmpty() ? mList.remove(0) : null; if (runnable != null) { Billing.debug("Removing pending request: " + runnable); } return runnable; } }
@Override public void removeAll(int type) { if (mCache == null) { return; } synchronized (this) { Billing.debug(TAG, "Removing all entries with type=" + type + " from the cache"); mCache.removeAll(type); } }
@Override public void clear() { if (mCache == null) { return; } synchronized (this) { Billing.debug(TAG, "Clearing the cache"); mCache.clear(); } } }
@Override public void put(@Nonnull Key key, @Nonnull Entry entry) { if (mCache == null) { return; } synchronized (this) { Billing.debug(TAG, "Adding entry with key=" + key + " to the cache"); mCache.put(key, entry); } }
@Override public void init() { if (mCache == null) { return; } synchronized (this) { Billing.debug(TAG, "Initializing cache"); mCache.init(); } }
@Override public void remove(@Nonnull Key key) { if (mCache == null) { return; } synchronized (this) { Billing.debug(TAG, "Removing entry with key=" + key + " from the cache"); mCache.remove(key); } }
public void putIfNotExist(@Nonnull Key key, @Nonnull Entry entry) { if (mCache == null) { return; } synchronized (this) { if (mCache.get(key) == null) { Billing.debug(TAG, "Adding entry with key=" + key + " to the cache"); mCache.put(key, entry); } else { Billing.debug(TAG, "Entry with key=" + key + " is already in the cache, won't add"); } } }
public void cancel() { synchronized (this) { if (mRequest != null) { Billing.debug("Cancelling request: " + mRequest); mRequest.cancel(); } mRequest = null; } }
/** * Method removes instance of <var>runnable</var> from the waiting list * * @param runnable runnable to be removed from the waiting list */ private void remove(@Nonnull RequestRunnable runnable) { synchronized (mList) { final Iterator<RequestRunnable> iterator = mList.iterator(); while (iterator.hasNext()) { if (iterator.next() == runnable) { Billing.debug("Removing pending request: " + runnable); iterator.remove(); break; } } } }
/** * Method cancels all pending requests */ void cancelAll() { synchronized (mList) { Billing.debug("Cancelling all pending requests"); final Iterator<RequestRunnable> iterator = mList.iterator(); while (iterator.hasNext()) { final RequestRunnable request = iterator.next(); request.cancel(); iterator.remove(); } } }
@Override @Nullable public Entry get(@Nonnull Key key) { if (mCache == null) { return null; } synchronized (this) { final Entry entry = mCache.get(key); if (entry == null) { Billing.debug(TAG, "Key=" + key + " is not in the cache"); return null; } final long now = currentTimeMillis(); if (now >= entry.expiresAt) { Billing.debug(TAG, "Key=" + key + " is in the cache but was expired at " + entry.expiresAt + ", now is " + now); mCache.remove(key); return null; } Billing.debug(TAG, "Key=" + key + " is in the cache"); return entry; } }
/** * Method cancels pending request with specified <var>requestId</var> * * @param requestId id of request to be cancelled */ void cancel(int requestId) { synchronized (mList) { Billing.debug("Cancelling pending request with id=" + requestId); final Iterator<RequestRunnable> iterator = mList.iterator(); while (iterator.hasNext()) { final RequestRunnable request = iterator.next(); if (request.getId() == requestId) { request.cancel(); iterator.remove(); break; } } } }
@Override public void verify(@Nonnull List<Purchase> purchases, @Nonnull RequestListener<List<Purchase>> listener) { final List<Purchase> verifiedPurchases = new ArrayList<Purchase>(purchases.size()); for (Purchase purchase : purchases) { // test purchases don't contain signatures let's auto-verify them if (TEST_SKUS.contains(purchase.sku)) { Billing.debug("Auto-verifying a test purchase: " + purchase); verifiedPurchases.add(purchase); continue; } if (Security.verifyPurchase(mPublicKey, purchase.data, purchase.signature)) { verifiedPurchases.add(purchase); continue; } if (isEmpty(purchase.signature)) { Billing.error("Cannot verify purchase: " + purchase + ". Signature is empty"); } else { Billing.error("Cannot verify purchase: " + purchase + ". Wrong signature"); } } listener.onSuccess(verifiedPurchases); } }
/** * Method cancels all pending requests with specified <var>tag</var> * * @param tag request tag */ void cancelAll(@Nullable Object tag) { synchronized (mList) { Billing.debug("Cancelling all pending requests with tag=" + tag); final Iterator<RequestRunnable> iterator = mList.iterator(); while (iterator.hasNext()) { final RequestRunnable request = iterator.next(); final Object requestTag = request.getTag(); if (requestTag == tag) { request.cancel(); iterator.remove(); continue; } if (requestTag != null && tag == null) { continue; } if (requestTag != null && requestTag.equals(tag)) { request.cancel(); iterator.remove(); } } } }
/** * Executes all pending runnable. * Note: this method must be called only on one thread. */ @Override public void run() { RequestRunnable runnable = peek(); while (runnable != null) { Billing.debug("Running pending request: " + runnable); if (runnable.run()) { remove(runnable); runnable = peek(); } else { // request can't be run because service is not connected => no need to run other requests (they will be // executed when service is connected) break; } } }