Home | History | Annotate | Download | only in processing
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.processing;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 
     22 import com.android.camera.debug.Log;
     23 
     24 import java.util.LinkedList;
     25 
     26 /**
     27  * Manages a queue of processing tasks as well as the processing service
     28  * lifecycle.
     29  * <p>
     30  * Clients should only use this class and not the {@link ProcessingService}
     31  * directly.
     32  */
     33 public class ProcessingServiceManager {
     34     private static final Log.Tag TAG = new Log.Tag("ProcessingSvcMgr");
     35 
     36     /** The singleton instance of this manager. */
     37     private static ProcessingServiceManager sInstance;
     38 
     39     /** The application context. */
     40     private final Context mAppContext;
     41 
     42     /** Queue of tasks to be processed. */
     43     private final LinkedList<ProcessingTask> mQueue = new LinkedList<ProcessingTask>();
     44 
     45     /** Whether a processing service is currently running. */
     46     private volatile boolean mServiceRunning = false;
     47 
     48     /** Can be set to prevent tasks from being processed until released.*/
     49     private boolean mHoldProcessing = false;
     50 
     51     /**
     52      * Initializes the singleton instance.
     53      *
     54      * @param context the application context.
     55      */
     56     public static void initSingleton(Context appContext) {
     57         sInstance = new ProcessingServiceManager(appContext);
     58     }
     59 
     60     /**
     61      * Note: Make sure to call {@link #initSingleton(Context)} first.
     62      *
     63      * @return the singleton instance of the processing service manager.
     64      */
     65     public static ProcessingServiceManager getInstance() {
     66         if (sInstance == null) {
     67             throw new IllegalStateException("initSingleton() not yet called.");
     68         }
     69         return sInstance;
     70     }
     71 
     72     private ProcessingServiceManager(Context context) {
     73         mAppContext = context;
     74     }
     75 
     76     /**
     77      * Enqueues a new task. If the service is not already running, it will be
     78      * started.
     79      *
     80      * @param task The task to be enqueued.
     81      */
     82     public synchronized void enqueueTask(ProcessingTask task) {
     83         mQueue.add(task);
     84         Log.d(TAG, "Task added. Queue size now: " + mQueue.size());
     85 
     86         if (!mServiceRunning && !mHoldProcessing) {
     87             startService();
     88         }
     89     }
     90 
     91     /**
     92      * Remove the next task from the queue and return it.
     93      *
     94      * @return The next Task or <code>null</code>, if no more tasks are in the
     95      *         queue or we have a processing hold. If null is returned the
     96      *         service is has to shut down as a new service is started if either
     97      *         new items enter the queue or the processing is resumed.
     98      */
     99     public synchronized ProcessingTask popNextSession() {
    100         if (!mQueue.isEmpty() && !mHoldProcessing) {
    101             Log.d(TAG, "Popping a session. Remaining: " + (mQueue.size() - 1));
    102             return mQueue.remove();
    103         } else {
    104             Log.d(TAG, "Popping null. On hold? " + mHoldProcessing);
    105             mServiceRunning = false;
    106             // Returning null will shut-down the service.
    107             return null;
    108         }
    109     }
    110 
    111     /**
    112      * @return Whether the service has queued items or is running.
    113      */
    114     public synchronized boolean isRunningOrHasItems() {
    115         return mServiceRunning || !mQueue.isEmpty();
    116     }
    117 
    118     /**
    119      * If the queue is currently empty, processing is suspended for new incoming
    120      * items until the hold is released.
    121      * <p>
    122      * If items are in the queue, processing cannot be suspended.
    123      *
    124      * @return Whether processing was suspended.
    125      */
    126     public synchronized boolean suspendProcessing() {
    127         if (!isRunningOrHasItems()) {
    128             Log.d(TAG, "Suspend processing");
    129             mHoldProcessing = true;
    130             return true;
    131         } else {
    132           Log.d(TAG, "Not able to suspend processing.");
    133           return false;
    134         }
    135     }
    136 
    137     /**
    138      * Releases an existing hold.
    139      */
    140     public synchronized void resumeProcessing() {
    141         Log.d(TAG, "Resume processing. Queue size: " + mQueue.size());
    142         if (mHoldProcessing) {
    143           mHoldProcessing = false;
    144             if (!mQueue.isEmpty()) {
    145                 startService();
    146             }
    147         }
    148     }
    149 
    150     /**
    151      * Starts the service which will then work through the queue. Once the queue
    152      * is empty {@link #popNextSession()} returns null), the task will kill
    153      * itself automatically and call #stitchingFinished().
    154      */
    155     private void startService() {
    156         mAppContext.startService(new Intent(mAppContext, ProcessingService.class));
    157         mServiceRunning = true;
    158     }
    159 }
    160