package com.gettingmobile.android.app; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class ServiceProxy<T extends Service, L extends ServiceListener> { private final Class<T> serviceClass; private final ServiceConnection connection = new ServiceConnection(); private final List<Operation<T>> startupOperations = new ArrayList<Operation<T>>(); private T service = null; private Set<L> listeners = new HashSet<L>(); public ServiceProxy(Class<T> serviceClass) { this.serviceClass = serviceClass; } protected Intent createIntent(Context context) { return new Intent(context, serviceClass); } public boolean isStarted() { return service != null; } public void startService(Context context) { final Intent intent = createIntent(context); context.bindService(intent, connection, Service.BIND_AUTO_CREATE); } public void stopService(Context context) { if (service != null) { context.stopService(createIntent(context)); context.unbindService(connection); } } public T getService() { return service; } /** * Executes the specified operation on the service, if the service is already up and running or schedules the * operation for execution on service startup. * @param operation the operation to be executed with the service. * @return {@code true} if the service is up and running and the operation has been executed, {@code false} if the * operation has been scheduled for execution on service startup. */ public boolean runOnService(Operation<T> operation) { if (service != null) { operation.run(service); return true; } else { startupOperations.add(operation); return false; } } protected void onStartup() { for (Operation<T> op : startupOperations) { op.run(service); } } /* * listener handling */ public boolean addListener(L listener) { return listeners.add(listener); } public boolean removeListener(L listener) { return listeners.remove(listener); } public Set<L> getListeners() { return listeners; } /* * inner classes */ public static interface Operation<T> { void run(T service); } class ServiceConnection implements android.content.ServiceConnection { @SuppressWarnings("unchecked") @Override public void onServiceConnected(ComponentName className, IBinder serviceBinder) { boolean unexpectedServiceBinder = true; if (serviceBinder != null && serviceBinder instanceof ServiceBinder<?>) { final Service svc = ((ServiceBinder) serviceBinder).getService(); if (serviceClass.isAssignableFrom(svc.getClass())) { service = (T) svc; onStartup(); unexpectedServiceBinder = false; } } if (unexpectedServiceBinder) { /* * this should occur only in the context of the CrashReport as this is running in another process */ service = null; Log.w(getClass().getName(), "Failed to gather service interface"); } } @Override public void onServiceDisconnected(ComponentName className) { service = null; } } }