package yuku.easybilling; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Pair; import java.util.ArrayList; import java.util.List; import com.android.vending.billing.IMarketBillingService; public class BillingService extends Service implements ServiceConnection { private static final String TAG = BillingService.class.getSimpleName(); /** The service connection to the remote MarketBillingService. */ private IMarketBillingService remoteService; private List<Pair<BillingRequest, BillingResultListener<? extends BillingResult>>> pendingRequests = new ArrayList<Pair<BillingRequest, BillingResultListener<? extends BillingResult>>>(); @Override public void onCreate() { super.onCreate(); Log.i(TAG, "@@onCreate"); } public void setContext(Context context) { attachBaseContext(context); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "Remote service connected."); remoteService = IMarketBillingService.Stub.asInterface(service); // run pending requests if any runPendingRequests(); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "Remote service disconnected"); remoteService = null; } @SuppressWarnings("unchecked") private void runPendingRequests() { Log.d(TAG, "@@runPendingRequests"); while (true) { if (pendingRequests.size() == 0) { Log.d(TAG, "No more pendingRequests"); break; } else { Log.d(TAG, "We have " + pendingRequests.size() + " pendingRequests"); } if (remoteService == null) { Log.d(TAG, "runPendingRequests stopped because remoteService is disconnected"); break; } // remoteService is available now! Pair<BillingRequest, BillingResultListener<? extends BillingResult>> entry = null; synchronized (pendingRequests) { if (pendingRequests.size() > 0) entry = pendingRequests.remove(0); } if (entry == null) { Log.d(TAG, "No more pendingRequests"); break; } @SuppressWarnings("rawtypes") BillingResultListener listener = entry.second; try { BillingRequest request = entry.first; Bundle requestBundle = request.getRequestBundle(); Bundle resultBundle = remoteService.sendBillingRequest(requestBundle); BillingResult result = request.parseResultBundle(resultBundle); if (listener == null) { Log.d(TAG, "Listener is null, we ignore the result (OK)"); } else { listener.onBillingResult(BillingRequestStatus.DELAYED, result); } } catch (RemoteException e) { if (listener == null) { Log.d(TAG, "Listener is null, we ignore the result (RemoteException)"); } else { listener.onBillingResult(BillingRequestStatus.REMOTE_EXCEPTION, null); } } } } public <T extends BillingResult> BillingRequestStatus request(BillingRequest request, BillingResultListener<T> resultListener) { BillingRequestStatus res = requestImpl(request, resultListener); Log.d(TAG, "request method result for " + request.getClass().getSimpleName() + ": " + res); return res; } @SuppressWarnings("unchecked") private <T extends BillingResult> BillingRequestStatus requestImpl(BillingRequest request, BillingResultListener<T> resultListener) { if (remoteService != null) { // we are connected to remote service. try { Bundle requestBundle = request.getRequestBundle(); Bundle resultBundle = remoteService.sendBillingRequest(requestBundle); resultListener.onBillingResult(BillingRequestStatus.IMMEDIATE, (T) request.parseResultBundle(resultBundle)); return BillingRequestStatus.IMMEDIATE; } catch (RemoteException e) { Log.e(TAG, "BillingService#request", e); return BillingRequestStatus.REMOTE_EXCEPTION; } } else { boolean bindResult = bindService(new Intent("com.android.vending.billing.MarketBillingService.BIND"), this, Context.BIND_AUTO_CREATE); if (bindResult) { synchronized (pendingRequests) { pendingRequests.add(new Pair<BillingRequest, BillingResultListener<?>>(request, resultListener)); } return BillingRequestStatus.DELAYED; } else { return BillingRequestStatus.BIND_ERROR; } } } }