• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
initSingleton(Context appContext)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      */
getInstance()65     public static ProcessingServiceManager getInstance() {
66         if (sInstance == null) {
67             throw new IllegalStateException("initSingleton() not yet called.");
68         }
69         return sInstance;
70     }
71 
ProcessingServiceManager(Context context)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      */
enqueueTask(ProcessingTask task)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      */
popNextSession()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      */
isRunningOrHasItems()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      */
suspendProcessing()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      */
resumeProcessing()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      */
startService()155     private void startService() {
156         mAppContext.startService(new Intent(mAppContext, ProcessingService.class));
157         mServiceRunning = true;
158     }
159 }
160