package org.ecomap.android.app.sync; import android.app.Activity; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.design.widget.Snackbar; import android.util.Log; import org.ecomap.android.app.utils.SnackBarHelper; import java.lang.ref.WeakReference; public class UploadingServiceSession { public Context mContext; private final String mHostToken; /** * Messenger for communicating with service. */ private Messenger mService = null; /** * Flag indicating whether we have called bind on the service. */ private boolean mIsBound; /** * Target we publish for clients to send messages to IncomingHandler. */ private final Messenger mMessenger; private final String LOG = UploadingServiceSession.class.getSimpleName(); public UploadingServiceSession(Activity activity, String hostToken, Callbacks callbackListener) { this.mContext = activity.getApplicationContext(); this.mHostToken = hostToken; this.mMessenger = new Messenger(new IncomingHandler(new WeakReference<>(activity), new WeakReference<>(callbackListener))); } /** * Handler of incoming messages from service. */ private static class IncomingHandler extends Handler { private final WeakReference<Callbacks> callbackListener; private final WeakReference<Activity> mContext; public IncomingHandler(WeakReference<Activity> mContext, WeakReference<Callbacks> callbackListener) { this.callbackListener = callbackListener; this.mContext = mContext; } @Override public void handleMessage(Message msg) { switch (msg.what) { case UploadingService.MSG_TASK_FINISHED: Bundle data = msg.getData(); if (mContext != null) { final Activity activity = mContext.get(); if(activity != null) SnackBarHelper.showSuccessSnackBar(activity, data.getString("PHOTO_URL") + " uploaded.", Snackbar.LENGTH_SHORT); } break; case UploadingService.MSG_ALL_TASKS_FINISHED: if(callbackListener != null && callbackListener.get() != null) { callbackListener.get().allTasksFinished(); } break; default: super.handleMessage(msg); } } } /** * Class for interacting with the main interface of the service. */ private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mService = new Messenger(service); //mCallbackText.setText("Attached."); // We want to monitor the service for as long as we are // connected to it. try { Message msg = Message.obtain(null, UploadingService.MSG_REGISTER_CLIENT); Bundle params = new Bundle(); params.putString("CLASS_NAME", mHostToken); msg.setData(params); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. } mIsBound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; //mCallbackText.setText("Disconnected."); mIsBound = false; } }; public void doBindService() { // Establish a connection with the service. We use an explicit // class name because there is no reason to be able to let other // applications replace our component. //if(!mIsBound) { final Intent intent = new Intent(mContext, UploadingService.class); // intent.setAction("org.ecomap.android.app.PHOTOS_UPLOADING"); mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); //} } public void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with // it, then now is the time to unregister. if (mService != null) { try { Message msg = Message.obtain(null, UploadingService.MSG_UNREGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service // has crashed. } } // Detach our existing connection. if (isMyServiceRunning(UploadingService.class)) { mContext.unbindService(mConnection); } //mIsBound = false; } } public void doStartService() { if (!mIsBound) { doBindService(); //while (!mIsBound); } Intent intent = new Intent(mContext, UploadingService.class); mContext.startService(intent); } public boolean isBound() { return mIsBound; } private boolean isMyServiceRunning(Class<?> serviceClass) { ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; } public void sendUploadRequest(int problemId, String photoURL, String comment) { Bundle params = new Bundle(); params.putString("CLASS_NAME", mHostToken); params.putInt("PROBLEM_ID", problemId); params.putString("PHOTO_URL", photoURL); params.putString("COMMENT", comment); Message msg = Message.obtain(null, UploadingService.MSG_UPLOAD_PHOTO); msg.setData(params); msg.replyTo = mMessenger; try { mService.send(msg); } catch (RemoteException e) { Log.e(LOG, e.getMessage(), e); } } public interface Callbacks { void allTasksFinished(); } }