| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.camera.processing; |
| |
| import android.content.Context; |
| import android.content.Intent; |
| |
| import com.android.camera.debug.Log; |
| |
| import java.util.LinkedList; |
| |
| /** |
| * Manages a queue of processing tasks as well as the processing service |
| * lifecycle. |
| * <p> |
| * Clients should only use this class and not the {@link ProcessingService} |
| * directly. |
| */ |
| public class ProcessingServiceManager { |
| private static final Log.Tag TAG = new Log.Tag("ProcessingSvcMgr"); |
| |
| /** The singleton instance of this manager. */ |
| private static ProcessingServiceManager sInstance; |
| |
| /** The application context. */ |
| private final Context mAppContext; |
| |
| /** Queue of tasks to be processed. */ |
| private final LinkedList<ProcessingTask> mQueue = new LinkedList<ProcessingTask>(); |
| |
| /** Whether a processing service is currently running. */ |
| private volatile boolean mServiceRunning = false; |
| |
| /** Can be set to prevent tasks from being processed until released.*/ |
| private boolean mHoldProcessing = false; |
| |
| /** |
| * Initializes the singleton instance. |
| * |
| * @param context the application context. |
| */ |
| public static void initSingleton(Context appContext) { |
| sInstance = new ProcessingServiceManager(appContext); |
| } |
| |
| /** |
| * Note: Make sure to call {@link #initSingleton(Context)} first. |
| * |
| * @return the singleton instance of the processing service manager. |
| */ |
| public static ProcessingServiceManager getInstance() { |
| if (sInstance == null) { |
| throw new IllegalStateException("initSingleton() not yet called."); |
| } |
| return sInstance; |
| } |
| |
| private ProcessingServiceManager(Context context) { |
| mAppContext = context; |
| } |
| |
| /** |
| * Enqueues a new task. If the service is not already running, it will be |
| * started. |
| * |
| * @param task The task to be enqueued. |
| */ |
| public synchronized void enqueueTask(ProcessingTask task) { |
| mQueue.add(task); |
| Log.d(TAG, "Task added. Queue size now: " + mQueue.size()); |
| |
| if (!mServiceRunning && !mHoldProcessing) { |
| startService(); |
| } |
| } |
| |
| /** |
| * Remove the next task from the queue and return it. |
| * |
| * @return The next Task or <code>null</code>, if no more tasks are in the |
| * queue or we have a processing hold. If null is returned the |
| * service is has to shut down as a new service is started if either |
| * new items enter the queue or the processing is resumed. |
| */ |
| public synchronized ProcessingTask popNextSession() { |
| if (!mQueue.isEmpty() && !mHoldProcessing) { |
| Log.d(TAG, "Popping a session. Remaining: " + (mQueue.size() - 1)); |
| return mQueue.remove(); |
| } else { |
| Log.d(TAG, "Popping null. On hold? " + mHoldProcessing); |
| mServiceRunning = false; |
| // Returning null will shut-down the service. |
| return null; |
| } |
| } |
| |
| /** |
| * @return Whether the service has queued items or is running. |
| */ |
| public synchronized boolean isRunningOrHasItems() { |
| return mServiceRunning || !mQueue.isEmpty(); |
| } |
| |
| /** |
| * If the queue is currently empty, processing is suspended for new incoming |
| * items until the hold is released. |
| * <p> |
| * If items are in the queue, processing cannot be suspended. |
| * |
| * @return Whether processing was suspended. |
| */ |
| public synchronized boolean suspendProcessing() { |
| if (!isRunningOrHasItems()) { |
| Log.d(TAG, "Suspend processing"); |
| mHoldProcessing = true; |
| return true; |
| } else { |
| Log.d(TAG, "Not able to suspend processing."); |
| return false; |
| } |
| } |
| |
| /** |
| * Releases an existing hold. |
| */ |
| public synchronized void resumeProcessing() { |
| Log.d(TAG, "Resume processing. Queue size: " + mQueue.size()); |
| if (mHoldProcessing) { |
| mHoldProcessing = false; |
| if (!mQueue.isEmpty()) { |
| startService(); |
| } |
| } |
| } |
| |
| /** |
| * Starts the service which will then work through the queue. Once the queue |
| * is empty {@link #popNextSession()} returns null), the task will kill |
| * itself automatically and call #stitchingFinished(). |
| */ |
| private void startService() { |
| mAppContext.startService(new Intent(mAppContext, ProcessingService.class)); |
| mServiceRunning = true; |
| } |
| } |