package vandy.mooc.model.services; import java.lang.ref.WeakReference; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import vandy.mooc.common.LifecycleLoggingService; import vandy.mooc.model.datamodel.RequestMessage; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; /** * A Bound Service that concurrently downloads an image requested via * a Message passed to a Request Messenger, stores the image in a file * on the local device, and returns the URI to the downloaded image * file back to the Activity via the Reply Messenger passed with the * original Message. */ public class DownloadImagesBoundService extends LifecycleLoggingService { /** * A RequestHandler that handles request Messages send from the * Activity. */ private RequestHandler mRequestHandler = null; /** * A Messenger that encapsulates the RequestHandler used to handle * request Messages sent from the Activity. */ private Messenger mRequestMessenger = null; /** * This class handles messages sent from an Activity in a pool of * threads managed by the Java ExecutorService. */ private static class RequestHandler extends Handler { /** * Debugging tag used by the Android logger. */ private final String TAG = getClass().getSimpleName(); /** * Store a WeakReference to the Service to enable garbage * collection. */ WeakReference<DownloadImagesBoundService> mService; /** * Reference to the ExecutorService that manages a pool of * threads. */ private ExecutorService mExecutorService; /** * Constructor initializes the WeakReference and ExecutorService. */ public RequestHandler(DownloadImagesBoundService service) { // Store a WeakReference to the DownloadImageService. mService = new WeakReference<>(service); // Create an ExecutorService that manages a pool of threads. mExecutorService = Executors.newCachedThreadPool(); } /** * Hook method called back when a request message arrives from * an Activity. The Message it receives contains the * Messenger used to reply to the Activity and the URL of the * image to download. This image is stored in a local file on * the local device and image file's URI is sent back to the * MainActivity via the Messenger passed with the message. */ public void handleMessage(Message message) { // Convert the Message into a RequestMessage. final RequestMessage requestMessage = RequestMessage.makeRequestMessage(message); // Get the reply Messenger. // TODO -- you fill in here. // Get the URL associated with the Message. // TODO -- you fill in here. // Get the directory pathname where the image will be // stored. // TODO -- you fill in here. // Get the requestCode for the operation that was invoked // by the Activity. // TODO -- you fill in here. // A Runnable that downloads the image, stores it in a // file, and sends the path to the file back to the // Activity. final Runnable downloadImageAndReply = new Runnable() { /** * This method runs in a background Thread. */ @Override public void run() { // Download and store the requested image. // TODO -- you fill in here. // Send the path to the image file, url, and // requestCode back to the Activity via the // replyMessenger. // TODO -- you fill in here. } }; // Execute the downloadImageAndReply Runnable to download // the image and reply. // TODO -- you fill in here. } /** * Send the @a pathToImageFile, @a url, and @a requestCode back to * the Activity via the @a messenger. */ public void sendPath(Messenger messenger, Uri pathToImageFile, Uri url, int requestCode) { // Call the makeReplyMessage() factory method to create // Message. // TODO -- you fill in here. try { Log.d(TAG, "sending " + pathToImageFile + " back to the MainActivity"); // Send the replyMessage back to the Activity. // TODO -- you fill in here. } catch (RemoteException e) { Log.e(getClass().getName(), "Exception while sending reply message back to Activity.", e); } } /** * Shutdown the ExecutorService immediately. */ public void shutdown() { // Immediately shutdown the ExecutorService. // TODO -- you fill in here. } } /** * Factory method that returns an explicit Intent for downloading * an image. */ public static Intent makeIntent(Context context) { // Create an intent that will download the image from the web. // TODO -- you fill in here, replacing null with the proper // code. return null; } /** * Hook method called when the Service is created. */ @Override public void onCreate() { // Create a RequestHandler used to handle request Messages // sent from an Activity. // TODO -- you fill in here. // Create a Messenger that encapsulates the RequestHandler. // TODO -- you fill in here. } /** * Factory method that returns the underlying IBinder associated * with the Request Messenger. */ @Override public IBinder onBind(Intent intent) { super.onBind(intent); // Return the IBinder associated with the Request Messenger. return mRequestMessenger.getBinder(); } /** * Hook method called when the last client unbinds from the * Service. */ @Override public void onDestroy() { super.onDestroy(); // Shutdown the RequestHandler. // TODO -- you fill in here. } }