1dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling/* 2dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Copyright (C) 2014 The Android Open Source Project 3dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 4dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License"); 5dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * you may not use this file except in compliance with the License. 6dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * You may obtain a copy of the License at 7dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 8dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * http://www.apache.org/licenses/LICENSE-2.0 9dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 10dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Unless required by applicable law or agreed to in writing, software 11dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS, 12dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * See the License for the specific language governing permissions and 14dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * limitations under the License. 15dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 16dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 17dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberlingpackage com.android.camera.processing; 18dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 19dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberlingimport android.content.Context; 20dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberlingimport android.content.Intent; 215596b4c902dcb685928b43678f428746ca5ffd08Angus Kong 225596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log; 23dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 24dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberlingimport java.util.LinkedList; 25dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 26dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling/** 27dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Manages a queue of processing tasks as well as the processing service 28dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * lifecycle. 29dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * <p> 30dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Clients should only use this class and not the {@link ProcessingService} 31dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * directly. 32dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 33dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberlingpublic class ProcessingServiceManager { 345596b4c902dcb685928b43678f428746ca5ffd08Angus Kong private static final Log.Tag TAG = new Log.Tag("ProcessingSvcMgr"); 35dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 36dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** The singleton instance of this manager. */ 37dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling private static ProcessingServiceManager sInstance; 38dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 39dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** The application context. */ 40dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling private final Context mAppContext; 41dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 42dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** Queue of tasks to be processed. */ 43dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling private final LinkedList<ProcessingTask> mQueue = new LinkedList<ProcessingTask>(); 44dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 45dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** Whether a processing service is currently running. */ 46dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling private volatile boolean mServiceRunning = false; 47dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 48366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling /** Can be set to prevent tasks from being processed until released.*/ 49366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling private boolean mHoldProcessing = false; 50366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling 51dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** 52dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Initializes the singleton instance. 53dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 54dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * @param context the application context. 55dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 56dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling public static void initSingleton(Context appContext) { 57dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling sInstance = new ProcessingServiceManager(appContext); 58dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 59dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 60dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** 61dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Note: Make sure to call {@link #initSingleton(Context)} first. 62dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 63dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * @return the singleton instance of the processing service manager. 64dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 65dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling public static ProcessingServiceManager getInstance() { 66dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling if (sInstance == null) { 67dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling throw new IllegalStateException("initSingleton() not yet called."); 68dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 69dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling return sInstance; 70dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 71dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 72dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling private ProcessingServiceManager(Context context) { 73dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling mAppContext = context; 74dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 75dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 76dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** 77dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Enqueues a new task. If the service is not already running, it will be 78dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * started. 79dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 80dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * @param task The task to be enqueued. 81dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 82dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling public synchronized void enqueueTask(ProcessingTask task) { 83dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling mQueue.add(task); 84dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling Log.d(TAG, "Task added. Queue size now: " + mQueue.size()); 85dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 86366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling if (!mServiceRunning && !mHoldProcessing) { 87366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling startService(); 88dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 89dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 90dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 91dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** 92dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * Remove the next task from the queue and return it. 93dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling * 94366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * @return The next Task or <code>null</code>, if no more tasks are in the 95366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * queue or we have a processing hold. If null is returned the 96366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * service is has to shut down as a new service is started if either 97366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * new items enter the queue or the processing is resumed. 98dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 99dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling public synchronized ProcessingTask popNextSession() { 100366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling if (!mQueue.isEmpty() && !mHoldProcessing) { 101366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling Log.d(TAG, "Popping a session. Remaining: " + (mQueue.size() - 1)); 102dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling return mQueue.remove(); 103366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } else { 104366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling Log.d(TAG, "Popping null. On hold? " + mHoldProcessing); 105366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling mServiceRunning = false; 106366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling // Returning null will shut-down the service. 107dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling return null; 108dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 109dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 110dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling 111dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling /** 112366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * @return Whether the service has queued items or is running. 113366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling */ 114366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling public synchronized boolean isRunningOrHasItems() { 115366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling return mServiceRunning || !mQueue.isEmpty(); 116366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } 117366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling 118366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling /** 119366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * If the queue is currently empty, processing is suspended for new incoming 120366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * items until the hold is released. 121366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * <p> 122366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * If items are in the queue, processing cannot be suspended. 123366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * 124366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * @return Whether processing was suspended. 125366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling */ 126366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling public synchronized boolean suspendProcessing() { 127366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling if (!isRunningOrHasItems()) { 128366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling Log.d(TAG, "Suspend processing"); 129366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling mHoldProcessing = true; 130366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling return true; 131366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } else { 132366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling Log.d(TAG, "Not able to suspend processing."); 133366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling return false; 134366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } 135366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } 136366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling 137366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling /** 138366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * Releases an existing hold. 1399f834952cbef4d8c2dbf67be77157192f7a70d90Carlos Hernandez */ 140366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling public synchronized void resumeProcessing() { 141366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling Log.d(TAG, "Resume processing. Queue size: " + mQueue.size()); 142366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling if (mHoldProcessing) { 143366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling mHoldProcessing = false; 144366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling if (!mQueue.isEmpty()) { 145366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling startService(); 146366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } 147366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling } 1489f834952cbef4d8c2dbf67be77157192f7a70d90Carlos Hernandez } 1499f834952cbef4d8c2dbf67be77157192f7a70d90Carlos Hernandez 1509f834952cbef4d8c2dbf67be77157192f7a70d90Carlos Hernandez /** 151366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * Starts the service which will then work through the queue. Once the queue 152366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * is empty {@link #popNextSession()} returns null), the task will kill 153366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling * itself automatically and call #stitchingFinished(). 154dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling */ 155366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling private void startService() { 156366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling mAppContext.startService(new Intent(mAppContext, ProcessingService.class)); 157366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling mServiceRunning = true; 158dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling } 159dd2d9e610aa9dc71fe0938f38de43bb0e26f3bb2Sascha Haeberling} 160